RecursiveFrog 发表于 2021-12-9 16:37

vue插槽(slot)详解

最近被问起是否了解vue的插槽(slot),咋一想发现,似乎很少用到这玩意。所以整理了下slot的一些用法。
slot(父组件 在子组件<slot></slot>处插入内容)

Vue 实现了一套内容分发的 API,将<slot>元素作为承载分发内容的出口,这是vue文档上的说明。具体来说,slot就是可以让你在组件内添加内容的‘空间’。举个例子:
//子组件 : (假设名为:ebutton)
<template>
<div class= 'button'>
      <button></button>
</div>
</template>

//父组件:(引用子组件 ebutton)
<template>
<div class= 'app'>
   <ebutton> </ebutton>
</div>
</template>
我们知道,如果直接想要在父组件中的<ebutton></ebutton> 中添加内容,是不会在页面上渲染的。那么我们如何使添加的内容能够显示呢?在子组件内添加slot 即可。
//子组件 : (假设名为:ebutton)
<template>
<div class= 'button'>
      <button></button>
      <slot></slot>       //slot 可以放在任意位置。(这个位置就是父组件添加内容的显示位置)
</div>
</template>
子组件可以在任意位置添加slot , 这个位置就是父组件添加内容的显示位置。
编译作用域 (父组件 在子组件<slot></slot>处插入 data)

上面我们了解了,slot其实就是能够让我们在父组件中添加内容到子组件的‘空间’。我们可以添加父组件内任意的data值,比如这样:
//父组件:(引用子组件 ebutton)

<template>
<div class= 'app'>
   <ebutton> {{ parent }}</ebutton>
</div>
</template>

new Vue({
el:'.app',
data:{
    parent:'父组件'
}
})
使用数据的语法完全没有变,但是,我们能否直接使用子组件内的数据呢?显然不行!!
// 子组件 : (假设名为:ebutton)
<template>
<div class= 'button'>
      <button> </button>
       <slot></slot>
</div>
</template>

new Vue({
el:'.button',
data:{
    child:'子组件'
}
})

// 父组件:(引用子组件 ebutton)

<template>
<div class= 'app'>
   <ebutton> {{ child }}</ebutton>
</div>
</template>
直接传入子组件内的数据是不可以的。因为:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
后备内容 (子组件<slot>   </slot>设置默认值)

所谓的后背内容,其实就是slot的默认值,有时我没有在父组件内添加内容,那么 slot就会显示默认值,如:
//子组件 : (假设名为:ebutton)
<template>
<div class= 'button'>
      <button></button>
      <slot> 这就是默认值 </slot>
</div>
</template>
具名插槽 (子组件 多个<slot ></slot><slot></slot>对应插入内容)

有时候,也许子组件内的slot不止一个,那么我们如何在父组件中,精确的在想要的位置,插入对应的内容呢? 给插槽命一个名即可,即添加name属性。
//子组件 : (假设名为:ebutton)
<template>
<div class= 'button'>
      <button></button>
      <slot name= 'one'> 这就是默认值1</slot>
      <slot name='two'> 这就是默认值2 </slot>
      <slot name='three'> 这就是默认值3 </slot>
</div>
</template>
父组件通过v-slot : name 的方式添加内容:
//父组件:(引用子组件 ebutton)
<template>
<div class= 'app'>
   <ebutton>
      <template v-slot:one> 这是插入到one插槽的内容 </template>
      <template v-slot:two> 这是插入到two插槽的内容 </template>
      <template v-slot:three> 这是插入到three插槽的内容 </template>
   </ebutton>
</div>
</template>
当然 vue 为了方便,书写 v-slot:one 的形式时,可以简写为 #one
作用域插槽 ( 父组件 在子组件 <slot></slot> 处使用子组件 data)

通过slot 我们可以在父组件为子组件添加内容,通过给slot命名的方式,我们可以添加不止一个位置的内容。但是我们添加的数据都是父组件内的。上面我们说过不能直接使用子组件内的数据,但是我们是否有其他的方法,让我们能够使用子组件的数据呢? 其实我们也可以使用v-slot的方式:
//子组件 : (假设名为:ebutton)
<template>
<div class= 'button'>
      <button></button>
      <slot name= 'one' :value1='child1'> 这就是默认值1</slot>    //绑定child1的数据
      <slot :value2='child2'> 这就是默认值2 </slot>//绑定child2的数据,这里我没有命名slot
</div>         
</template>

new Vue({
el:'.button',
data:{
    child1:'数据1',
    child2:'数据2'
}
})

//父组件:(引用子组件 ebutton)
<template>
<div class= 'app'>
   <ebutton>
      <template v-slot:one = 'slotone'>
         {{ slotone.value1 }}    // 通过v-slot的语法 将子组件的value1值赋值给slotone
      </template>
      <template v-slot:default = 'slottwo'>
         {{ slottwo.value2 }}// 同上,由于子组件没有给slot命名,默认值就为default
      </template>
   </ebutton>
</div>
</template>
总结来说就是:

[*]首先在子组件的slot上动态绑定一个值( :key='value')
[*]然后在父组件通过v-slot : name= ‘values ’的方式将这个值赋值给 values
[*]最后通过{{values.key }}的方式获取数据

unityloverz 发表于 2021-12-9 16:42

那如果我想改变插槽里面的css,是在子组件里面修改,还是在父组件呢?

kirin77 发表于 2021-12-9 16:48

我觉得如果是静态改变直接从子组件中改;如果是根据父组件中的某些属性修改css的话,应该使用绑定样式吧
[思考]

NoiseFloor 发表于 2021-12-9 16:51

我的肯定
[赞同]

jquave 发表于 2021-12-9 17:00

老板儿写的言简意赅, 太棒了

DomDomm 发表于 2021-12-9 17:06

有点儿晕
页: [1]
查看完整版本: vue插槽(slot)详解