vuejs3.0 从入门到精通——插槽
插槽
一、匿名插槽
App.vue:
<script setup> import A from './FancyButton.vue' </script> <template> <A> 这是 XXXX 数据 </A> </template>
<template> <div> <h1>子: A组件</h1> <header> <div>头部</div> <slot></slot> </header> <footer> <div>底部</div> <slot></slot> </footer> </div> </template> <style> .fancy-btn { color: #fff; background: linear-gradient(315deg, #42d392 25%, #647eff); border: none; padding: 5px 10px; margin: 5px; border-radius: 8px; cursor: pointer; } </style>
运行结果如下:
二、具名插槽
App:vue:
<script setup>
import A from './FancyButton.vue'
</script>
<template>
<A>
<template v-slot:xxx> 这是xxx数据</template>
<template v-slot:yyy> 这是yyy数据</template>
</A>
</template>
FancyButton.vue:
<template>
<div>
<h1>子: A组件</h1>
<header>
<div>头部</div>
<slot name='xxx'></slot>
</header>
<footer>
<div>底部</div>
<slot name='yyy'></slot>
</footer>
</div>
</template>
运行结果如下:
三、渲染作用域
https://cn.vuejs.org/guide/components/slots.html#render-scope
插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的。举例来说:
<span>{{ message }}</span>
<FancyButton>{{ message }}</FancyButton>
这里的两个{{ message }}
插值表达式渲染的内容都是一样的。
插槽内容无法访问子组件的数据。Vue模板中的表达式只能访问其定义时所处的作用域,这和JavaScript的词法作用域规则是一致的。换言之:
父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。
四、作用域插槽
https://cn.vuejs.org/guide/components/slots.html#scoped-slots
在上面的渲染作用域中我们讨论到,插槽的内容无法访问到子组件的状态。
然而在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。要做到这一点,我们需要一种方法来让子组件在渲染时将一部分数据提供给插槽。
我们也确实有办法这么做!可以像对组件传递 props 那样,向一个插槽的出口上传递 attributes:
<!-- <MyComponent> 的模板 -->
<div>
<slot :text="greetingMessage" :count="1"></slot>
</div>
当需要接收插槽 props 时,默认插槽和具名插槽的使用方式有一些小区别。
下面我们将先展示默认插槽如何接受 props,通过子组件标签上的v-slot
指令,直接接收到了一个插槽 props 对象:
<MyComponent v-slot="slotProps">
{{ slotProps.text }} {{ slotProps.count }}
</MyComponent>
子组件传入插槽的 props 作为了v-slot
指令的值,可以在插槽内的表达式中访问。
你可以将作用域插槽类比为一个传入子组件的函数。子组件会将相应的 props 作为参数传给它:
MyComponent({
// 类比默认插槽,将其想成一个函数
default: (slotProps) => {
return `${slotProps.text} ${slotProps.count}`
}
})
function MyComponent(slots) {
const greetingMessage = 'hello'
return `<div>${
// 在插槽函数调用时传入 props
slots.default({ text: greetingMessage, count: 1 })
}</div>`
}
实际上,这已经和作用域插槽的最终代码编译结果、以及手动编写渲染函数时使用作用域插槽的方式非常类似了。
v-slot="slotProps"
可以类比这里的函数签名,和函数的参数类似,我们也可以在v-slot
中使用解构:
<MyComponent v-slot="{ text, count }">
{{ text }} {{ count }}
</MyComponent>
五、动态插槽
https://cn.vuejs.org/guide/components/slots.html#dynamic-slot-names
动态指令参数在v-slot
上也是有效的,即可以定义下面这样的动态插槽名:
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
<!-- 缩写为 -->
<template #[dynamicSlotName]>
...
</template>
</base-layout>
注意这里的表达式和动态指令参数受相同的语法限制。