Vue.js 中的组件
组件使我们的代码可重用,并使我们能够遵循软件开发中的 DRY(Don't Repeat Yourself,不要重复自己)原则。组件是扩展基本 HTML 标记行为的代码块,可以反复用于不同的用途。这意味着 Vue 中的组件看起来像基本的 HTML 元素,但它们更易于配置,因此可以执行比普通 HTML 元素更多的功能。组件还可以包含其他组件,这使得我们的前端非常健壮且模块化。
现代 Web 应用程序由许多部分组成,跟踪所有组件的最佳方法是将它们抽象成不同的小部分(组件),使其易于组织、使用和维护。最终,您可能会得到类似这样的代码,用于执行整个页面的多种功能:
<html>
<head>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<div id='app'>
<app-header :links="links"></app-header>
<app-sidebar :items="items"></app-sidebar>
<app-body></app-body>
<app-footer></app-footer>
</div>
</html>
作为维护者,您肯定会同意我的观点:这样的代码非常简洁明了,无需花费太多时间就能弄清楚代码的运行机制以及各个部分的功能。
Vue 中的组件可以通过两种方式创建:一种是在单独的文件中创建,然后使用 ES6import语句导入;另一种是在基础 JavaScript 文件中注册并直接使用。
本文将创建一个基本组件,该组件接收一个用户对象,输出一个列表,并在点击每个用户时弹出该用户的详细信息。
我们将通过以下方式演示:
- 创建组件,
- 通过Props将数据传递给组件,
- 列表渲染,
- 从子组件发出事件,
- 监听父组件上的事件,以及
- 处理已发出的事件
如果您是 Vue 新手,可以查看官方文档入门。
如果您想直接查看最终项目,可以在CodePen上找到已完成的项目。
设置
设置 Vue 项目有两种方法。
- 使用 Webpack 构建工具或
- 通过 Vue CDN 使用 Vue。
让我们来探讨一下如何使用 Vue CDN 在 JavaScript 文件中定义组件。
首先,创建一个普通的 HTML 文件,然后从 CDN 引入 Vue JavaScript 文件。
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
这样可以确保 Vue 在项目中可用。接下来,我们<script>在 body 标签内添加一个标签。我们的代码将放在这里。
现在,您的项目应该看起来像这样:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<body>
<script type="text/javascript">
//Our Codes, Here
</script>
</body>
</html>
现在我们准备开始编写代码。
为了确保 Vue.js 已正确安装,我们先创建一个名为“Hello Vue”的应用。
在 HTML 文件的 body 标签内添加一个 div 标签,并将其 id 设置为“app”。
在 div 标签内div,复制并粘贴以下代码:{{message}}双花括号内的文本表示 Vue 中的一个变量。
在您的脚本标签中,复制并粘贴以下内容,我们稍后将探讨这些内容的含义。
let app = new Vue({
el : "#app",
data(){
return{
message: 'Hello Vue'
}
}
});
我们上面所做的就是:
- 实例化一个新的 Vue 对象,并告诉它应该使用的 HTML 元素的 ID 为:
app - 然后我们提供了一个数据对象,该对象返回
message - 最后,我们将上面数据对象中定义的 message 变量打印到 HTML 中,方法是输入以下内容:
{{message}}双花括号表示它们的内容是一个变量。
现在,我们所有的代码应该看起来像这样:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<body>
<div id="app">
{{message}}
</div>
<script type="text/javascript">
let app = new Vue({
el : "#app",
data(){
return{
message: 'Hello Vue'
}
}
});
</script>
</body>
</html>
如果在浏览器中运行这段代码,应该会输出“Hello Vue”。
既然我们已经确认 Vue 配置正确,接下来就让我们开始定义 Vue 组件吧。
定义我们的组件。
如前所述,组件可以创建为一个单独的文件,也可以直接创建在主 JavaScript 文件中。在本教程中,我们将直接在 JavaScript 文件中定义组件。
组件通过命令注册Vue.component('tag-name', options),其中 ` tag-name<name>` 是组件的名称,`<before>`options是一个定义组件行为的对象。这样,组件就可以在文件中全局使用,从而可以在不同的场景中应用。
我们先来定义一个虚拟组件,它除了在屏幕上显示一条消息之外什么也不做。我们把它叫做 `<message>` user-list。为了方便跟进,请创建一个新的 HTML 文件,或者修改 `hello vue` 文件,使其内容如下所示:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<body>
<div id="app">
<user-list></user-list>
</div>
<script type="text/javascript">
let userList = Vue.component('user-list', {
template : '<div>I am a component</div>'
});
let app = new Vue({
el : "#app"
});
</script>
</body>
</html>
我们创建了一个名为“user-list”的 Vue 组件,然后在 HTML 代码中,我们user-list像使用普通 HTML 标签一样使用了它。这就是将组件输出到前端的方式。
你可以template在 Vue 组件定义中看到 `<head>` 属性,它指定了组件挂载时将输出的 HTML 标签。请注意,一个 Vue 组件只能有一个根元素。
以上就是创建 Vue 基本组件的全部内容。
虽然这种方法可行,但实用性不高,因为它没有体现组件的强大功能和可复用性。让我们通过定义 props 来进一步扩展这个组件。
道具和组件
每个 Vue 组件都存在于自己的作用域中,不应该访问外部数据。Props
提供了一种将数据从父组件(外部)传递给子组件的方法。在本例中,我们将从父组件向子组件传递数据。app但userList在执行此操作之前,我们必须显式地指定组件期望的 props user-list。为组件添加另一个属性user-list,并将其命名为 `props`,props它将是一个包含所有期望传递给组件的 props 的数组user-list。假设 `props` 属性的内容为 `props`。['users']同时,让我们修改 ` templateprops` 属性,并删除 `props` 中的所有内容,将div其替换为 `props` {{users}}。
另外,在主 HTML 文件中,我们向标签添加一个名为“users”的新属性<user-list>,并将其值设置为users="list of users"。
目前,我们应用程序的源代码应该大致如下所示:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<body>
<div id="app">
<user-list users="list of users"></user-list>
</div>
<script type="text/javascript">
let userList = Vue.component('userList', {
template : '<div>{{users}}</div>',
props: ['users']
});
let app = new Vue({
el : "#app"
});
</script>
</body>
</html>
我们可以看到,我们的组件变得更智能了,现在可以使用users属性将数据从父组件传递到它。
这并不意味着只有字符串才能作为 props 传递,变量也可以通过v-bindVue 的 data 属性传递。让我们进一步拓展一下。在我们的主 Vue 应用中,我们将定义一个 data 属性,并将 Vue 组件要使用的变量传递给它。data 属性现在将如下所示:
data(){
return{
allUsers : [
{
name : 'John Doe',
about : 'Really nice guy'
},
{
name : 'Jane Dean',
about: 'Loves eggs'
},
{
name : 'Clark Kent',
about: 'Not your everyday reporter'
}
]
}
}
这实际上返回了一个包含三个对象的数组,每个对象有两个键name。about为了
将我们新定义的用户列表传递给组件,我们只需将v-bind:users属性添加到组件,并将数组名称传递给它,因此我们有了 `<users>` <user-list v-bind:users="allUsers"></user-list>。v-bind:前缀告诉 Vue 我们希望将usersprops 动态绑定到一个变量,而不是直接传递字符串字面量。
目前,我们的应用程序源代码如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<body>
<div id="app">
<user-list v-bind:users="allUsers"></user-list>
</div>
<script type="text/javascript">
let userList = Vue.component('userList', {
template : '<div>{{users}}</div>',
props: ['users']
});
let app = new Vue({
el : "#app",
data(){
return{
allUsers : [
{
name : 'John Doe',
about : 'Really nice guy'
},
{
name : 'Jane Dean',
about: 'Loves eggs'
},
{
name : 'Clark Kent',
about: 'Not your everyday reporter'
}
]
}
}
});
</script>
</body>
</html>
还记得我们之前说过,我们希望组件能够列出所有传递给它的用户吗?为此,我们需要使用 `ListRendering`v-for指令来实现列表渲染。该指令用于根据数组渲染列表项。
语法如下:
<li v-for="item in items"></li>
这里,`items` 是一个数组,`item` 是当前正在迭代的数组项的别名。掌握了列表渲染的知识后,让我们扩展用户列表组件,使其能够遍历所有用户。为此,我们将模板替换为以下代码:
template : `
<ul>
<li v-for="user in users">
{{user.name}}
</li>
</ul>
`,
如果您还不熟悉,反引号在现代 JavaScript 中被称为模板字面量,它允许我们编写多行语句,就像上面的示例一样。您可以在这里了解更多关于模板字面量的信息。
我们上面所做的,是定义了一个基础ul元素,然后遍历<li>该元素,并使用v-for列表渲染指令动态创建其中的所有标签。如果您运行我们当前的代码,应该会得到如下输出:
处理点击事件
为了确保组件的可复用性,我们不会在组件内部处理点击事件,而是将事件返回给父组件,由父组件使用传入的有效负载来执行所需的任何操作。这样做的好处是,我们可以将同一个组件用于多种不同的用途。
我们将通过让user-list组件在点击某个项目时发出一个事件来实现这一点,并且我们将在父组件上处理这个事件。
让我们给<li>元素添加一个点击事件监听器,在 Vue 中,我们通过添加属性来实现@click。这个点击事件会调用一个内部方法,并将用户的about属性传递给该方法。
<li v-for="user in users" @click="emitClicked(user.about)">
{{user.name}}
</li>
如上所示,点击处理程序接收了一个名为 emitClicked 的方法,我们将通过向 Vue 组件添加 methods 属性来定义此方法。
methods : {
emitClicked(data){
this.$emit('item-clicked',data)
}
此方法会发出一个带有有效负载的事件,父级可以监听该事件,并使用该事件进行操作。
监听事件
在父组件中监听事件的最简单方法是使用 ` v-onevent` 属性。记住,我们在子组件中触发了一个item-clicked事件,因此可以通过v-on:item-clicked在<user-list>HTML 标签中添加 `event` 属性来轻松监听该事件。
<user-list v-bind:users="allUsers" v-on:item-clicked="alertData"></user-list>
从上面的代码中,我们可以看到有一个名为 `getpayload(data)` 的新方法alertData。该方法用于处理子组件发出事件时传递的有效负载(数据)。
我们还将在主组件内部定义该alertData方法,方法是添加 methods 属性。
methods:
{
alertData(data)
{
alert(data)
}
}
该方法只是简单地使用原生 alert 方法来显示从子组件传递过来的数据。
现在我们所有的代码应该看起来像这样:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<body>
<div id="app">
<user-list v-bind:users="allUsers" v-on:item-clicked="alertData"></user-list>
</div>
<script type="text/javascript">
let userList = Vue.component('userList', {
template : `
<ul>
<li v-for="user in users" @click="emitClicked(user.about)">
{{user.name}}
</li>
</ul>
`,
props: ['users'],
methods : {
emitClicked(data){
this.$emit('item-clicked',data)
}
}
});
let app = new Vue({
el : "#app",
data(){
return{
allUsers : [
{
name : 'John Doe',
about : 'Really nice guy'
},
{
name : 'Jane Dean',
about: 'Loves eggs'
},
{
name : 'Clark Kent',
about: 'Not your everyday reporter'
}
]
}
},
methods:
{
alertData(data)
{
alert(data)
}
}
});
</script>
</body>
</html>
该组件的可重用性在于它v-on:item-clicked可以接受不同的方法并产生不同的输出,因此,该user-list组件可以在应用程序中多次重用。
结论
组件对于分离前端应用程序的关注点并将其拆分成更小的逻辑单元非常有用。一般来说,组件应该只执行单一功能,以实现最大的可重用性。在本文中,我们探讨了如何创建组件以及如何在组件与其父组件之间传递数据。
文章来源:https://dev.to/faradayyg/components-in-vuejs-j5g



