初识渲染器


// JS对象描述UI
const title = {
  // 标签名称
  tag: "h1",
  // 标签属性
  props: {
    onclick: handler,
  },
  // 子节点
  children: [{ tag: "span" }],
} // 对应的vue模版
`<h1 onclick="handler"><span></span></h1>`;

// import { h } from "vue";
// export default {
//   render(h) {
//     return h("h1", {
//       onclick: handler,
//     }); // 虚拟dom
//   },
// };

// 虚拟DOM就是用js对象来描述真实的DOM结构

const vnode = {
  // 标签名称
  tag: "div",
  // 标签属性
  props: {
    onclick: () => alert("hello world"),
  },
  // 子节点
  children: "click",
};

// 渲染器 把虚拟DOM转换成真实DOM

//普通元素
function mountElement(vnode, container) {
  const el = document.createElement(vnode.tag);
  for (const key in vnode.props) {
    if (/^on/.test(key)) {
      // 如果on开头的属性,则说明是事件
      el.addEventListener(key.slice(2).toLowerCase(), vnode.props[key]);
    }
  }
  if (typeof vnode.children === "string") {
    el.appendChild(document.createTextNode(vnode.children));
  } else if (Array.isArray(vnode.children)) {
    // 递归调用renderer函数渲染子节点,使用当前元素el作为挂载点
    vnode.children.forEach((child) => {
      renderer(child, el);
    });
    // 将元素添加到挂载点
    container.appendChild(el);
  }
}
// mountElement(vnode, document.body);
// 组件函数形式
const MyComponent = function () {
  return {
    // 标签名称
    tag: "div",
    // 标签属性
    props: {
      onclick: () => alert("hello world"),
    },
    // 子节点
    children: "click me",
  };
};
// 组件对象形式
const MyComponent2 =  {
 render() {
  return {
    // 标签名称
    tag: "div",
    // 标签属性
    props: {
      onclick: () => alert("hello world"),
    },
    // 子节点
    children: "click me",
  };
 },
};
const vComNode = {
  tag:MyComponent,
  tag2:MyComponent2,
}
//组件function形式渲染
function mountComponent(vnode, container) {
  // 调用组件函数,获取组件要渲染的内容(虚拟DOM)
  const subtree = vnode.tag();
  // 递归调用renderer函数渲染子组件subtree
  renderer(subtree, container);
}
// 组件对象 形式
function mountComponent(vnode, container) {
  // 调用组件函数,获取组件要渲染的内容(虚拟DOM)
  const subtree = vnode.tag.render();
  // 递归调用renderer函数渲染子组件subtree
  renderer(subtree, container);
}
function renderer(vnode, container) {
  if (typeof vnode.tag==='string') {
    mountElement(vnode, container);
  } else if (typeof vnode.tag === "function") {
    mountComponent(vnode, container);
  }else if (typeof vnode.tag === "object") {
    mountComponent2(vnode, container);
  } 
}

Last updated