首页 > 编程笔记 > JavaScript笔记
阅读:161
Vue slot插槽完全攻略
项目中有很多组件显示的内容,在不同的地方使用的时候,有些内容需要变化,这时候可以用插槽内容分发功能实现。
例如,开发人员可以定义一个组件,专门用来显示提示信息。只是显示的信息包含在插槽 slot 元素中,满足在不同的地方,提示的内容不一样。
MessageAlert 组件中包含了 slot 插槽,运行的时候,就会将组件元素包含的内容动态地渲染到视图中,代码如下:
当然,分发到 slot 中的内容,可以包含动态内容,此时动态的变量只能使用父组件里面的 property,代码如下:
示例代码如下:
开发人员可以在 slot 元素中,使用 v-bind 指令将对象绑定后,传递到组件外面,如:slot v-bind:userAttr="user".../slot 就是将子元素中的 user 数据,通过 v-bind 指令绑定到 userAttr 属性上。
userAttr 属性又称为 slot property,在父组件中,可以在 template 元素中使用指定的插槽属性变量操作 userAttr 绑定的 user 数据,代码如下:
v-slot:header 可以被重写为 # header,代码如下:
例如,开发人员可以定义一个组件,专门用来显示提示信息。只是显示的信息包含在插槽 slot 元素中,满足在不同的地方,提示的内容不一样。
MessageAlert 组件中包含了 slot 插槽,运行的时候,就会将组件元素包含的内容动态地渲染到视图中,代码如下:
...
<div id="app">
<message-alert>普通</message-alert>
<message-alert>警告</message-alert>
<message-alert>错误</message-alert>
</div>
<script>
// 定义MessageAlert组件
const MessageAlert = {
template: `
<div>
<strong>消息:</strong>
<slot></slot>
</div>
`
};
// 注册全局MessageAlert组件
Vue.component('message-alert', MessageAlert);
// 创建Vue实例并挂载到#app元素
const vm = new Vue({
el: '#app'
});
</script>
...
插槽的缺省内容和编译作用域
在实战中,slot 中往往希望有缺省值,实现起来很简单,直接在子元素的 slot 之间包含缺省值即可,调用的时候,如果有新值,则自动会将缺省值覆盖,如 slot 缺省值 /slot。当然,分发到 slot 中的内容,可以包含动态内容,此时动态的变量只能使用父组件里面的 property,代码如下:
...
<div id="app">
<!-- 使用缺省值 -->
<slot-dft-content></slot-dft-content>
<!-- 使用静态内容 -->
<slot-dft-content>提交</slot-dft-content>
<!-- 编译作用域 -->
<!-- parentValue是在父组件vm的data中定义的 -->
<slot-dft-content>{{parentValue}}</slot-dft-content>
<!-- 如果放开下面这行,会报异常,因为sonValue是在子组件SlotDftContent的data中定义的 -->
<!-- <slot-dft-content>{{sonValue}}</slot-dft-content> -->
</div>
<script>
// 注册SlotDftContent组件
Vue.component('slot-dft-content', {
template: `
<button type="submit">
<slot>提交</slot>
</button>
`,
data: function() {
return {
sonValue: 'sonContent'
}
}
});
// 创建Vue实例并挂载到#app元素
const vm = new Vue({
el: '#app',
data: {
parentValue: 'parentContent'
}
});
</script>
...
具名插槽
有时候在一个子元素中需要定义多个插槽,使用子元素的时候,将不同内容分发到不同插槽中去。这时候,开发人员可以使用 slot 的 name 属性,给每个 slot 命名(没有命名的为 default),使用子组件时,用 template 元素包含要分发到每个 slot 的内容,使用“v-slot:目标插槽的名称”来指定对应的分发插槽。示例代码如下:
...
<div id="app">
<base-layout>
<!-- 具名插槽:header -->
<template v-slot:header>头</template>
<!-- 具名插槽:footer -->
<template v-slot:footer>尾</template>
<!-- 默认插槽内容 -->
<p>默认内容</p>
</base-layout>
</div>
<script>
// 注册BaseLayout组件
Vue.component('base-layout', {
template: `
<div class="container">
<header>
<!-- header具名插槽 -->
<slot name="header"></slot>
</header>
<main>
<!-- 默认插槽 -->
<slot></slot>
</main>
<footer>
<!-- footer具名插槽,当前为空 -->
<slot name="footer"></slot>
</footer>
</div>
`
});
// 创建Vue实例并挂载到#app元素
const vm = new Vue({
el: '#app'
});
</script>
...
作用域插槽
有时候,需要获取子元素的数据,进行整理后再分发给插槽,这时候可以使用作用域插槽。开发人员可以在 slot 元素中,使用 v-bind 指令将对象绑定后,传递到组件外面,如:slot v-bind:userAttr="user".../slot 就是将子元素中的 user 数据,通过 v-bind 指令绑定到 userAttr 属性上。
userAttr 属性又称为 slot property,在父组件中,可以在 template 元素中使用指定的插槽属性变量操作 userAttr 绑定的 user 数据,代码如下:
<div id="app">
<!-- 使用作用域插槽 -->
<range-slot>
<template v-slot:default="slotProps">
{{ slotProps.userAttr.userName }}整理好了
</template>
</range-slot>
</div>
<script>
// 定义RangeSlot组件
Vue.component('range-slot', {
template: `
<div>
<!-- 作用域插槽,向父组件传递userAttr属性 -->
<slot v-bind:userAttr="user"></slot>
</div>
`,
data: function() {
return {
user: {
name: '李四',
userName: 'lisi'
}
}
}
});
// 创建Vue实例并挂载到#app元素
const vm = new Vue({
el: '#app'
});
</script>
...
动态插槽名
动态指令参数也可以用在 v-slot 上,用来定义动态的插槽名。特别要注意的是,这里不支持驼峰命名的变量名,语法如下:
<range-slot>
<template v-slot:[动态的插槽名称]>
...
</template>
</range-slot>
具名插槽的缩写
跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容(v-slot:)替换为字符 #。v-slot:header 可以被重写为 # header,代码如下:
<base-layout>
<!-- Header template -->
<template #header>
<h1>Here might be a page title</h1>
</template>
<!-- Main content -->
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<!-- Footer template -->
<template #footer>
<p>Here's some contact info</p>
</template>
</base-layout>
然而,和其他指令一样,该缩写只在有参数的时候才可用,这意味着以下语法是无效的:
<!-- 这样会触发一个警告 -->
<current-user #="{ user }">
{{ user.firstName }}
</current-user>
如果开发人员希望使用缩写,则必须始终以明确的插槽名取而代之,代码如下:
<current-user #default="{ user }">
{{ user.firstName }}
</current-user>
ICP备案:
公安联网备案: