luy
Version:
所谓类```React```框架就是**和React用法一模一样**的框架。其实当初制造这个框架的目的是为了能更好的学习React内部结构,了解其原理而制作的玩具。但是随着框架的渐渐成长,代码越来越多,我还是决定将其发展下去. 
135 lines (112 loc) • 3.47 kB
JavaScript
import { typeNumber } from "./utils";
import { currentOwner } from './vdom'
const RESERVED_PROPS = {
ref: true,
key: true,
__self: true,
__source: true,
}
function Vnode(type, props, key, ref) {
this.owner = currentOwner.cur
this.type = type
this.props = props
this.key = key
this.ref = ref
}
/**
* 创建虚拟Dom的地方
* @param {string | Function} type
* @param {object} config
* @param {array} children
*/
function createElement(type: string | Function, config, ...children: array) {
let props = {},
key = null,
ref = null,
childLength = children.length;
if (config != null) {
//巧妙的将key转化为字符串
key = config.key === undefined ? null : '' + config.key
ref = config.ref === undefined ? null : config.ref
/**这一步讲外部的prop属性放进prop里 */
for (let propName in config) {
// 除去一些不需要的属性,key,ref等
if (RESERVED_PROPS.hasOwnProperty(propName)) continue
//保证所有的属性都不是undefined
if (config.hasOwnProperty(propName)) {
props[propName] = config[propName]
}
}
}
if (childLength === 1) {
props.children = typeNumber(children[0]) > 2 ? children[0] : []
} else if (childLength > 1) {
props.children = children
}
/**设置defaultProps */
let defaultProps = type.defaultProps;
if (defaultProps) {
for (let propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
return new Vnode(type, props, key, ref);
}
/**
* 实际上这里做的事情就是将文字节点全部转换成Vnode
* @param {*} children
*/
export function flattenChildren(children: Array) {
if (children === undefined) return new Vnode('#text', "", null, null)
let length = children.length
let ary = [],
isLastSimple = false, //判断上一个元素是否是string 或者 number
lastString = '',
childType = typeNumber(children)
if (childType === 4 || childType === 3) {
return new Vnode('#text', children, null, null)
}
if (childType !== 7) return children
children.forEach((item, index) => {
if (typeNumber(item) === 7) {
if (isLastSimple) {
ary.push(lastString)
}
item.forEach((item) => {
ary.push(item)
})
lastString = ''
isLastSimple = false
}
if (typeNumber(item) === 3 || typeNumber(item) === 4) {
lastString += item
isLastSimple = true
}
if (typeNumber(item) !== 3 && typeNumber(item) !== 4 && typeNumber(item) !== 7) {
if (isLastSimple) {//上一个节点是简单节点
ary.push(lastString)
ary.push(item)
lastString = ''
isLastSimple = false
} else {
ary.push(item)
}
}
if (length - 1 === index) {
if (lastString) ary.push(lastString)
}
})
ary = ary.map((item) => {
if (typeNumber(item) === 4) {
item = new Vnode('#text', item, null, null)
}
return item
})
return ary
}
export {
createElement,
Vnode
}