中国住房城乡建设厅网站首页,做网站做推广有效果吗,wordpress vs,简历设计网官网文章目录 前言为什么需要插槽作用域插槽插槽的原理总结 前言
插槽是Vue中一个重要的特性#xff0c;它有很多种用法#xff1a;默认插槽、具名插槽、作用域插槽。尤其作用域插槽#xff0c;还有一堆特性#xff0c;比如解构prop#xff0c;解构prop的时候还可以进行属性名… 文章目录 前言为什么需要插槽作用域插槽插槽的原理总结 前言
插槽是Vue中一个重要的特性它有很多种用法默认插槽、具名插槽、作用域插槽。尤其作用域插槽还有一堆特性比如解构prop解构prop的时候还可以进行属性名的映射。 记不住根本记不住。 死记硬背当然记不住但只要了解了原理这些根本不用记。
为什么需要插槽
在深入原理之前我们还是巩固一下基础。 为什么我们需要插槽这个特性插槽到底是什么 如果你看的是Vue2的文档那么你会一头雾水 Vue2几乎是没什么铺垫上来就给你介绍插槽的特性。所以插槽到底是什么为什么要用这个东西得你自己悟。 Vue3的文档稍微好一点 Vue3的文档说到了插槽的一些关键的点但仍然很隐晦。 这里我们戳破这层窗户纸给插槽一个明确的定义
插槽给是组件的一种传参方式。组件可以通过props传参也可以通过插槽传参。props传参传的是对象或值插槽传的是模板内容使用插槽的目的是将一部分由子组件负责的渲染工作交给父组件定义提高的组件的灵活性
为什么要使用插槽呢接下来我通过一个例子来说明。 现在假设你要实现一个无序列表的组件基本长下面这样 但是用户可能不满足于此他们希望能让选项的字体加粗或者变成斜体或者改变字体颜色或者在选项前面增加图标。更有甚者他们希望选项的内容可以是更加复杂的DOM结构。
怎么办如果没有插槽你只能给组件提供足够多的props让用户通过设置这些props来定制自己想要的效果。用户有新的需求你也要跟着修改。
用插槽就可以完美解决这个问题。 我们定义一个组件List
script setuplet props defineProps([data])
/scripttemplateulli v-foritem in props.dataslot v-binditem{{item.text}}/slot/li/ul
/template父组件可以这么用
script setup
import { ref } from vue
import List from ./List.vue;const data [ {text: Java }, { text: PHP}, { text: CSS} ]
/scripttemplateList :data /
/template这里使用的是后备内容所以就是平平无奇的展示。
如果父组件想要让文字加粗或者使用斜体或改变颜色它可以自己定义
template v-slotdatabi{{data.text}}/i/b/templateList组件不需要做任何改动。
作用域插槽
这里我们不在赘述默认插槽、具名插槽这没啥好说的我们直接来看作用域插槽。 作用域插槽的难点就在解构prop上写法有很多种比如
template v-slot{ user }{{ user.name }}
/template你有没有想过为啥user要包裹一个花括号你也可以不包裹
template v-slotscope{{ scope.user.name }}
/template你还可以进行属性映射
template v-slot{ user: person }{{ person.name }}
/template你还可以这样
template v-slot{ user { name: Guest } }{{ user.name }}
/template不是这都是啥直接懵了呀。
我为什么要加括号什么时候不加属性映射是个啥有啥用呀解构的时候还可以提供默认值还有这是Vue的模板语法还是JS的语法呀
有这些疑问都是因为不熟悉插槽的原理。不熟悉原理就只能死记硬背熟悉了根本就不用记。 在vue2的文档里面有对解构的原理进行解释 所以这些语法不是Vue创造的而是ES2015的函数参数解构的语法比如 普通的参数解构
function test({ name }) {console.log(name)
}let user { name: 张三, age: 18 }
test(user) // 张三解构的时候提供默认值
function test({ name张三 }) {console.log(name)
}let user { age: 18 }
test(user) // 张三
user.name 李四
test(user) // 李四解构的时候进行属性映射
function test({ name: userName}) {console.log(userName)
}let user { name: 张三, age: 18 }
test(user) // 张三只要这种参数解构的语法是JS支持的那么Vue的插槽就是支持的你还需要死记硬背吗。
插槽的原理
最后我们终于要系统性的看看插槽是怎么实现的了我们可以在Vue的Playground看看插槽编译后的结果。 子组件编译后的关键代码 子组件的render函数中通过调用renderSlot方法来渲染插槽你可以认为子组件会去调用
_ctx.$slots.default({item})如果父组件没有提供插槽的模板子组件就会渲染后备内容也就是
_createTextVNode(_toDisplayString(item.text), 1 /* TEXT */)接下来我们再看看父组件编译后的关键代码 父组件通过createBlock渲染子组件第三个参数传的是插槽的实现default就是默认插槽的名字如果是具名插槽那么就是对应插槽的名字。 我通过JS的高阶函数来模拟这个过程让大家更容易理解这个原理。 现在假设我一个函数list
function list(consumer) {const data [ {text: Java }, { text: PHP}, { text: CSS} ]for (let item of data) {consumer(item)}
}list函数可以通过接收一个consumer让调用方来控制输出的方式。 调用方可以这样
list((data) console.log(data.text))
// Java
// PHP
// CSS也可以控制输出比如
list((data) console.log(, data.text, ))
// Java
// PHP
// CSS也可以解构
list(({text}) console.log(text))
// Java
// PHP
// CSS这样是不是更容易理解了。 父组件不同的插槽实现编译出来的结果也不一样这就是vue的编译器要做的事情了。 比如我们看看prop解构的时候编译的结果是什么样子的。 没有解构的情况
template v-slotdata{{data.text}}/template编译后 有解构
template v-slot{text}{{text}}/template编译后 解构的时候进行属性映射
template v-slot{text: name}{{name}}/template编译后 提供参数默认值 是不是一模一样所以这块就是用的JS的语法特性。
什么时候需要进行解构什么时候不需要呢这取决于父组件需要关注哪些prop。 子组件定义插槽的时候可以绑定多个属性比如
slot :textitem.text :iconitem.icon{{item.text}}/slot编译后的结果如下 如果父组件提供插槽内容的时候只使用text那么就可以只解构出text属性。
template v-slot{ text }{{text}}/template如果text和icon都要用到那么就都解构
template v-slot{ text, icon }i classfa :classfa- icon/ispan{{text}}/span/template或者不解构
template v-slotitemi classfa :classfa- item.icon/ispan{{item.text}}/span/template这些都不需要死记硬背你知道了原理知道了父组件v-slot的内容就是子组件所有bind的属性组成的对象知道了它的结构你就知道要不要解构以及可以怎么解构。
总结
总结一下最重要的三个结论
插槽是一种组件的传参方式可以传递模板内容可以提高组件的灵活性插槽的本质就是JS的高阶函数函数由父组件实现子组件调用插槽的prop解构不是vue的语法本质就是ES6方法参数的解构语法