天天看点

Vue中的slot、slot-scope、v-slot辨析

1.slot(插槽)

概念

插槽是Vue中的一个中的一个特殊特性,他的作用是,在指定位置,开辟一个空间,给未来的元素使用,这里所谓的未来元素指的就是组件的内容,但是slot已被废弃。

下面以一个简单的例子来说明上述问题。

<body>
    <div id="app">
        <Test>
            <p>这是Test组件</p>
        </Test>
    </div>
    <template id="test">
        <div> 
            <h3>这是Test组件模板</h3>
        </div>
    </template>
</body>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
<script>
    Vue.component('Test', {
        template: '#test',
        data() {
            return {
                msg: 'Hello World!'
            }
        }
    })
    new Vue({
        el: '#app',
    })
</script>
           

在上述案例代码中,我们运行后可以发现,在id为app的范围内的p标签的内容并没有显示,显示的是名为Test的组件模板中的内容,这是因为写在id为app的中的Test组件中的内容会被Test自身的模板内容覆盖,所以只显示模板中的内容。slot能够为Test组件中的内容开辟一个空间,让Test使用,此时只需要在

<h3>这是Test组件模板</h3>
           

该行代码的上一行或者下一行,写入

<slot></slot>
           

就可以达到需求。

具名插槽

具名插槽指的是,当我们需要多个插槽时,可以利用 元素的一个特殊的特性:name来定义具名插槽,达到开辟的空间能够与组件内容相对应的效果。

具体使用如下:

先利用slot插槽的那么为当前插槽定义一个名字,名字随意定义

<slot name="header"></slot>
           

在对应的位置,将对应的标签与slot定义的名字绑定,如下

<header slot="header"></header>
           

完整案例代码如下:

<body>
    <div id="app">
        <Test>
            <header slot="header">
                头部
            </header>
            <footer slot="footer">
                底部
            </footer>
        </Test>

    </div>
    <template id="test">
        <div>
            <slot name="header"></slot>
            <h3>这里是Test模板</h3>
            <slot name="footer"></slot>
        </div>
    </template>
</body>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
<script>
    Vue.component('Test',{
        template:'#test',
    })
    new Vue({
        el:'#app',
    })
</script>
           

2.作用域插槽【slot-scope】

作用域插槽其实就是一个带有数据的插槽,我们知道组件中的数据只能在对应的组件模板中使用,在其他地方无法获取,那么要想在其他地方获取到该数据,就可以通过使用slot-scope来获取,但是slot-scope已被废弃。

具体使用如下:

首先将组件中的数据与slot绑定

<slot :msg = "msg"></slot>
           

然后利用 slot-scope获取到与slot绑定的数据,此处的data为自己定义的,是一个对象

<span slot-scope = "data">
        {{ data.msg }}
      </span>
           

完整案例代码如下:

<div id="app">
    <Hello>
      <span slot-scope = "data">
        {{ data.msg }}
      </span>
    </Hello>
  </div>
  <template id="hello">
    <div>
      <h3> 这里是hello组件 </h3>
      <slot :msg = "msg"></slot>
    </div>
  </template>
</body>
<script src="../../../lib/vue.js"></script>
<script>
  Vue.component('Hello',{
    template: '#hello',
    data () {
      return {
        msg: 'hello 1905'
      }
    }
  })
  new Vue({
    el: '#app'
  })
</script>
           

3.v-slot指令(Vue 2.6)

从 vue2.6 开始,Vue 为具名插槽和作用域插槽引入了一个全新的语法,即v-slot 指令。目的就是想统一 slot 和 scope-slot 语法,使代码更加规范和清晰。

具体使用如下:

1.插槽的名字现在通过 v-slot:slotName 这种形式来使用,如下。

<template v-slot:header> </template>
           

有一个 默认的名称default

<template v-slot:default> </template>
           

但是该默认的名字,往往省略不写

<template v-slot="data"> </template>
           

2.此处需要注意的是,

v-slot

只能添加到

<template>

上,这点Vue 2.5中的slot是不同的。

<template v-slot:slotName="data"> </template>
           

3.正常情况下,假设Test组件注册及组件模板如下,

//组件模板
 <template id="test">
        <div>
            <h3>这里是test组件</h3>
            <slot></slot>
        </div>
    </template>
//组件注册
   Vue.component('Test', {
        template: '#test',
        data() {
            return {
                msg: 'Hello World!'
            }
        }
    })
           

当我们需要在下面的p标签内获取Test组件数据时,可能往往写法如下

<Test>
            <template v-slot:default>
            <p>{{msg}}</p>
            </template>
</Test>
           

但是,由于组件的数据只能限于当前组件模板才能使用,所以它访问不了Test组件中的数据,为了解决这个问题,需要给组件模板中的元素上动态绑定一个对象属性,绑定到 元素上的属性我们称之为 slot props。该对象属性的名字可以自定义,而属性值就是Test组件数据的名字,这样就可以获取到Test组件中的数据,如下

<slot :msg="msg"></slot>
           

同时使用v-slot重构上面代码

<Test>
            <template v-slot:default="data">//此处的data就是在<slot>中绑定的属性slot props
                <p>{{data.msg}}</p>
            </template>
</Test>
           

在上面的案例中,用data 作为 slot props 名字,但是你可以根据自己的需求自行定义。而data是一个对象,里面放着msg的数据,可以将其理解成一个容器,凡是通过

<slot :msg="msg"></slot>

绑定的数据,都以键值对的形式放在里面比如此处的msg,即,

data={ msg:“Hello World!”}

完整案例代码如下:

<body>
    <div id="app">
        <Test>
            <template v-slot:default="data">
                <p>{{data.msg}}</p>
            </template>
        </Test>
    </div>
    <template id="test">
        <div>
            <h3>这里是test组件</h3>
            <slot :msg="msg"></slot>
        </div>
    </template>
</body>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
<script>
    Vue.component('Test', {
        template: '#test',
        data() {
            return {
                msg: 'Hello World!'
            }
        }
    })
    new Vue({
        el: '#app',
    })
</script>