25-更新element-更新props

136 阅读1分钟

来个案例

/*
 * @Author: Lin zefan
 * @Date: 2022-03-21 21:46:14
 * @LastEditTime: 2022-04-02 15:41:35
 * @LastEditors: Lin zefan
 * @Description:
 * @FilePath: windowmini-vue3windowexamplewindowupdateComponentwindowApp.js
 *
 */

import { h, ref } from "../../lib/mini-vue.esm.js";

export default {
  setup() {
    const counter = ref(1);
    function inc() {
      counter.value += 1;
    }

    const props = ref({
      foo: "foo",
      bar: "bar",
    });

    function patchProp1() {
      // 逻辑1: old !== new
      props.value.foo = "new-foo";
    }
    function patchProp2() {
      // 逻辑2: new === undefined || null, remove new
      props.value.bar = undefined;
    }
    function patchProp3() {
      // 逻辑3: old 存在,new 不存在,remove new
      props.value = {
        car: "car",
      };
    }

    return {
      counter,
      props,
      inc,
      patchProp1,
      patchProp2,
      patchProp3,
    };
  },
  render() {
    return h(
      "div",
      {
        foo: this.props.foo,
        bar: this.props.bar,
        car: this.props.car,
      },
      [
        h("div", {}, "" + this.counter),
        h("button", { onClick: this.inc }, "inc"),
        h("button", { onClick: this.patchProp1 }, "修改props"),
        h("button", { onClick: this.patchProp2 }, "删除props"),
        h("button", { onClick: this.patchProp3 }, "props重新赋值"),
      ]
    );
  },
};

实现

更新props

更新props时候主要考虑2种情况

  1. 更新
  2. 删除

render.ts

  function updateElement(n1, n2, container, parentComponent) {
    // 更新props
    patchProps(n1, n2);
  }
  
   function patchProps(n1: any, n2: any) {
    const prevProps = n1.props || EMPTY_OBJECT;
    const nowProps = n2.props || EMPTY_OBJECT;
    
    // 相等不操作
    if (prevProps === nowProps) return;
    
    // dom元素取的是旧vnode,覆盖新vnode的el
    const el = (n2.el = n1.el);

    
    // 值新增、变更的情况
    for (const key in nowProps) {
      if (prevProps[key] !== nowProps[key]) {
        hostPatchProp(el, key, nowProps);
      }
    }

    // 旧的props为空,不遍历
    if (EMPTY_OBJECT === prevProps) return;
    
    // 键不存在删除
    for (const key in prevProps) {
      if (!(key in nowProps)) {
        hostPatchProp(el, key, null);
      }
    }
  }

runtime-dom/index.ts

export function patchProp(el, key, props) {
  const val = (props && props[key]) || null;
  /** 注册事件
   * 1. 判断是否on开头并包含一个大写字母开头
   * 2. 是的话,截取on后面的内容
   * 3. 注册元素事件
   */
  if (isEvents(key)) {
    el.addEventListener(isEvents(key), val);
  } else {
    // 如果当前的值是空的,那要把对应的行内属性删除
    if (val === undefined || val === null) {
      el.removeAttribute(key);
      return;
    }
    el.setAttribute(key, val);
  }
}