Vue(07)——slot插槽和自定义事件
1、slot插槽
什么是插槽
Vue 实现了一套内容分发的 API,将 <slot>
元素作为承载分发内容的出口,称为插槽。
插槽实质是对子组件的扩展,通过<slot>
插槽向组件内部指定位置传递内容。
插槽的使用
准备一个待办事项(todo),该组件由待办事项(todo-title)和待办内容(todo-items)组成,下面就把todo-title和todo-items插入todo中:
<!DOCTYPE html >
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>计算属性</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<div id="app">
<todo>
<!-- :是v-bind:的缩写-->
<todo-title slot="todo-title" :title="title"></todo-title>
<!--从todoItems循环遍历出的每个值为item,然后props里的item接收到item,再把数据显示到模板上,最后再插入slot-->
<todo-items slot="todo-items" v-for="item in todoItems" :item="item"></todo-items>
</todo>
</div>
<script>
//父组件,插槽,把其他组件的内容添加到里面
Vue.component("todo",{
//插槽通过name属性绑定组件
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
//子组件
Vue.component("todo-title",{
props: ['title'],
template: '<div>{{title}}</div>'
});
//子组件
Vue.component("todo-items",{
props: ['item'],
template: '<li>{{item}}</li>'
});
var vm = new Vue({
el: '#app',
data: {
title: "技术栈",
todoItems: ['Java','Python','Linux']
}
});
</script>
</body>
</html>
到这里,我们就实现了将todo-title子组件和todo-items子组件分发到todo(父组件)的插槽中。
2、自定义事件
在上面例子中,子组件使用props接收父组件传递的数据,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
- 使用
$on(eventName)
监听事件 - 使用
$emit(eventName)
触发事件
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
<!DOCTYPE html >
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>自定义事件</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<div id="app">
<todo>
<!-- :是v-bind:的缩写-->
<todo-title slot="todo-title" :title="title"></todo-title>
<!--遍历出数组的数据以及下标-->
<todo-items slot="todo-items" v-for="(item,index) in todoItems"
:item="item" :index="index" @remove1="removeItem(index)" :key="index"></todo-items><!--自定义事件绑定vue实例中的removeItem方法-->
</todo>
</div>
<script>
//插槽,把其他组件的内容添加到里面
Vue.component("todo",{
//插槽通过name属性绑定组件
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
Vue.component("todo-title",{
props: ['title'],
template: '<div>{{title}}</div>'
});
Vue.component("todo-items",{
props: ['item','index'],// @是v-on的缩写 index 数组下标
template: '<li>{{index}}---{{item}} <button @click="remove2">删除</button></li>',
methods: {
remove2: function (index){
//$emit(自定义事件的名称,自定义事件处理程序需要的参数)
this.$emit('remove1',index);//触发自定义事件
}
}
});
var vm = new Vue({
el: '#app',
data: {
title: "技术栈",
todoItems: ['Java','Python','Linux']
},
methods: {
removeItem: function (index){//根据数组下标删除元素
console.log("删除"+this.todoItems[index]+" OK")
this.todoItems.splice(index,1)//从下标为index开始删除,一次删除一个元素
}
}
});
</script>
</body>
</html>