vue2 插槽:slot,slot-scoped,v-slot

邓阳嘉
2023-12-01

一、vue中的插槽

1.1 vue中插槽要解决的问题

slot 插槽 ,是用在组件中,向组件分发内容。它的内容可以包含任何模板代码,包括HTML。它会解决下面的问题:

<template>
  <div>
    <p>buttonTest</p>
    <my-button>
      <!-- 处于自定义标签中的内容,如何呈现 -->
      button
    </my-button>
  </div>
</template>
<script>
import MyButton from "./MyButton.vue";

export default {
  components: {
    "my-button": MyButton,
  },
  props: {},
  data() {
    return {};
  },
  methods: {},
};
</script>

自定义组件中,标签中间的内容如何呈现。

1.2 vue中插槽的发展

vue 在 2.6.0 中,具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slotslot-scope 这两个目前已被废弃但未被移除且仍有用的特性。但是将会在vue 3 中,被废弃的这两个,不会被支持即无效

二、匿名插槽

<template>
  <div>
    <!-- slot里面也可以设置内容,这个可以设置不传内容时,slot有个默认值替换 -->
    <slot>这里面是slot的默认值</slot>
  </div>
</template>
<script>
export default {
  name: "MyButton",
  props: {},
  data() {
    return {};
  },
  methods: {},
};
</script>
<template>
  <div>
    <p>buttonTest</p>
    <my-button>
      button
    </my-button>
  </div>
</template>
<script>
import MyButton from "./MyButton.vue";

export default {
  name: "HelloWorld",
  components: {
    "my-button": MyButton,
  },
  props: {},
  data() {
    return {};
  },
  methods: {},
};
</script>
  • 匿名的方式,就是指把在引用组件的时候,里面传的内容全部一起传送到组件页面中 <slot></slot> 所在的位置。
  • 只要组件中有<slot></slot>,并且不管有多少个,都会全部渲染为传过来的内容。意思就是说要是有多个<slot></slot>,那么传过来的内容就会渲染多次
  • <slot></slot>里面也可以设置内容,这个内容是保证引入组件的时候,有个默认值。当然,<slot></slot>里面不设置内容也可以,这样只是没有默认值,是不会报错的。
  • 传递的内容,也可以是动态的。
  • 如果传递的内容,没有slot 来接收,那么,传递的内容就会被抛弃掉不会起作用

三、具名插槽

<template>
  <div>
    <slot name="icon"></slot>
    <slot name="content"></slot>
  </div>
</template>
<script>
export default {
  name: "MyButton",
  props: {},
  data() {
    return {};
  },
  methods: {},
};
</script>
<template>
  <div>
    <p>2.6.0以前的写法</p>
    <my-button>
      <!--2.6.0以前的写法-->
      <template slot='icon'>
        +
      </template>
      <template slot='content'>
        新建
      </template>
    </my-button>
    <p>--------------------------------------------</p>
    <p>2.6.0之后的写法</p>
    <my-button>
      <!--2.6.0之后的写法-->
      <template v-slot:icon>
        +
      </template>
      <template v-slot:content>
        新建
      </template>
    </my-button>
  </div>
</template>
<script>
import MyButton from "./MyButton.vue";

export default {
  name: "HelloWorld",
  components: {
    "my-button": MyButton,
  },
  props: {},
  data() {
    return {};
  },
  methods: {},
};
</script>

具名插槽,就是给插槽指定名称,然后 一 一对应

  • 2.6.0之前的版本
    1. 引入组件的页面,如果是多个内容,需要用template 包裹起来,并且添加 slot 属性和 自定义值
    2. slot 的值需要和组件中 <slot name='xxx'></slot> name的值相对应。
    3. 如果剩下的内容没有包裹起来并制定值的话,那么这些内容会被渲染到 组件中 所有的 <slot></slot> 所在的位置。
    4. 如果 slot 设置为defaultname 设置为default,那就和没设置slot与name是一样的
    5. vue 2.6.0 以后的具名插槽相比 template上的 slot='xxx' 只需要 改成 v-slot:xxx 就行了,等号改成了冒号并且值没有引号带引号反而会报错
    6. 具名插槽只需要name值 slot的值对应 ,插槽的顺序是没有关系的
  • 2.6.0之后的版本
    1. v-slot只能用在组件component 或者 template 上 ,用在 divp这种标签上是会报错
    2. slot=' xxx ' 改成了v-slot:xxx,并且冒号后面这个名称不能打引号
    3. 组件页面中slot的内容没有变化
    4. 2.6.0 之后,具名插槽 v-slot:header可以缩写为#header,必须是有参数才能这样写! #= "xxx " 这样是不行的,#default = 'xxx'这样才可以

四、作用域插槽

<template>
  <div>
    <!--这里最重要的是 :anyName=value,anyName也是可以随便取的,表示要传过去的值-->
    <slot name="icon" :anyName="defaultConfig"></slot>
    <!--这里最重要的是 :anyName=value,anyName也是可以随便取的,表示要传过去的值-->
    <slot name="content" :anyName="defaultConfig"></slot>
  </div>
