在 HTML 的世界里,我们想创建一个面板,包括标题和文本。你可以像这样创建:
<div class="panel">
<div class="panel__header">Title</div>
<div class="panel__body">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium, sit!
</div>
</div>
通过应用 CSS 和 JavaScript 到这些类,我们可以重复使用这段 HTML。这得益于类的存在,这也是像 Bootstrap 这样的 CSS 框架多年来运作的方式。 现在让我们看看 Vue 是如何处理可重用性的: 创建 Vue 组件 首先,我们需要在一个组件中创建一个基础的面板类。 创建 Panel.vue 组件:
<template>
<div>
<div class="header">Title</div>
<div class="body">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium, sit!
</div>
</div>
</template>
<script>
export default {
}
</script>
注意,我们可以消除一些类,因为我们的 CSS 将被限制在这个组件内部,同时 header 明确指向面板的头部。
现在,不再重复这个 HTML 块,而是在需要的地方导入这个组件。
在 App.vue 中添加两个面板组件
<template>
<div>
<Panel />
<Panel />
</div>
</template>
<script>
import Panel from './Panel.vue'
export default {
components: { Panel },
}
</script>
这种关注点的分离非常好,因为我们不再有各种嵌套的 div 容器,而是仅仅使用了 Panel,使得我们的模板非常易于理解。 动态 Props 但是等等!像这样,标题和内容将始终保持不变。没错,所以我们需要让这些属性是动态的。 为此,我们需要让父组件(App.vue)将标题和内容传递给子组件(Panel.vue)。子组件通过 props 定义它接受的属性。 Props 在 Panel.vue 中:
<template>
<div>
<div class="header">{{ title }}</div>
<div class="body">{{ body }}</div>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
required: true,
},
body: String,
}
}
</script>
我们的组件接受两个 props。title 必须是字符串并且是必需的,body 也是一个字符串,但不一定是必需的。
App.vue 现在可以将 props 传递给面板组件:
<template>
<div>
<Panel title="Lorem Ipsum" body="Lorem ipsum dolor sit amet" />
<Panel title="Something else" />
</div>
</template>
<script>
import Panel from './Panel.vue'
export default {
components: { Panel },
}
</script>
Props 与普通 HTML 属性非常相似。
样式
现在,某些面板特别重要,它们的背景颜色需要突出显示。在 HTML 中,现在我们要为面板添加一个 modifier 类并进行样式设置。
让我们添加类 panel--primary:
<div class="panel panel--primary">
<div class="panel__header">Title</div>
<div class="panel__body">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium, sit!
</div>
</div>
在 Vue 中,这将简单地成为另一个 prop。
在 Panel.vue 中:
<template>
<div :class="{primary: isPrimary}">
<div class="header">{{ title }}</div>
<div class="body">{{ body }}</div>
</div>
</template>
<script>
export default {
props: {
title: "String,"
body: String,
isPrimary: {
type: Boolean,
default: false,
},
}
}
</script>
<style scoped>
.primary {
background-color: #369; /* you might as well have a global CSS rule for the background color */
}
</style>
我们在 props 列表中添加了 isPrimary prop。注意如何将其默认为 false。现在,只需在实际需要主要面板时传递 isPrimary prop。
在 App.vue 中:
<template>
<div>
<Panel isPrimary title="Lorem Ipsum" body="Lorem ipsum dolor sit amet" />
<Panel title="Something else" body="Lorem ipsum dolor sit amet" />
</div>
</template>
<script>
import Panel from './Panel.vue'
export default {
components: { Panel },
}
</script>
传递数据作为 Props
到目前为止,我们只向子组件传递了字符串。但是当我们需要传递其他数据时会发生什么呢?
在 App.vue 中,将标题和内容定义为实际数据,并尝试将其传递给子组件。
<template>
<div>
<Panel isPrimary title="title" body="body" />
</div>
</template>
<script>
import Panel from './Panel.vue'
export default {
components: { Panel },
data() {
return {
title: 'Lorem Ipsum',
body: 'Lorem ipsum dolor sit amet',
}
}
}
</script>
上述代码将不起作用。它将字面传递字符串 title 和 body,而不是变量的内容。为了修复这个问题,我们必须在 prop 前添加一个前缀。因此,我们只需更改 App.vue 的模板部分:
<template>
<div>
<Panel :title="title" :body="body" />
</div>
</template>
实际上,你可以简化以上模板,简单地使用:
<template>
<div>
<Panel :title="title" :body="body" />
</div>
</template>
事实上,v-bind 允许任何 JavaScript 表达式。 总结 通过 Vue 组件,我们实现了 HTML 中面板的重用,并将其做了进一步的改进,使得标题和内容可以动态传递。通过 props 和 slots 的使用,我们能够更加灵活地构建和组织我们的界面组件。