We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
VDOM,也叫虚拟 DOM,它是仅存于内存中的 DOM,因为还未展示到页面中,所以称为 VDOM
var vdom = document.createElement("div");
上面这一句就是最简单的虚拟 DOM
var vdom = document.createElement("div"); document.body.append(vdom);
上面这两句就是把虚拟 DOM 转化为 真实 DOM,其实就是把节点 append 到页面中
常见DOM操作,就三类:增、删、改。对应的DOM操作如下:
以前我们写代码经常会拼接完模板,简单粗暴的用$(el).html(template)整块节点替换
$(el).html(template)
这样做最大的问题在于性能,如果页面比较小,问题不大,但如果页面庞大,这样会出现卡顿,用户体验会很差,所以解决办法就是差量更新
差量更新就是只对局面的 HTML 片段进行更新。比如你加了一个节点,那么我就只更新这个节点,我无需整个模板替换。这样做效率就会提高。但问题在于,不知道哪个节点更新了,哪个节点删除了,哪个节点替换了,所以我们需要对 DOM 建模
DOM 建模,简单点说就是用一个 JS 对象来表示 VDOM。
如果我们可以用一个JS对象来表示 VDOM,那么这个对象上多一个属性(增加节点),少一个属性(删除节点),或者属性值变了(更改节点),就很清醒了
DOM 也叫 DOM 树,是一个树形结构,DOM 树上有很多元素节点,要对 VDOM 进行建模,本质上就是对一个个元素节点进行建模,然后再把节点放回 DOM 树的指定位置
每个节点都是由以下三部分组成
{type:"div",props: null, children:[ {type:"img",props:{"src":"avatar.png", "className":"profile"},children:[], {type:"h3",props: null, children:[{[user.firstName, user.lastName].join(' ')}], ]}
上面 VDOM 建模是用下面的 HTML 结构转出来的
var profile = <div> <img src="avatar.png" className="profile" /> <h3>{[user.firstName, user.lastName].join(' ')}</h3> </div>;
但这段代码并不是合法的 js 代码,它是一种被称为 jsx 的语法扩展,通过它我们就可以很方便的在 js 代码中书写 html 片段
本质上,jsx 是语法糖,上面这段代码会被 babel 转换成如下代码
pig("div", null, pig("img", { src: "avatar.png", className: "profile" }), pig("h3", null, [user.firstName, user.lastName].join(" ")))
而上面的这段被转化的代码是 将我们的 VDOM 配合pig(一般应该是createElement函数)转化为真实 DOM
pig
createElement
注意,如果是自定义组件<App />会转化为pig(App, null),因为组件是class App extends React.Component {}这样定义的,所以App进入createElement函数里面就会变成是一个对象
<App />
pig(App, null)
class App extends React.Component {}
这里我们可以把这个函数放进createElement()里面生成一个 VDOM 对象,然后用生成的 VDOM 对象,配合render()生成一个 DOM 插入页面,从而转变成真实 DOM 结构
createElement()
render()
补充createElement()方法的源代码
function createElement(type, props, ...childrens) { return { // 父标签类型,比如dev,ul等 type: type, // 属性值 props: { ...props, }, // 子节点,比如li,字符串等 children: childrens.length <= 1 ? childrens[0] : childrens }; }
补充render()方法的源代码
//=>DOM的动态创建 function render(jsxObj, container, callback) { let { type, props, children } = jsxObj; let newElement = document.createElement(type); //=>属性和子元素的处理 for (let attr in props) { if (!props.hasOwnProperty(attr)) break; switch (attr) { case 'className': newElement.setAttribute('class', props[attr]); break; case 'style': let styleOBJ = props['style']; for (let key in styleOBJ) { if (styleOBJ.hasOwnProperty(key)) { newElement['style'][key] = styleOBJ[key]; } } break; // =>CHILDREN case 'children': // 如果children放在props里面的话,这句才会有意义 // renderChildren() default: newElement.setAttribute(attr, props[attr]); } } renderChildren() function renderChildren() { let childrenAry = children; childrenAry = childrenAry instanceof Array ? childrenAry : (childrenAry ? [childrenAry] : []); childrenAry.forEach(item => { // 如果子节点直接是字符串,进入这个分支 if (typeof item === 'string') { // =>字符串:文本节点,直接增加到元素中 newElement.appendChild(document.createTextNode(item)); } else { // 如果是标签节点比如<span><img />这些都进入这个分支 // =>字符串:新的JSX元素,递归调用RENDER,只不过此时的容器是当前新创建的newElement render(item, newElement); } }); } console.log(newElement); container.appendChild(newElement); callback && callback(); }
安装transform-react-jsx来实现 jsx 和 js 之间的转换
npm install [email protected] @babel/core @babel/preset-env webpack // 首先安装好 babel 环境 npm install --save-dev babel-plugin-transform-react-jsx //再安装 transform-react-jsx 插件
配置对应的 webpack 参数,如果这里把注释的那条 plugins 打开,那就不需要写另外配置 .babelrc 文件,这里默认会先使用 plugins 的配置的
const path = require('path'); const config = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [{ test: /\.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { // "plugins": ["transform-react-jsx"]// 如果需要配置参数注释这条,在 .babelrc上面配置 } } }] } }; module.exports = config;
配置 .babelrc 文件,如果需要对应的自定义的函数名,可以设置 pragma 的参数,不设置默认返回 React.createElement
React.createElement
{ "plugins": [ ["transform-react-jsx", { "pragma": "pig.yao" // default pragma is React.createElement }] ] }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
VDOM
VDOM,也叫虚拟 DOM,它是仅存于内存中的 DOM,因为还未展示到页面中,所以称为 VDOM
上面这一句就是最简单的虚拟 DOM
上面这两句就是把虚拟 DOM 转化为 真实 DOM,其实就是把节点 append 到页面中
常见DOM操作
常见DOM操作,就三类:增、删、改。对应的DOM操作如下:
以前我们写代码经常会拼接完模板,简单粗暴的用
$(el).html(template)
整块节点替换这样做最大的问题在于性能,如果页面比较小,问题不大,但如果页面庞大,这样会出现卡顿,用户体验会很差,所以解决办法就是差量更新
差量更新
差量更新就是只对局面的 HTML 片段进行更新。比如你加了一个节点,那么我就只更新这个节点,我无需整个模板替换。这样做效率就会提高。但问题在于,不知道哪个节点更新了,哪个节点删除了,哪个节点替换了,所以我们需要对 DOM 建模
如果我们可以用一个JS对象来表示 VDOM,那么这个对象上多一个属性(增加节点),少一个属性(删除节点),或者属性值变了(更改节点),就很清醒了
DOM 也叫 DOM 树,是一个树形结构,DOM 树上有很多元素节点,要对 VDOM 进行建模,本质上就是对一个个元素节点进行建模,然后再把节点放回 DOM 树的指定位置
JSX建模
每个节点都是由以下三部分组成
上面 VDOM 建模是用下面的 HTML 结构转出来的
但这段代码并不是合法的 js 代码,它是一种被称为 jsx 的语法扩展,通过它我们就可以很方便的在 js 代码中书写 html 片段
本质上,jsx 是语法糖,上面这段代码会被 babel 转换成如下代码
而上面的这段被转化的代码是 将我们的 VDOM 配合
pig
(一般应该是createElement
函数)转化为真实 DOM注意,如果是自定义组件
<App />
会转化为pig(App, null)
,因为组件是class App extends React.Component {}
这样定义的,所以App进入createElement
函数里面就会变成是一个对象这里我们可以把这个函数放进
createElement()
里面生成一个 VDOM 对象,然后用生成的 VDOM 对象,配合render()
生成一个 DOM 插入页面,从而转变成真实 DOM 结构createElement()
补充
createElement()
方法的源代码render()
补充
render()
方法的源代码transform-react-jsx
安装transform-react-jsx来实现 jsx 和 js 之间的转换
配置对应的 webpack 参数,如果这里把注释的那条 plugins 打开,那就不需要写另外配置 .babelrc 文件,这里默认会先使用 plugins 的配置的
配置 .babelrc 文件,如果需要对应的自定义的函数名,可以设置 pragma 的参数,不设置默认返回
React.createElement
源码
参考文章
The text was updated successfully, but these errors were encountered: