一、Vue组件
1. 什么是组件
组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。
在 Vue 里,一个组件本质上是一个拥有预定义选项的一个 Vue 实例,就是一组可重复使用的模板,与JSTL的自定义标签、Thymeleaf的th:fragment
等框架有异曲同工之妙;
几乎任意类型的应用界面都可以抽象为一个组件树
例如:CSDN博客有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文分类、博文数量等其他的组件
2. 定义一个组件
格式:第一个参数为组件名,第二个参数为组件对象,对象包含一些属性,如props
、template
Vue.component("组件名", {
props: 可接收的参数
template: 模板
})
代码示例:定义一个名为zsr
组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue组件</title>
</head>
<body>
<div id="component">
<zsr/>
</div>
<!--导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<script>
//定义一个组件zsr
Vue.component("zsr", {
template: '<li>hello</li>'
})
//创建Vue对象
var vue = new Vue({
el: "#component"
})
</script>
</body>
</html>
效果演示:
3. 组件传参
像上面那样用组件没有任何意义,所以我们是需要传递参数到组件的,此时就需要使用
props
属性了
注意:默认规则下props属性里的值不能为大写
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue组件</title>
</head>
<body>
<div id="component">
<zsr v-for="item in items" v-bind:x="item"></zsr>
</div>
<!--导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<script>
//定义一个组件
Vue.component("zsr", {
props: ['x'],
template: '<li>{{x}}</li>'
})
//创建Vue对象
var vue = new Vue({
el: "#component",
data: {
items: ["Java", "Python", "C++"]
}
})
</script>
</body>
</html>
说明:
v-for="item in items"
:遍历Vue的实例中定义名为items
的数组,并创建同等数量的组件v-bind:x="item"
:将遍历的item
项绑定到组件对象属性props
定义的名为x
的属性上;
效果演示:
二、内容分发:插槽slot
在
Vue.js
中,我们使用<slot>
元素作为承载分发内容的出口,作者称之为 插槽 ,可以用在组合组件的场景中
代码测试:比如准备一个待做清单组件todo
,该组件由标题组件todo-title
和列表组件todo-list
组成,这三个组件相互独立,我们可以用插槽将他们组合起来
第一步:定义待做清单组件
- 这里留两个插槽
slot
,并指定名称分别为todo-title
和todo-list
//待做清单组件
Vue.component("todo", {
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-list"></slot>\
</ul>\
</div>'
});
第二步:定义标题组件todo-title
- 利用
props
属性定义接收的参数为title
//标题组件
Vue.component("todo-title", {
props: ['title'],
template: '<div>{{title}}</div>'
});
第三步:定义列表组件todo-list
- 利用
props
属性定义接收的参数为list
和index
//列表组件
Vue.component("todo-list", {
props: ['list','index'],
template: '<li>{{index}--}{{list}}</li>'
});
第四步:实例化Vue并初始化数据
- 初始化
title
数据和todoLists
数据
//定义一个vue对象
var vue = new Vue({
el: "#slot",
data: {
title: "待做清单",
todoLists: ['Java', 'C++', 'Python']
}
});
第五步:通过插槽插入组件并绑定初始值
- 在
todo
组件内插入todo-title
和todo-list
组件 - 并对组件设置插槽名,与
todo
组件中的插槽名对应,实现对应位置插入 - 绑定元素值:
title
绑定到vue对象中data中的title值,list
绑定到vue对象中data中的todoLists遍历出来的每个值todoList
<div id="slot">
<todo>
<todo-title slot="todo-title" v-bind:title="title"></todo-title>
<todo-list slot="todo-list" v-for="(todoList,index) in todoLists" v-bind:list="todoList" v-bind:index="index"></todo-list>
</todo>
</div>
完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>slot</title>
</head>
<body>
<div id="slot">
<todo>
<todo-title slot="todo-title" v-bind:title="title"></todo-title>
<todo-list slot="todo-list" v-for="(todoList,index) in todoLists" v-bind:list="todoList"
v-bind:index="index"></todo-list>
</todo>
</div>
<!--导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<script>
//待做清单组件
Vue.component("todo", {
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-list"></slot>\
</ul>\
</div>'
});
//标题组件
Vue.component("todo-title", {
props: ['title'],
template: '<div>{{title}}</div>'
});
//列表组件
Vue.component("todo-list", {
props: ['list', "index"],
template: '<li>{{index}}--{{list}}</li>'
});
//定义一个vue对象
var vue = new Vue({
el: "#slot",
data: {
title: "待做清单",
todoLists: ['Java', 'C++', 'Python']
}
});
</script>
</body>
</html>
效果演示:
三、自定义事件
继上述示例,如果我们在每行列表后加一个删除按钮
//列表组件
Vue.component("todo-list", {
props: ['list'],
template: '<li>{{index}}--{{list}}<button v-on:click="remove">删除</button></li>'
});
如果想要实现点击删除按钮删除对应的行,该怎么实现呢?
我们首先可以在vue示例的定义中加入一个删除方法
//定义一个vue对象
var vue = new Vue({
el: "#slot",
data: {
title: "待做清单",
todoLists: ['Java', 'C++', 'Python']
},
methods: {
deleteList: function (index) {
alert("删除了第" + index + "行")
this.todoLists.splice(index, 1);//删除index行
}
}
});
这是我们打开浏览器在控制台调用deleteList
方法即可删除指定行
这样在控制台实现了删除行,那么怎么实现点击按钮删除行呢?
我们可以自定义事件remove
绑定到deleteList()
方法实现删除
<div id="slot">
<todo>
<todo-title slot="todo-title" v-bind:title="title"></todo-title>
<todo-list slot="todo-list" v-for="(todoList,index) in todoLists" v-bind:list="todoList" v-bind:index="index"
v-on:remove="deleteList(index)"></todo-list>
</todo>
</div>
然后在todo-list
组件中添加一个删除方法remove()
绑定上述remove
事件使其生效
//列表组件
Vue.component("todo-list", {
props: ['list', "index"],
template: '<li>{{index}}--{{list}}<button v-on:click="remove">删除</button></li>',
methods: {
remove: function () {
this.$emit('remove')
}
}
});
再测试,点击对应行按钮即可实现删除