此文章沒什么難度
// 類型校驗(yàn)工具
function typeOf (obj, type) {
const testType = Object.prototype.toString.call(obj).split(' ')[1].split(']')[0].toLowerCase();
return type === testType;
}
/**
* 創(chuàng)建虛擬dom對象
*/
export function createElement (type, props, ...childs) {
let jsxObj = {
type,
props: {},
key: null,
ref: null
};
if (props) {
// => 處理key和ref
if (props.hasOwnProperty("key")) {
jsxObj.key = props.key;
delete props.key;
}
if (props.hasOwnProperty("ref")) {
jsxObj.ref = props.ref;
delete props.ref;
}
jsxObj.props = Object.assign(jsxObj.props, props);
}
// => childrens 處理
if (childs.length > 0) {
childs = childs.length === 1 ? childs[0] : childs;
jsxObj.props["children"] = childs;
}
return jsxObj;
}
/**
* 把虛擬dom轉(zhuǎn)化為真實(shí)dom
*/
export function render (jsxObj, container, callback) {
let { type, props } = jsxObj;
// 1. 根據(jù)type創(chuàng)建一個(gè)dom(真實(shí)dom)
let elem = document.createElement(type);
// 1.1 根據(jù)props,中的屬性依次給創(chuàng)建的元素進(jìn)行設(shè)置
for (let key in props) {
// 1.2 關(guān)于某些特殊屬性的處理:className/style/children
if (/^className|style|children$/.test(key)) {
if (!props.hasOwnProperty(key)) break;
if (key === 'className') elem.className = props.className;
if (key === 'style') {
let styObj = props.style;
for (let sKey in styObj) {
if (!styObj.hasOwnProperty(sKey)) break;
elem["style"][sKey] = styObj[sKey];
}
}
if (key === 'children') {
let val = props['children'],
childrenArr = Array.isArray(val) ? val : [val];
// 循環(huán)迭代所有的子節(jié)點(diǎn):如果是字符產(chǎn) 直接插入到當(dāng)前dom中,如果是一個(gè)新的dom對象,遞歸調(diào)用render,再次創(chuàng)建元素插入到當(dāng)前dom
childrenArr.forEach(item => {
if (typeOf(item) === 'string') {
elem.appendChild(document.createTextNode(item));
return;
}
render(item, elem);
})
}
continue;
}
elem.setAttribute(key, props.key);
}
// 2. 把創(chuàng)建的對象添加到指定容器中
container.appendChild(elem);
typeOf(callback, 'function') && callback();
}