概述
在这里插入代码片
在HTML中 slot 元素 ,作为 Web Components 技术套件的一部分,是Web组件内的一个占位符
该占位符可以在后期使用自己的标记语言填充
举个栗子
Slot template
1
2
template不会展示到页面中,需要用先获取它的引用,然后添加到DOM中,
customElements.define(‘element-details’,
class extends HTMLElement {
constructor() {
super();
const template = document
.getElementById(‘element-details-template’)
.content;
const shadowRoot = this.attachShadow({mode: ‘open’})
.appendChild(template.cloneNode(true));
}
})
在Vue中的概念也是如此
Slot 艺名插槽,花名“占坑”,我们可以理解为solt在组件模板中占好了位置,当使用该组件标签时候,组件标签里面的内容就会自动填坑(替换组件模板中slot位置),作为承载分发内容的出口
使用场景
通过插槽可以让用户可以拓展组件,去更好地复用组件和对其做定制化处理
如果父组件在使用到一个复用组件的时候,获取这个组件在不同的地方有少量的更改,如果去重写组件是一件不明智的事情
通过slot插槽向组件内部指定位置传递内容,完成这个复用组件在不同场景的应用
比如布局组件、表格列、下拉选、弹框显示内容等
分类
slot可以分来以下三种:
默认插槽
具名插槽
作用域插槽
默认插槽
子组件用标签来确定渲染的位置,标签里面可以放DOM结构,当父组件使用的时候没有往插槽传入内容,标签内DOM结构就会显示在页面
父组件在使用的时候,直接在子组件的标签内写入内容即可
子组件Child.vue
插槽后备的内容
父组件子组件用name属性来表示插槽的名字,不传为默认插槽
父组件中在使用时在默认插槽的基础上加上slot属性,值为子组件插槽name属性值
子组件Child.vue
插槽后备的内容 插槽后备的内容 父组件 具名插槽 内容... 作用域插槽子组件在作用域上绑定属性来将子组件的信息传给父组件使用,这些属性会被挂在父组件v-slot接受的对象上
父组件中在使用时通过v-slot:(简写:#)获取子组件的信息,在内容中使用
子组件Child.vue
没传footer插槽
父组件 来⾃⼦组件数据:{{slotProps.testProps}}编写一个buttonCounter组件,使用匿名插槽
Vue.component(‘button-counter’, {
template: ’
})
使用该组件
new Vue({
el: ‘#app’,
template: '我是slot传入内容
',
components:{buttonCounter}
})
回顾setupRenderEffect
在组件的数据发生改变时会自动触发副作用渲染函数setupRenderEffect
// runtime-core/src/renderer.ts
import { effect } from ‘@vue/reactivity’
const setupRenderEffect = (instance, initialVNode, container, …) => {
// 在当前的组件实例上添加 update 方法,通过响应式方法 effect 创建
instance.update = effect(function componentEffect() {
if (!instance.isMounted) {
//...
} else {
// 非首次渲染,进入 update 阶段
let { next, vnode } = instance
// 缓存一份更新后的 vnode
let originNext = next
if (next) {
// 这里需要把更新后的组件 vnode 赋值 el,因为下面第一次 渲染新的组件 vnode 时并没有设置 el
next.el = vnode.el
updateComponentPreRender(instance, next)
} else {
// 如果没有 next 直接指向当前 vnode
next = vnode
}
// 渲染新的组件 vnode,因为数据发生了变化
const nextTree = renderComponentRoot(instance)
// 缓存旧的组件 vnode
const preTree = instance.subTree
// 更新实例上的 subTree 为新的组件 vnode
instance.subTree = nextTree
patch(prevTree, nextTree, ..., instance)
// 更新 DOM 元素
next.el = nextTree.el
}
}, prodEffectOptions)
这里主要看update的部分(即else代码块)。首先会先从组件实例instance里取出next(在处理组件一节会详细说明next存在与不存在的情况)。
组件内的数据发生了改变,所以要生成新的组件模板的vnode节点,在渲染阶段命名为subTree,然后还要保存一份旧的subTree,这样有了新旧subTree后就可以用patch函数更新DOM。
patch函数
在进入具体的diff流程之前,我们不妨先想一下,当数据发生改变时,会有哪些变化类型?
实际上按照类型可以分为更新普通DOM元素和更新vue组件这两种情况。下面先关注一下patch函数的逻辑。
// runtime-core/src/renderer.ts
const patch = (n1, n2, container, …) => {
// n1 是旧节点,n2 是新节点
// 如果 n1、n2 新旧节点的类型不同,直接销毁旧节点
if(n1 && !isSameVNodeType(n1, n2)) {
unmount(n1, parentComponent, parentSuspense, true)
n1 = null
}
const { type, ref, shapeFlag } = n2
switch(type) {
// 处理文本节点
case Text:
processText(n1, n2, container, anchor)
break
// 处理注释
case Comment:
processCommentNode(n1, n2, container, anchor)
break
// ...
default:
// 处理 DOM 元素
if(shapeFlag & ShapeFlags.ELEMENT) {
processElement(n1, n2, container, ...)
// 处理 vue 组件
} else if (shapeFlag & ShapeFlags.COMPONENT) {
processComponent(n1, n2, container, ...)
}
// ...
}
}
最开始先判断新旧节点的类型是否一样,如果不一样,可以设想某个节点从div标签变成span标签,最合理的方式是直接舍弃旧节点,重新挂载新的节点。
再往下会根据当前节点类型type进行特定的处理。比如文本节点执行processText的特定处理、注释节点执行processCommentNode的特定处理。这样的前置处理实际上是一个优化,在编译阶段,vue会将模版语法编译成渲染函数,这个时候会把第一个参数节点类型type填上,如果这个参数命中了这样的特殊节点,会直接执行相应的process方法。
default块儿里才是分析的重点,即处理普通DOM元素和vue组件
没有key值的情况
其实对于不写key值的diff处理非常的简单粗暴,会先取新旧数组长度较小的作为公共长度,然后以这个较小的长度挨个进行遍历并对新旧数组的节点patch。
之后判断:
如果新数组的长度大于旧数组,说明有新增的节点,那么只需要接着挂载即可。
如果新数组的长度小于旧数组,说明有删除的节点,那么只需要从尾部开始删除即可
最后
以上就是冷艳小猫咪为你收集整理的说说你对slot的理解?slot使用场景有哪些的全部内容,希望文章能够帮你解决说说你对slot的理解?slot使用场景有哪些所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复