在 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 块,而是在需要的地方导入这个组件。
<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>
到目前为止,我们只向子组件传递了字符串。但是当我们需要传递其他数据时会发生什么呢?
在 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 的使用,我们能够更加灵活地构建和组织我们的界面组件。