从render到mount

H函数

interface H_Interface {
  tag: string;
  props: object | null;
  child?: string | any[];
}
const h = (
  tag: string,
  props: object | null,
  child?: string | any[]
): H_Interface => {
  return {
    tag,
    props,
    child,
  };
};
export default h;

mount函数

interface Vnode_Interface {
  tag: string;
  props: object | null;
  child?: string | any[];
}

const mount = (Vnode: Vnode_Interface): HTMLElement => {
  //挂载
  let parentNode: HTMLElement = document.createElement(Vnode.tag);
  if (Vnode.props) {
    for (let key in Vnode.props) {
      if (key.startsWith("on")) {
        //处理事件
        const EventName = key.slice(2).toLocaleLowerCase();
        parentNode.addEventListener(EventName, Vnode.props[key]);
      } else {
        //纯attribute
        parentNode.setAttribute(key, Vnode.props[key]);
      }
    }
  }
  if (Vnode.child) {
    if (Array.isArray(Vnode.child)) {
      if (Vnode.child.length) {
        for (let i = 0; i < Vnode.child.length; i++) {
          if (typeof Vnode.child[i] == "string") {
            parentNode.textContent += Vnode.child[i];
          } else {
            parentNode.appendChild(mount(Vnode.child[i]));
          }
        }
      }
    } else {
      parentNode.textContent += Vnode.child;
    }
  }
  return parentNode;
};

export default mount;

Vue构造函数

import mount from "./mount";
import h from "./h";

interface H_Interface {
  tag: string;
  props: object | null;
  child?: string | any[];
}
interface Vnode_Interface extends H_Interface {}
interface Vue_Options_Interface {
  el?: string;
  data?: object | (() => object);
  methods?: object;
  props?: Array<string> | object;
  render?: (
    h: (
      tag: string,
      props: object | null,
      child?: string | any[]
    ) => H_Interface
  ) => Vnode_Interface;
}

class Vue {
  public $root: HTMLElement;
  public $data: object | (() => object);
  public $methods: object;
  public $props: Array<string> | object;
  constructor(options: Vue_Options_Interface) {
    this.$root = document.querySelector(options.el);
    this.$data = options.data
      ? typeof options.data == "function"
        ? options.data()
        : options.data
      : null;
    this.$methods = options.methods ? options.methods : null;
    // this.$props = options.props ? options.props : null;
    if (this.$data) {
      for (let key in this.$data) {
        this[key] = this.$data[key];
      }
    }
    if (this.$methods) {
      for (let key in this.$methods) {
        this[key] = this.$methods[key];
      }
    }
    //beforMount
    this.$root.appendChild(mount(options.render(h)));
    //mounted
  }
}

export default Vue;

测试code

import Vue from "./vue";

const vm = new Vue({
  el: "#app",
  data() {
    return {
      msg: "zz",
    };
  },
  methods: {
    say() {
      console.log(this.msg);
    },
  },
  render(h) {
    return h("h1", { id: "red" }, [
      "hello",
      "world",
      h("span", { class: "span" }, "i am child"),
      h("span", { class: "span" }, "i am child2"),
      h("span", { class: "span", id: "lastSpan" }, [
        h("i", { class: "i" }, "icon"),
      ]),
    ]);
  },
});
console.log(vm);

效果--->Vnode成功渲染至指定根节点上

posted @ 2021-09-24 17:41  微若蜉蝣  阅读(116)  评论(0)    收藏  举报