说说你对slot的理解?slot使用场景有哪些

在这里插入代码片

在这里插入图片描述
在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。
之后判断:
如果新数组的长度大于旧数组,说明有新增的节点,那么只需要接着挂载即可。
如果新数组的长度小于旧数组,说明有删除的节点,那么只需要从尾部开始删除即可

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

故事只若初见

坚持就是胜利

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值