html引入renderer
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="./renderer.js"></script>
<script>
const vnode = h('div',{},[
h('div',{class:'yui'},'yui'),
h('span',{calss:'span'},'span')
])
mount(vnode,document.querySelector('#app'))
</script>
</body>
</html>
js的renderer
const h = (tag, props, children) =>{
return{
tag,
props,
children
}
}
const mount = (vnode,container) =>{
const el = vnode.el = document.createElement(vnode.tag)
if(vnode.props){
for (const key in vnode.props) {
const value = vnode.props[key]
if(key.startsWith('on')){
el.addEventListener(key.slice(2).toLowerCase(),value)
}else{
el.setAttribute(key,value)
}
}
}
if(vnode.children){
if(typeof vnode.children === 'string'){
el.textContent = vnode.children;
}else{
vnode.children.forEach(element => {
mount(element,el)
});
}
}
container.appendChild(el)
}
const patch = (n1,n2) => {
if(n1.tag !== n2.tag){
const n1Elparenter = n1.el.parentElement;
n1Elparenter.removeChild(n1.el);
mount(n2,n1Elparenter)
}else{
const el = n1.el = n2.el;
const oprops = n1.props || {};
const nprops = n2.props || {};
for (const key in nprops) {
const ovalue = oprops[key];
const nvalue = nprops[key];
if(ovalue !== nvalue){
if(key.startsWith('on')){
el.addEventListener(key.slice(2).toLowerCase(),nvalue)
}else{
el.setAttribute(key,nvalue)
}
}
}
for (const key in oprops) {
if(!(key in nprops)){
if(key.startsWith('on')){
const value = oprops[key]
el.removeEventListener(key.slice(2).toLowerCase(),value)
}else{
el.removeAttribute(key)
}
}
}
//children
const newchildren = n1.children || {};
const oldchildren = n2.children || {};
if(typeof newchildren === 'string'){
if(typeof oldchildren === 'string'){
if(newchildren !== oldchildren){
el.textContent = newchildren;
}
}else{
el.innerHtml = newchildren;
}
}else{
if(typeof oldchildren === 'string'){
el.textContent = ""
newchildren.forEach(item =>{
mount(item,el)
})
}else{
const min = Math.min(oldchildren.length,newchildren.length)
for (let i = 0; i < min; i++) {
patch(oldchildren[i],newchildren[i])
}
if(oldchildren.length > newchildren.length){
oldchildren.length.slice(min).forEach(item=>{
el.removeChild(item)
})
}
if(newchildren.length > oldchildren.length){
newchildren.length.slice(min).forEach(item=>{
mount(item,el)
})
}
}
}
}
}