Vue-插槽及自定义事件分发

发布时间 2023-09-23 15:53:27作者: ~java小白~

一.插槽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()   来完成调用