08.实现函数setPropsForDOM进行属性更新
上一小节我们已经将一个字符串渲染到了页面上,但这个字符串没有样式,假设我们在index.js中的jsx给div添加一些属性,会发现页面内容没有任何样式上的区别。这是因为我们根据虚拟DOM创建DOM的时候,也就是createDOM函数中,没有对属性进行处理,这一小节就来完成这项工作,将虚拟DOM上携带的属性信息追加到创建的真实DOM上。具体代码变化过程请观看视频,这里把关键代码展示出来:
index.js:
js
import React from './react';
import ReactDOM from './react-dom';
// 【这里需要注意jsx属性名称的写法】
ReactDOM.render(<div className='test-class' style={{color: 'red'}}>Simple React App<span>xx1</span><span>xx2</span></div>, document.getElementById('root'))react-dom.js:
js
function createDOM(VNode){
const {type, props} = VNode
let dom;
if (type && VNode.$$typeof === REACT_ELEMENT) {
dom = document.createElement(type);
}
if(props){
if (typeof props.children === 'object' && props.children.type) {
mount(props.children, dom)
} else if (Array.isArray(props.children)) {
mountArray(props.children, dom);
} else if (typeof props.children === 'string'){
dom.appendChild(document.createTextNode(props.children));
}
}
setPropsForDOM(dom, props) // 【增加的逻辑】
return dom
}
// 主要不要去死记硬背函数名称,我们这个版本的函数名称和原版源码的名称有所差异,但思路是一致的
function setPropsForDOM(dom, VNodeProps = {}) {
if(!dom) return
for (let key in VNodeProps) {
if (key === 'children') continue;
if (/^on[A-Z].*/.test(key)) { // 大家需要注意这个正则表达式为什么这么写
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
// ^ :开头
// . :含义1: Matches any single character except line terminators: \n, \r, \u2028分隔符 or \u2029段落分隔符. For example, /.y/ matches "my" and "ay", but not "yes", in "yes make my day", as there is no character before "y" in "yes".
// . :含义2: Inside a character class, the dot loses its special meaning and matches a literal dot.
// * : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers Matches the preceding item "x" 0 or more times.
// TODO: 事件相关内容我们在后续单独介绍
} else if (key === 'style') {
Object.keys(VNodeProps[key]).forEach(styleName => {
dom.style[styleName] = (VNodeProps[key])[styleName];
})
} else {
// 如果用函数setAttribute(key, VNodeProps[key]),则需要对key值进行转化
// dom上的属性名称和jsx的属性名称基本一致,但和我们编写html时候的属性名称是有差异的,需要注意
// 在官方文档上有关于属性名称的说明:https://reactjs.org/docs/introducing-jsx.html
// Since JSX is closer to JavaScript than to HTML, React DOM uses camelCase property naming convention instead of HTML attribute names.
// For example, class becomes className in JSX, and tabindex becomes tabIndex.
dom[key] = VNodeProps[key]
}
}
}