原生js怎么写?
javascript
const dom = document.createElement("div")
dom.id="app"
document.querySelector('#root').append(dom)
const textNode = document.createTextNode("")
textNode.nodeValue = "app"
dom.append(textNode)
为什么需要虚拟dom?
通过以上原生写法可以看出,虚拟dom可以简化开发,使代码更加框架、结构化,清晰可读易于维护。
框架层面:频繁的dom操作会一直导致浏览器重排和重绘,会严重影响性能。
原生层面:相对于原生层面虚拟dom对性能提示微乎其微,并且在复杂情况会损耗性能。
当然虚拟dom还有个非常重要的作用就是跨端运行。
面试怎么答?
- 减少浏览器重排和重绘(框架层面、原生层面)
- 跨平台运行,不局限于浏览器
- 减少心智负担,提高开发效率
当然不能干巴巴的把这几点甩出去,记得拓展。
极简版React内核
此处代码实现了一个极简的创建虚拟dom和虚拟dom转真实dom
/core/React.js
javascript
//创建文本对象虚拟dom
function createTextNode(text) {
return {
type: "TEXT_ELEMENT",
props: {
nodeValue: text,
children: [],
},
};
}
//创建虚拟dom对象
function createElement(type, props, ...children) {
return {
type,
props: {
...props,
children: children.map((child) => {
return typeof child === "string" ? createTextNode(child) : child;
}),
},
};
}
//渲染器,vdom->tdom
function render(el, container) {
const dom =
el.type === "TEXT_ELEMENT"
? document.createTextNode("")
: document.createElement(el.type);
// id class
Object.keys(el.props).forEach((key) => {
if (key !== "children") {
dom[key] = el.props[key];
}
});
const children = el.props.children;
children.forEach((child) => {
render(child, dom);
});
container.append(dom);
}
const React = {
render,
createElement,
};
export default React;
可以看到以上代码中createElement
函数就实现了一个极简版的虚拟dom,里面有三个元素分别是:
type
:类型props
:传入的值children
:子节点
而render
函数则实现了一个极简版的渲染器,用于将虚拟dom转化成真实dom,传入的值分别是:
el
:虚拟dom对象container
:具体在哪个真实dom节点渲染
创建虚拟dom对象
/App.js
通过上面定义的createElement
函数来创建一个虚拟dom对象app
并将其导出
typescript
import React from './core/React.js';
const App = React.createElement("div", { id: "app" }, "hi- ", "mini-react");
export default App
极简React渲染组件
定义了一个createRoot
函数,通过传入的渲染容器container
和虚拟dom对象App
来将虚拟dom元素渲染到真实dom上。
/core/ReactDom.js
typescript
import React from "./React.js";
const ReactDOM = {
createRoot(container) {
return {
render(App) {
React.render(App, container);
},
};
},
};
export default ReactDOM;
创建ReactDOM
/main.js
javascript
import ReactDOM from "./core/ReactDom.js";
import App from "./App.js";
ReactDOM.createRoot(document.querySelector("#root")).render(App);
总结
createRoot
用于将虚拟dom渲染成真实dom
createElement
用于创建虚拟dom对象
render
是createRoot
的内核
项目总结构:
markdown
v01
├─ 📁core
│ ├─ 📄React.js
│ └─ 📄ReactDom.js
├─ 📄App.js
├─ 📄index.html
└─ 📄main.js
贴上main.js
:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="main.js"></script>
</body>
</html>