Vue-插槽及自定义事件分发
一.插槽slot
在某些场景中,我们可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。
<slot>
元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。
插槽就好比一个占位符,它不是解决页面必须元素的位置,而是解决未知元素的位置,好比:页面导航栏,有那些导航指向哪里都是写死的,网站不倒闭他都不变的,是不需要使用插槽的,
最该使用插槽的应该是数据库中查询出来的数据,这类数据在页面显示有一个很明显的特点:每个人的数据查询都是不一样的,数据条目也是不一样的,所以很难从HTML+CSS的架构来完美构造接收数据库数据的前端页面,
所以vue作为一个专注视图层的js库,插槽的概念就孕育而生,它使用slot标签在页面进行占位,数据库数据不会先到页面上,而是先到vue的组件中去,把数据按条目整理好了再去页面代替slot插槽的位置,完成无差别渲染
这样对不同数据量的页面很友好,使得前端也能工程化,结构化
代码展示:
<div id="app"> <msf> <!-- 插槽位置需要绑定插槽组件,用于传参到那个组件内,数据一般是页面先获取到,获取到后由插槽和组件渲染--> <msf-title slot="msf-title" :title="title"></msf-title> <msf-body slot="msf-body" v-for="a in args" :arg="a"></msf-body> </msf> </div> <script> //组件内部留有插槽 Vue.component('msf',{ //绑定插槽位置,每个slot标签使用前都需要绑定 template: '<div>\ <slot name="msf-title"></slot>\ <ul>\ <slot name="msf-body"></slot>\ </ul>\ <div></div>' }); //插槽:根据数据库条目动态改变页面内容 Vue.component('msf-title',{ props: ['title'], template: '<div>{{title}}</div>' }) Vue.component('msf-body',{ props: ['arg'], template: '<li>{{arg}}</li>' }) let vue = new Vue({ el: "#app", data: { title: '计算机必修课程', args: ['java','mysql','spring','js'] } }); </script>
如上代码,我们需要知道四个域:
页面占位插槽,组件,插槽,model层数据域
利用vue绑定app元素,使得在model层数据都可以在此范围内使用,在页面占位插槽也在这个区域内,先使用一个组件,这个组件是用来控制格式的,比如美化插槽这块区域,使得这块区域更好看
组件如果需要美化插槽的部分,那么就需要在美化的位置也加入插槽slot标签,并且需要在name属性下填写插槽的名字,用于绑定唯一插槽
插槽要做的就是自己是使用什么方式输出,以及接收参数,如:使用h标签,p标签,li标签来装饰输出数,接收参数需要页面占位插槽绑定
页面占位插槽需要两个属性,slot属性:标识model穿过来的数据放在那个插槽内,需要传到这个插槽,v-指令:用于绑定model层,数据双向绑定,也是让model层知道数据到底传到哪里
插槽代码结果展示:
二.自定义事件内容分发
自定义事件分发指的是在插槽的基础上,写入一些事件来操作数据,写入事件是很简单的,但是实际操作数据就很难了
首先在插槽中只能使用自己的方法属性,它是不能调用到实例化的Vue对象中的方法的,但是使用插槽位置的方法又操作不了model层的数据
所以我们要想怎么在插槽的方法调用到Vue实例化对象中的方法,利用它来操作model层的数据
Vue官方提供了一个方法:this.$emit() 来调用自定义的方法
代码展示:
<div id="app"> <mm> <mm-body slot="mm-body" v-for="(arg,index) in args" :arg="arg" :index="index" v-on:removed="VueRemoved(index)"></mm-body> </mm> </div> <script> Vue.component('mm',{ template: '<div>\ <ul>\ <slot name="mm-body"></slot>\ </ul>\ </div>' }); Vue.component('mm-body',{ props: ['arg','index'], template: '<li>{{arg}}<button v-on:click="removed">删除</button></li>', methods:{ removed: function (index) { this.$emit('removed',index); } } }) let vue = new Vue({ el: "#app", data: { args: ['神里凌华','雷电将军','神里绫人','枫原万叶','流浪者'] }, methods:{ VueRemoved: function (index) { this.args.splice(index,1); } } }); </script>
这个小案例讲的是插槽或者组件加入一些事件的操作方法,
但是映射到vue的大知识点是:组件只能直接调用自己的方法(methods),而组件不能直接操作model层的数据,而vue中的实例方法(methods)可以直接操作model层数据,因为它们位于同一域中,都在Vue实例对象之中。
在这里我们要清楚vue的两步操作:
- 绑定
- 传入
我们说了,触发事件的按钮是在组件中的,所以触发事件也只能在组件中触发,但是要操作的数据的方法在vue实例中,得想想怎么让这个实例方法进来,思考view层的数据是怎么到组件中去的,传入,通过v-bind:组件参数 = 'view层参数',这就是关键,需要的vue实例方法可以通过传入的方式到组件中去,所以v-on:removed = VueRemoved(index) 这就是传入组件的操作,好了我们已经解决了一个view层的方法怎么送到组件中去了
接着,view层的方法怎么来呢,这个方法肯定是vue实例中的,这就是vue实例中el属性的功劳了,它绑定的区域内都可以使用此个vue实例,然后后v-on指令是专门用于view绑定vue实例中的事件的,所以使用v-on:="VueRemoved",就可以使得将方法绑定到view层中去,完整的v-on:removed = VueRemoved(index),既包含了绑定vue实例中的方法,也包含了将绑定方法传入到组件中去
完成上面一步后,在组件中removed就是VueRemoved的一个映射,所以我们可以直接调用它,这个自定义方法使用:this.$emit() 来完成调用
自定义事件内容分发结果展示:
按钮点击可删除