手写一个简单的React(1)
搭建环境与JSX&虚拟DOM
使用parcel打包
npm install parcel-bundler 打包命令 npx parcel index.html
安***abel插件
"babel-plugin-transform-react-jsx": "^6.24.1", //主要调用React.createElement方法将jsx转换为数组
"babel-preset-env": "^1.7.0",
"babel-core": "^6.26.3",
"parcel-bundler": "^1.12.3"
//index.html
<body>
<div id="root"></div>
<script src="./index.js"></script>
</body>
//index.js
import React from './react'
import ReactDom from './react-dom'
const ele = (
<div className='active' title='123'>
hello,<span>react</span>
</div>
)
ReactDom.render(ele, document.querySelector('#root'))/react/index.js
/**
* createElement(tag,attrs,child1,child2)
*/
const React = {
createElement
}
function createElement(tag, attrs, ...childrens) {
return {
tag,
attrs,
childrens
}
}
export default React/react-dom/index.js
const ReactDom = {
render
}
function render(vnode, container) {
if (vnode === undefined) {
return
}
if (typeof vnode === 'string') {
//创建文本节点
const textNode = document.createTextNode(vnode)
return container.appendChild(textNode)
}
//虚拟dom
const { tag, attrs, childrens } = vnode
const dom = document.createElement(tag)
if (attrs) {
//遍历
Object.keys(attrs).forEach(key => {
const value = attrs[key]
setAttribute(dom, key, value)
})
}
//遍历子节点
childrens.forEach(child => {
render(child, dom)
})
return container.appendChild(dom)
}
//设置属性
function setAttribute(dom, key, value) {
//将className转换成class
if (key === 'className') {
key = 'class'
}
//如果是事件 onClick onBlur...
if (/on\w+/.test(key)) {
key = key.toLowerCase()
dom[key] = value || ''
} else if (key === 'style') {
if (!value || typeof value === 'string') {
dom.style.cssText = value
} else if (value && typeof value === 'object') {
//{width:20}
for (let k in value) {
if (typeof value[k] === 'number') {
dom.style[key] = value[k] + 'px'
} else {
dom.style[key] = value[k]
}
}
}
}
else {
//其他属性
if (key in dom) {
dom[key] = value || ''
}
if (value) {
dom.setAttribute(key, value)
} else {
dom.removeAttribute(key)
}
}
}
export default ReactDom
传音控股公司福利 333人发布
