以下为ChatGPT自动生成的解答,正确与否请自行判断。
BFE.devAI解答 - JavaScript 代码题
140. Virtual DOM III - Functional Component
思路:需要在原有的 createElement()
和 render()
函数中添加对 Functional Component 的支持。对于 Functional Component,我们只需要调用其函数并传入 props
参数即可得到它的返回值,即一个 MyElement
。因此,在 render()
函数中对于传入的函数组件,我们需要调用它,并将 props
作为参数传递进去。在 createElement()
函数中,对于传入的 MyComponent
,需要在它的 props
中加入 children
属性,并将函数名添加到 tag
属性中,以便后面可以通过函数名来判断这是一个函数组件。
完整代码如下:
/**
* @typedef MyElement
* @property {string} tag
* @property {Object} props
* @property {MyElement[]} children
*/
/**
* @param {string} tag
* @param {Object=} props
* @param {MyElement[]=} children
* @returns {MyElement}
*/
function createElement(tag, props = {}, ...children) {
if (typeof tag === 'function') { // 如果传入的是函数
return tag(Object.assign({}, props, { children }));
}
return {
tag,
props: Object.assign({}, props, { children }),
children: flatten(children)
};
}
/**
* @param {MyElement} element
* @returns {HTMLElement}
*/
function render(element) {
const el = document.createElement(element.tag);
for (let key in element.props) {
if (key.startsWith('on')) { // 处理事件监听器
el.addEventListener(key.substring(2).toLowerCase(), element.props[key]);
} else if (key === 'className') { // 将 className 改为 class
el.setAttribute('class', element.props[key]);
} else if (key === 'style' && typeof element.props[key] === 'object') { // 处理 style 属性
const styles = Object.keys(element.props.style).map(key => `${key}:${element.props.style[key]}`).join(';');
el.setAttribute('style', styles);
} else if (key === 'value' && element.tag === 'input') { // 处理 input 的 value 属性
el.value = element.props[key];
} else if (key !== 'children') { // 其他属性直接设置
el.setAttribute(key, element.props[key]);
}
}
element.children.forEach(child => {
const childEl = child instanceof MyElement ? render(child) : document.createTextNode(child);
el.appendChild(childEl);
});
return el;
}
/**
* 将多维数组扁平化
* @param {Array} arr
* @returns {Array}
*/
function flatten(arr) {
return arr.reduce((prev, curr) => {
return prev.concat(Array.isArray(curr) ? flatten(curr) : curr);
}, []);
}
测试代码如下:
const h = createElement
const Title = ({ children, ...res }) => h('h1', res, ...children)
const Link =
({ children, ...res }) => h('a', res, ...children)
const Name =
({ children, ...res }) => h('b', res, ...children)
const Button =
({ children, ...res }) => h('button', res, ...children)
const Paragraph =
({ children, ...res }) => h('p', res, ...children)
const Container =
({ children, ...res }) => h('div', res, ...children)
const app = h(
Container,
{},
h(Title, {}, ' this is '),
h(
Paragraph,
{ className: 'paragraph' },
' a ',
h(Button, {}, ' button '),
' from ',
h(
Link,
{ href: 'https://bfe.dev' },
h(Name, {}, 'BFE'),
'.dev')
)
)
document.body.appendChild(render(app))