vue源码笔记之——运行时runtime

一、源码中的位运算

在这里插入图片描述

  1. 按位于 运算
if (shapeFlag & ShapeFlags.TELEPORT) {

解释:如果shapFlag本身值为8,type为1的话,那么转换为二进制(js都是32位)那就是
shapFlag:00000000 00000000 00000000 00001000
type: 00000000 00000000 00000000 00000001
结果为: 00000000 00000000 00000000 00000000
按位进行运算,如果两个都为为1那就是1,否则为0,所以结果为0

  1. 按位或 赋值
vnode.shapeFlag |= type
// 和这个代码一样
vnode.shapeFlag = vnode.shapeFlag |type

解释:如果shapFlag本身值为8,type为1的话,那么转换为二进制(js都是32位)那就是
shapFlag:00000000 00000000 00000000 00001000
type: 00000000 00000000 00000000 00000001
结果为: 00000000 00000000 00000000 00001001
按位进行运算,如果有一个为1那就是1,所以结果为9

二、挂载vnode时,不同属性的挂载方式不同,这是为什么?

比如:
class使用的是vnode.className = 'newClass'
value是使用el[key] = 'newValue'
type是使用dom.setAttribute('type', 'newType')
主要原因为
HTML AttributeDOM properties区别

  • HTML Attribute:html标签上的属性,例如下面的target,href等
    在这里插入图片描述
  • DOM properties:所在dom对象属性,是通过document.getElementById('xx')获取到的dom对象

Element.setAttribute():可以设置元素上的某个属性值
dom.xxx:相当于直接修改指定对象的属性
但是对于相同的属性,两种方式的名称不同
例如class,使用dom修改为dom.className='' ,但是attr的方式就是dom.setAttribute('class', '')

小知识点:设置class时,className的性能高于setAttribute。所以vue进行了一个判断,优化性能,尽量使用className
在这里插入图片描述

三、事件挂载

vue的事件更新本质上其实就是下面的demo事件,触发点击时间本质上是触发invoker.value事件,所以挂载、更新、卸载等操作只需要处理invoker的value属性。

  const eleBtn = document.querySelector('button')
  const invoker = () => {
    invoker.value();
  }
  invoker.value = () => {
      alert('hh');
  }
  eleBtn.addEventListener('click', invoker)
  setTimeout(() => {
    invoker.value = () => {
      alert('pp');
    }
  }, 2000)

vue源码如下:

export function patchEvent(
  el: Element & { _vei?: Record<string, Invoker | undefined> },
  rawName: string,
  prevValue: EventValue | null,
  nextValue: EventValue | null,
  instance: ComponentInternalInstance | null = null
) {
  // vei = vue event invokers
  const invokers = el._vei || (el._vei = {})
  const existingInvoker = invokers[rawName]
  if (nextValue && existingInvoker) {
    // patch
    existingInvoker.value = nextValue
  } else {
    const [name, options] = parseName(rawName)
    if (nextValue) {
      // add
      const invoker = (invokers[rawName] = createInvoker(nextValue, instance))
      // 对浏览器的addEventLister进行了封装
      addEventListener(el, name, invoker, options) 
    } else if (existingInvoker) {
      // remove
      removeEventListener(el, name, existingInvoker, options)
      invokers[rawName] = undefined
    }
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值