组件是什么
未引入Virtual DOM前,请看以下代码
// _ => lodash
const compiler = _.template("<h1><%= title %></h1>");
const HelloComponent = (data) => {
return compiler(data);
};
const init= (data) => {
const App = document.getElementById("app");
App.innerHTML = HelloComponent({ title: "Hello!" });
setTimeout(() => {
App.innerHTML = HelloComponent({ title: "Hello Again!" });
}, 2000);
};
init();
从上面代码可以看出,组件是一个输入为模板所需数据和输出为模板字符串的函数,
模板 + 数据 => 模板字符串
引入Virtual DOM后, 请看以下代码
const { h, init } = snabbdom;
// init 方法用来创建 patch 函数
const patch = init([]);
const HelloComponent = (props) => {
const vnode = h("h1", props.title);
return vnode;
};
const load = () => {
const App = document.getElementById("app");
// 组件的产出是 VNode
const prevVnode = HelloComponent({ title: "Hello!" });
// 将 VNode 渲染成真实 DOM,增加了前后节点的对比后,才会渲染内容
patch(App, prevVnode);
// 两秒之后重渲染
setTimeout(() => {
// 数据变更,产出新的 VNode
const nextVnode = HelloComponent({ title: "Hello Again!" });
// 通过对比新旧 VNode,高效的渲染真实 DOM
patch(prevVnode, nextVnode);
}, 2000);
};
load()
从上面代码可以看出,组件是一个输入为数据和输出为* Virtual DOM*的函数
模板 + 数据 => Virtual DOM
让人不禁会问,为什么要引入Virtual DOM?这样只需对产出的vnode格式做统一规定,即可通过patch挂载函数实现在不同端的渲染了。
组件的挂载
请看如下代码
// MyComponent 组件
class MyComponent {
render(data) {
// render 函数产出 VNode
return {
tag: "div",
text: data.text
};
}
}
// VNode
const componentVnode = {
tag: MyComponent
};
const App = document.getElementById("app")
function render(container, vnode) {
if (typeof vnode.tag === "string") {
// html 标签
mountElement(container,vnode);
} else {
// 组件
mountComponent(container,vnode);
}
}
function mountComponent(container,vnode) {
// 创建组件实例
const instance = new vnode.tag()
instance.$vnode = instance.render({text: '组件div'})
// 挂载
mountElement(container, instance.$vnode);
}
function mountElement(container, vnode) {
// 创建元素
const el = document.createElement(vnode.tag);
el.innerText = vnode.text
// 将元素添加到容器
container.appendChild(el);
}
render(App, componentVnode);
render(App, {tag: 'div', text: '普通div'});
先是声名了一个组件类MyComponent ,利用单例模式生成新的组件,然后即可挂载
参考原文链接