做自己头像的网站,梧州建设网站,旅行社网站规划与建设,室内设计和装修设计为学习Vue基础知识#xff0c;我动手操作通关了Vue演练场#xff0c;该演练场教程的目标是快速体验使用 Vue 是什么感受#xff0c;设置偏好时我选的是选项式 单文件组件。以下是我结合深入指南写的总结笔记#xff0c;希望对Vue初学者有所帮助。 文章目录 十五. 插槽插槽…为学习Vue基础知识我动手操作通关了Vue演练场该演练场教程的目标是快速体验使用 Vue 是什么感受设置偏好时我选的是选项式 单文件组件。以下是我结合深入指南写的总结笔记希望对Vue初学者有所帮助。 文章目录 十五. 插槽插槽内容与出口渲染作用域默认内容具名插槽条件插槽动态插槽名作用域插槽具名作用域插槽高级列表组件示例无渲染组件 十五. 插槽
插槽内容与出口
父组件可以用props向子组件传递js表达式emits向子组件传递事件那能不能直接向子组件传递定义好的模板内容呢 这就是插槽的作用。
!-- Dialog.vue --
div classdialogslot /
/divDialogdiv对话框内容/div
/Dialog最终渲染出的 DOM 是这样
div classdialogdiv对话框内容/div
/div渲染作用域
由于插槽内容是在父组件里定义的所以它能访问到父组件的数据作用域不能访问子组件的。
!-- Dialog.vue --
script
export default {data() {return {msg: 来自子组件的内容};}
}
/script
templatediv classdialogslot //div
/templatescript
import Dialog from ./Dialog.vue;
export default {components: {Dialog},data() {return {msg: 来自父组件的内容};}
}
/script
templateDialogdiv{{msg}}/div/Dialog
/template最终渲染出的 DOM 是这样
div classdialogdiv来自父组件的内容/div
/div默认内容
slot 标签之间的内容可以作为默认内容如果父组件使用了含有插槽的子组件但没有传入插槽内容子组件中的插槽就使用默认内容。
!-- Dialog.vue --
div classdialogslot默认内容/slot
/divDialogdiv对话框内容/div
/Dialog
Dialog /最终渲染出的 DOM 是这样
div classdialogdiv对话框内容/div
/div
div classdialog默认内容
/div具名插槽
有时候我们希望子组件能接收多个插槽内容比如希望一个对话框组件支持分别接收头部内容、主体内容、底部内容。对于这种场景 元素可以有一个特殊的 attribute name用来给各个插槽分配唯一的 ID。 这类带 name 的插槽被称为具名插槽 (named slots)。没有提供 name 的 slot 出口会被隐式地命名为“default”。
!-- Dialog.vue --
div classdialog!-- 对话框头部 --header classcard-headerslot nameheader //header!-- 对话框主体 --main classcard-mainslot/slot/main!-- 对话框尾部 --footer classcard-footerslot namefooter默认底部/slot/footer
/div与之slot nameheader匹配的是包含模板内容的template v-slot:header或简写为template #header
Dialog!-- 对话框头部 --template #headerdiv我的标题/div/template!-- 对话框主体 --template #defaultp我的内容1/pp我的内容2/p/template!-- 对话框尾部 --template #footerbutton取消/buttonbutton确定/button/template
/Dialog当一个组件同时接收默认插槽和具名插槽时所有位于顶级的非 template 节点都被隐式地视为默认插槽的内容。所以也可以省略掉template #default把其中内容直接作子组件的直接子元素但不能混用即子组件的直接子元素中不能同时出现template #default和非 template 节点。
Dialog!-- 对话框头部 --template #headerdiv我的标题/div/template!-- 对话框主体 --p我的内容1/pp我的内容2/p!-- 对话框尾部 --template #footerbutton取消/buttonbutton确定/button/template
/Dialog最终渲染出的 HTML 如下
div classdialog!-- 对话框头部 --header classcard-headerdiv我的标题/div/header!-- 对话框主体 --main classcard-mainp我的内容1/pp我的内容2/p/main!-- 对话框尾部 --footer classcard-footerbutton取消/buttonbutton确定/button/footer
/div推荐在使用具名插槽的时候为默认插槽使用显式的 template 标签不容易混淆更加可读。
条件插槽
在上面的例子中我们为对话框组件的 header、footer 或 default 等插槽设置了margin等样式
header classcard-headerslot nameheader /
/header但如果用户希望创建一个没有头部的对话框于是不传header插槽内容且没有默认插槽内容那就会出现对话框顶部渲染出一个空的header。
header classcard-header/header那么有没有办法在根据header插槽存在与否来决定要不要渲染header标签呢 可以结合 $slots 属性与 v-if 来实现
header classcard-header v-if$slot.headerslot nameheader /
/header其中的$slots表示父组件传入插槽的对象。 通常用于手写渲染函数但也可用于检测是否存在插槽。 每一个插槽都在 this.$slots 上暴露为一个函数返回一个 vnode 数组同时 key 名对应着插槽名。默认插槽暴露为 this.$slots.default。
// this.$slots等于
{default: () div.../div,header: () div.../div,footer: () div.../div,
}动态插槽名
插槽名不仅可以设置为常量还可以设置为变量如以下设置插槽名为变量mySlotName
!-- Dialog.vue --
div classdialogslot :namemySlotName默认底部/slot
/divDialogtemplate #[mySlotName]button取消/buttonbutton确定/button/template
/Dialog作用域插槽
上文中提到插槽是在父组件中被定义的所以无法读取到子组件的状态。那假如插槽需要拿到子组件状态该怎么办呢 可以像对组件传递 props 那样向插槽出口slot上传入 attributes实现把子组件的变量传递到插槽内容
!-- Dialog.vue --
div classdialogslot msg来自子组件的内容 / !-- 将子组件的状态传入slot --
/divDialog v-slotslotProps !-- 设置一个slotProps变量接收来自父组件的插槽Props --div{{slotProps.msg}}/div
/Dialog
// 或
Dialog v-slot{msg}div{{msg}}/div
/Dialog最终渲染出的 DOM 是这样
div classdialogdiv来自子组件的内容/div
/div具名作用域插槽
作用域插槽也可以与具名插槽混用如下面的v-slot:headerslotProps1也可写作#headerslotProps1
!-- Dialog.vue --
div classdialogheaderslot nameheader msg来自子组件的内容1 //headermainslot msg来自子组件的内容2//main
/divDialog!-- header插槽 --!-- v-slot设置在template上而不是Dialog上 --!-- v-slot:headerslotProps1 也可以简写成 #headerslotProps1 --template #headerslotProps1 div来自父组件的内容/divdiv{{slotProps1.msg}}/div/template!-- 默认插槽 --!-- 支持在 v-slot 中使用解构 --!-- 可写作 v-slot{msg} 或 v-slot:default{msg} 或 #default{msg} --template #default{msg}div{{msg}}/div/template/Dialog最终渲染出的 DOM 是这样
div classdialogheaderdiv来自父组件的内容/divdiv来自子组件的内容1/div/headermaindiv来自子组件的内容2/div/main
/div再次推荐为默认插槽使用显式的 template 标签不容易出错。 不允许像下面这样 同时在子组件上和template上定义v-slot否则会编译报错。 Dialog v-slotslotProps2!-- header插槽 --template v-slot:headerslotProps1 div来自父组件的内容/divdiv{{slotProps1.msg}}/div/template!-- 默认插槽 --div{{slotProps2.msg}}/div/Dialog高级列表组件示例
通过对具名作用域插槽的运用我们可以实现一个高级列表组件封装了可重用的逻辑 (如数据获取、分页、无限滚动等) 和视图输出并将部分视图输出如列表项的内容和样式、每页条目数通过作用域插槽交给了消费者组件来管理。
!-- FuncyList.vue --
ulli v-foritem in list keyitem.idslot nameitemSlot v-binditem{{item}}/slot/li每页{{pageNum}}个
/ulFuncyList :page-num10 template #itemSlot{id, title} div{{id}}-{{title}}/div/template/FuncyList无渲染组件
一些组件可能只包括了逻辑而不需要自己渲染内容视图输出通过作用域插槽全权交给了消费者组件。我们将这种类型的组件称为无渲染组件。
!-- NoRenderComponent.vue --
script
export default {data() {return {pi: 3.1415926535};},computed: {doublePi: () this.pi *2;}
}
/script
template!-- 仅包含逻辑不包含任何视图 --slot :textdoublePi /
/temlateNoRenderComponent template v-slot{text}!-- 展示NoRenderComponent数据的视图写在插槽里 --div classuiClass{{text}}/div/template
/NoRenderComponent