总结下vue的插槽知识,来学学吧

552 阅读2分钟

这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

缘由

vue的插槽用过,但是不是很常用,因为有别的方案也能实现,比如通过props传值然后通过v-if或者v-show来控制显隐。但是有时候需要自定义的内容很多,props传的值过多,这时候插槽就可以派上用场。所以今天总结下vue的插槽知识,来学学吧。

定义

vue的插槽是在调用组件的时候用的,组件内定义一个默认内容(可选),如果调用的时候传入自定义内容,则会使用自定义内容进行渲染,否则会使用默认内容渲染。

子组件必须要有slot标签,如果没有slot标签,则无法渲染父组件的自定义内容。

例子:

  <div id="app">
    <user-info>
      <h3>我是自定义内容</h3>
    </user-info>
  </div>
  <script>
    Vue.component('user-info', {
      template: '<div><slot>我是备用内容</slot></div>'
    })
    const vm = new Vue({
      el: '#app'
    })
  </script>

结果如下:

传了自定义内容:

image.png

没传自定义内容:

image.png

具名插槽

如果想把插槽渲染在特定的结构中,那么vue是支持具名插槽,例子如下:

  <div id="app">
    <user-info>
      <h3 slot="header">我是头部内容</h3>
      <h3>我是content</h3>
      <h3 slot="footer">我是底部内容</h3>
    </user-info>
  </div>
  <script>
    Vue.component('user-info', {
      template: `
                  <div>
                    <slot name="header"></slot>
                    <slot></slot>
                    <slot name="footer"></slot>
                  </div>`
    })
    const vm = new Vue({
      el: '#app'
    })
  </script>

image.png

具名插槽是通过父组件标签的slot属性值和子组件的slot标签的name值匹配,符合的展示父组件的具名插槽,不符合就默认展示slot标签内的内容。

父组件标签没有slot属性值都当作默认默认插槽,替换默认的slot标签的内容。

slot-scope

如果你想在父组件的插槽使用子组件上的数据,可以使用slot-scope

  <div id="app">
    <user-info>
      <!-- 通过{}解构 -->
      <h3 slot-scope="{info}">{{info}}</h3> 
    </user-info>
  </div>
  <script>
    Vue.component('user-info', {
      data() {
        return {
          info: { name: '答案cp3' }
        }
      },
      template: `
                  <div>
                    <slot :info="info"></slot>
                  </div>`
    })
    const vm = new Vue({
      el: '#app'
    })
  </script>

image.png

新语法

vue自2.6.0及以上版本改进了具名插槽和slot-scope的写法,下面也总结一下。

上面的具名插槽和slot-scope的写法官方已经不推荐使用,大家后面还是以新语法为主。

具名插槽

使用v-slot:name来表示, 而且v-slot只能用在template标签上(但是如果你只有默认插槽,v-slot可以使用在组件上)。默认插槽是v-slot:default,可以简写v-slot

注意:v-slot内部标签不能再使用着v-slot

改写上面的例子:

  <div id="app">
    <user-info>
      <!-- `v-slot`一般只能用在template标签 -->
      <template v-slot:header>
        <h3 >我是头部内容</h3>
      </template>
      <template v-slot:default>
       <h3>我是content</h3>
      </template>
      <template v-slot:footer>
        <h3 >我是底部内容</h3>
      </template>
    </user-info>
  </div>
  <script>
    Vue.component('user-info', {
      template: `
                  <div>
                    <slot name="header"></slot>
                    <slot></slot>
                    <slot name="footer"></slot>
                  </div>`
    })
    const vm = new Vue({
      el: '#app'
    })
  </script>

slot-scope

改写上面的slot-scope例子

  <div id="app">
    <user-info>
      <!-- 通过{}解构 -->
      <!-- `v-slot`一般只能用在template标签 -->
      <!-- 等同于v-slot:default -->
      <template v-slot="{info}">
        <h3>{{info}}</h3>
      </template>
    </user-info>
  </div>
  <script>
    Vue.component('user-info', {
      data() {
        return {
          info: { name: '答案cp3' }
        }
      },
      template: `
                  <div>
                    <slot :info="info"></slot>
                  </div>`
    })
    const vm = new Vue({
      el: '#app'
    })
  </script>

v-slot缩写

v-slot的缩写是#,它后面必须带有name,比如默认插槽,#default, 不能缩写#

    <user-info>
      <!-- 等同于v-slot:header -->
      <template #header>
        <h3 >我是头部内容</h3>
      </template>
      <!-- 等同于v-slot:default -->
      <template #default>
       <h3>我是content</h3>
      </template>
       <!-- 等同于v-slot:footer -->
      <template #footer>
        <h3 >我是底部内容</h3>
      </template>
    </user-info>