</template>
<script>
export default {
  name: "MyButton",
  props: {},
  data() {
    return {
      defaultConfig: {
        icon: "+",
        content: "新建",
      },
    };
  },
  methods: {},
};
</script>

<template>
  <div>
    <p>2.6.0以前的写法</p>
    <my-button>
      <!--这里的anyName对应 slot 中传值 :name=value 中的 name-->
      <template slot="icon" slot-scope="{ anyName }">
        {{ anyName.icon }}
      </template>
      <!--这里的obj是随便取的名称,不与任何地方对应-->
      <template slot="content" slot-scope="obj">
        {{ obj.anyName.content }}
      </template>
    </my-button>
    <p>--------------------------------------------</p>
    <p>2.6.0之后的写法</p>
    <my-button>
      <!--这里的anyName对应 slot 中传值 :name=value 中的 name-->
      <template v-slot:icon="{ anyName }">
        {{ anyName.icon }}
      </template>
      <!--这里的obj是随便取的名称,不与任何地方对应-->
      <template v-slot:content="obj">
        {{ obj.anyName.content }}
      </template>
    </my-button>
  </div>
</template>
<script>
import MyButton from "./MyButton.vue";

export default {
  name: "HelloWorld",
  components: {
    "my-button": MyButton,
  },
  props: {},
  data() {
    return {};
  },
  methods: {},
};
</script>
  • 2.6.0之前的版本
    1. 作用域插槽主要是使用子组件的任何数据来达到自定义显示内容的目的
    2. 作用域插槽最重要的一步,即是在<slot></slot>绑定数据 ,如果没有绑定数据,则父组件收到的,只是一个空对象{}
    3. 作用域插槽中<slot></slot>上绑定数据,可以是写死的,也可以是动态绑定的。如果是动态绑定的,则也需要v-bind:xxx
    4. 作用域插槽中<slot></slot>上绑定的数据也可以传一个定义好的有返回值的 methods 方法
    5. <slot></slot>绑定上数据之后,引用组件的地方中发送的内容就能通过slot-scope获取。获取到的内容,就是一个对象
    6. slot-scope可以接收任何有效的可以出现在函数定义的参数位置上的JavaScript 表达式。
  • 2.6.0之后的版本
    1. 两个属性 合并成了一个v-slot:插槽名称='传过来的值'
    2. 组件页面中slot的内容没有变化 。
    3. v-slot不能用在html标签上 。
    4. 如果是默认插槽,可以写成v-slot='xxx'

五、动态插槽名

动态指令参数也可以用在 v-slot 上,来定义动态的插槽名

    <base-layout>
      <template v-slot:[dynamicSlotName]>
        ...
      </template>
    </base-layout>

六、插槽内容的解构赋值

v-slot 的值只要满足函数参数定义的 JavaScript 表达式的都可以接受。因此,在支持的环境(单文件或现代浏览器)中,你还可以使用 ES2015 解构语法来提取特定的插值内容,例如:

<template>
  <div>
    <slot name="icon" :anyName="defaultConfig"></slot>
    <slot name="content" :anyName="defaultConfig"></slot>
  </div>
</template>
<script>
export default {
  name: "MyButton",
  props: {},
  data() {
    return {
      defaultConfig: {
        add: {
          icon: "+",
          content: "新建",
        },
      },
    };
  },
  methods: {},
};
</script>
<template>
  <div>
    <my-button>
      <template v-slot:icon="{ anyName }">
        {{ anyName.add.icon }}
      </template>
      <template v-slot:content="{ anyName: { add } }">
        {{ add.content }}
      </template>
    </my-button>
  </div>
</template>
<script>
import MyButton from "./MyButton.vue";

export default {
  name: "HelloWorld",
  components: {
    "my-button": MyButton,
  },
  props: {},
  data() {
    return {};
  },
  methods: {},
};
</script>

七、2.6.0之前和之后的版本对比

2.6.0之前的版本2.6.0之后的版本
匿名插槽父组件:<template>content<template>
子组件:<slot></slot>
父组件:<template>content<template>
子组件:<slot></slot>
具名插槽父组件:<template slot="slotName"><template>
子组件:<slot name="slotName"></slot>
父组件:<template v-slot:slotName><template>
子组件:<slot name="slotName">
简写: <template #slotName><template>
作用域插槽父组件:<template slot="slotName" slot-scope="obj"><template>
子组件:<slot name="slotName" :anyName="data"></slot>
父组件:<template v-slot:slotName="obj"><template>
子组件:<slot name="slotName" :anyName="data"></slot>
简写: <template #slotName="obj"><template>
使用位置可用在任意标签,如:<p slot="slotName" slot-scope="data">{{ data }}</p>只能用在 组件component 或者 template

参考

 类似资料: