83 lines
2.9 KiB
TypeScript
83 lines
2.9 KiB
TypeScript
type JSXElement = {
|
||
type: string | symbol;
|
||
props: Record<string, any>;
|
||
key?: string | number;
|
||
};
|
||
export function createDOMElement(jsxElement: JSXElement) {
|
||
// 如果 jsxElement 是 null, undefined 或者是布尔值,则直接跳过处理
|
||
if (jsxElement == null || typeof jsxElement === 'boolean') {
|
||
console.warn('Invalid JSX element:', jsxElement);
|
||
return null;
|
||
}
|
||
const { type, props } = jsxElement;
|
||
// React Fragment 的处理
|
||
if (type === Symbol.for('react.fragment')) {
|
||
const fragment = document.createDocumentFragment();
|
||
if (props.children) {
|
||
if (Array.isArray(props.children)) {
|
||
props.children.forEach((child) => {
|
||
const childElement = createDOMElement(child);
|
||
if (childElement) {
|
||
fragment.appendChild(childElement);
|
||
}
|
||
});
|
||
} else {
|
||
const childElement = createDOMElement(props.children);
|
||
if (childElement) {
|
||
fragment.appendChild(childElement);
|
||
}
|
||
}
|
||
}
|
||
return fragment;
|
||
}
|
||
|
||
const domElement = document.createElement(type as string);
|
||
|
||
// 处理 props
|
||
Object.keys(props).forEach((prop) => {
|
||
if (prop === 'children') {
|
||
// 递归处理 children
|
||
if (Array.isArray(props.children)) {
|
||
props.children.forEach((child) => {
|
||
const childElement = createDOMElement(child);
|
||
if (childElement) {
|
||
domElement.appendChild(childElement);
|
||
}
|
||
});
|
||
} else if (typeof props.children === 'string') {
|
||
domElement.appendChild(document.createTextNode(props.children));
|
||
} else if (typeof props.children === 'object' && props.children !== null) {
|
||
const childElement = createDOMElement(props.children);
|
||
if (childElement) {
|
||
domElement.appendChild(childElement);
|
||
}
|
||
}
|
||
} else if (prop.startsWith('on')) {
|
||
// 处理事件监听器
|
||
const eventType = prop.slice(2).toLowerCase(); // 提取事件类型(如 onClick -> click)
|
||
domElement.addEventListener(eventType, props[prop]);
|
||
} else if (prop === 'style' && typeof props[prop] === 'object') {
|
||
// 处理 style 属性
|
||
Object.assign(domElement.style, props[prop]);
|
||
} else if (prop === 'dangerouslySetInnerHTML') {
|
||
// 处理 dangerouslySetInnerHTML
|
||
if (props[prop] && typeof props[prop].__html === 'string') {
|
||
domElement.innerHTML = props[prop].__html;
|
||
} else {
|
||
console.warn('Invalid dangerouslySetInnerHTML content:', props[prop]);
|
||
}
|
||
} else if (prop === 'ref') {
|
||
// React 的 ref 在手动创建 DOM 时没有用处
|
||
console.warn('Ref prop is not supported in manual DOM creation');
|
||
} else if (prop === 'key') {
|
||
// React 的 key 属性是用于虚拟 DOM 的,不影响实际 DOM
|
||
console.warn('Key prop is not applicable in manual DOM creation');
|
||
} else {
|
||
// 处理其他普通属性
|
||
domElement.setAttribute(prop, props[prop]);
|
||
}
|
||
});
|
||
|
||
return domElement;
|
||
}
|