實(shí)現(xiàn)三個(gè)接口:React.createElement, React.Component,ReactDom.render
在src目錄下創(chuàng)建一個(gè)react目錄 /src/react/index.js
**
function createElement() {
console.log(arguments)
}
const React = {
createElement
}
export default React;
在index.js里面引入 react/index.js
**
import React from "./react";
更新index.js:為createElement添加參數(shù)并返回結(jié)果對象
function createElement(type, props,...children){
// 父元素需要子元素返回結(jié)果贺辰,這里可以通過JSX編譯后的代碼得出結(jié)論
props.children = children;
return {type,props}
}
export default {createElement}
render
- 在src下創(chuàng)建一個(gè)react-dom /src/react-dom/index.js
- 創(chuàng)建一個(gè)render函數(shù)户盯,能夠?qū)dom渲染出來嵌施,這里先打印vnode
function render(vnode, container) {
container.innerHTML = `<pre>${JSON.stringify(vnode, null, 2)}</pre>`
}
export default {render}
在react-dom下創(chuàng)建一個(gè)react-vdom.js /src/react-dom/react-vdom.js
- 在當(dāng)前文件下需要將虛擬dom轉(zhuǎn)化成真實(shí)dom
- 處理原生標(biāo)簽、類組件莽鸭、函數(shù)組件&&各種屬性吗伤、事件
首先要區(qū)分一下type是=原生標(biāo)簽、類還是函數(shù)硫眨,聲明一個(gè)createVNode方法去將虛擬dom包裝一下
export function createVNode(vtype, type, props) {
const vnode = { vtype, type, props};
return vnode;
}
在react/index.js的createElement方法里去判斷type類型 并將vtype做標(biāo)識
import {createVNode} from '../react-dom/react-vdom';
function createElement(type, props, ...children) {
props.children = children
delete props.__source;
delete props.__self;
let vtype;
if (typeof type === 'string') {
//原生標(biāo)簽
vtype = 1;
} else if (typeof type === 'function') {
if (type.isClassCompoent) {
//類組件
vtype = 2;
} else {
//函數(shù)組件
vtype = 3;
}
}
return createVNode(vtype, type, props)
}
export class Component {
static isClassComponent = true;
constructor(props) {
this.props = props;
this.state = {};
}
}
看頁面輸出足淆,每個(gè)對應(yīng)的組件vdom已經(jīng)有了標(biāo)識,接下來就按這個(gè)標(biāo)識對vdom進(jìn)行處理
-
在react-vdom文件下 聲明一個(gè)initVNode方法礁阁,將虛擬dom抓轉(zhuǎn)化成真實(shí)dom
function initVNode(vnode) { const { vtype } = vnode; if (!vtype) { //沒有vtype代表是文本節(jié)點(diǎn) return document.createTextNode(vnode); } else if (vtype === 1) { //原生標(biāo)簽 return createElementTag(vnode) } else if (vtype === 2) { //class return createClassComp(vnode) } else if (vtype === 3) { //函數(shù) return createFuncComp(vnode) } }
對這三個(gè)方法進(jìn)行擴(kuò)展處理
function createElementTag(vnode) {
const { type, props } = vnode;
const node = docunment.createElement(type);
//處理特殊屬性
const { key, children, ...rest } = props;
Object.keys(rest).forEach(i => {
// 處理特殊屬性巧号,例如className、htmlfor姥闭、style等屬性
if (i === 'className') {
node.setAttribute('class', rest[i]);
} else if (i === 'style' && typeof rest[i] === 'object') {
const style = Object.keys(rest[i]).map(s => s + ':' + res[i][s]).join(';');
node.setAttribute('style', style);
} else if (/on\w+/.test(i)) {
//通過正則對事件進(jìn)行處理
const event = i.toLowerCase();
node[event] = rest[i];
} else {
node.setAttribute(i, rest[i]);
}
})
//遞歸渲染子元素
children.forEach(dom => {
if (Array.isArray(dom)) {
dom.forEach(n => node.appendChild(initVNode(dom)));
} else {
node.appendChild(initVNode(dom));
}
})
return node;
}
// 對class類聲明的組件進(jìn)行處理
function createClassComp(vnode) {
const {type, props} = vnode;
const vdom = new type(props).render();
return initVNode(vdom);
}
// 對function聲明的組件進(jìn)行處理
function createFuncComp(vnode) {
const {type, props} = vnode;
const vdom = new type(props);
return initVNode(vdom);
}
- 最后在/react-dom/index.js里面講initVNode方法進(jìn)行調(diào)用 看下頁面結(jié)果
import {initVNode} from './react-vdom'
function render(vnode, container) {
//container.innerHTML = `<pre>${JSON.stringify(vnode, null, 2)}</pre>`
const node = initVNode(vnode);
container.appendChild(node);
}
export default {render}
jsx:
import React, {Component} from './react';
import ReactDOM from './react-dom';
console.log(ReactDOM)
function Comp (props) {
return <h2>{props.name}</h2>
}
class Comp2 extends Component {
render () {
return (
<div>
<h2>hi {this.props.name}</h2>
</div>
)
}
}
const users = [
{
name: '123',
age: 12
},
{
name: '1xzc23',
age: 13
}
]
const ele = (
<div className="active" style={{color: 'red'}} onClick={() => alert('clcik')}>
<span>hello</span>
<Comp name="hi,function"></Comp>
<Comp2 name="hi,class"></Comp2>
{/* <ul>
{users.map(item => {
return (
<li>{item.name}-{item.age}</li>
)
})}
</ul> */}
</div>
)
console.log(ele)
ReactDOM.render(ele, document.getElementById('root'));