>[success] # 简单的了解虚拟DOM
1. vue 无论是模板通语法将模板转换为`render`,或者直接使用`render`的形式也罢,其实都是为接下来转换**虚拟DOM**做准备
2. 由普通的 JS 对象来描述 DOM 对象,因为不是真实的 DOM 对象,所以叫 `Virtual DOM`(虚拟DOM),虚拟DOM 节点叫`VNode`(虚拟节点)
>[danger] ##### 打印真实dom
1. 既然有了虚拟dom,那么真实dom是什么?把下面的代码在浏览器中运行
~~~
let div = document.createElement('div')
let str = ''
for (const key in div) {
str += key + ''
}
console.log(str)
~~~
2. 上面代码运行后,可以发现输出了**很多的属性**,可以发现一个真正的 **DOM 元素是非常庞大**,这些对象属性并不是**实际开发过程都会用上**的如果有一个用js表现的dom的结构,再将这个结构渲染会成为dom可以让开发阶段更关心数据
>[info] ## 虚拟dom
1. 手动操作DOM时代 ,即使有了jq帮助我们对dom做了简化的操作,但随着项目的复杂DOM操作也变得复杂起来
2. 后来也出现了一种产物模板方式进行dom操作,就例如**art-template**,但依旧不能解决跟踪状态变化
3. 随着vue 这类数据发生变化视图就要随之更新,在更新视图的时候难免要操作DOM,而操作真实DOM又是**非常耗费性能**
4. 想跟踪变化,就需要进行比较,比较后知道哪里改变了,去改变对应位置思路就诞生了,**如果说维护两个dom**,每次两个dom进行比较,这原本一个dom就相对比较浪费,现在又用两个,这个肯定不行,如果我们用**js形式记录两个数组**,每次比较两个数组那个位置变化了,再去操作对应变化的局部的dom是不是会更好(两个dom 比较不好的主要原因通过打印dom 属性看到的数量上,这么多属性每次都要最对比是个开销,并且并不是每个属性都用了)
5. **Virtual DOM**(虚拟dom) 的好处是当状态改变时**不需要立即更新 DOM**,只需要创建一个虚拟树来描述DOM, Virtual DOM 内部将弄清楚如何 **有效(diff)** 的更新 DOM
>[danger] ##### 虚拟DOM能带来的
1. 由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,不同的运行环境进行代码转换,所以使它具有了**跨平台的能力**,比如说**SSR(Nuxt.js/Next.js)、原生应用(Weex/React Native)、小程序(mpvue/uni-app)**
2. 优化性能 。DOM 操作是**比较耗时**的,对于**大量、频繁的 DOM 操作**,如果先在 JavaScript 中模拟进行,然后再通过计算比对,找到**真正需要更新的节点**,这样就有可能减少**不必要**的 DOM 操作,从而提升渲染性能。但并不是所有的 DOM 操作**都能通过虚拟 DOM 提升性能**,比如**单次删除某个节点**,直接操作 DOM肯定比虚拟 DOM 计算比对之后再删除要快。总体而言,** 虚拟 DOM 提升了 DOM 操作的性能下限,降低了DOM 操作的性能上限**。 所以会看到一些对渲染性能要求比较高的场景,比如**在线文档、表格编辑,还是会使用原生 DOM 操作**。
3. JavaScript 对象来表示 DOM 元素的方式,该对象仅包括常用的这些属性方法和节点关系,这样就可以大大降低对象内存、虚拟 DOM 差异对比的计算量等
>[danger] ##### vnode
1. **VNode是javascript对象**,VNode表示**Virtual DOM**(虚拟DOM)中的**虚拟节点**
* js表现形式
~~~
{
sel: "div",
data: {},
children: undefined,
text: "Hello Virtual DOM",
elm: undefined,
key: undefined
}
~~~
>[info] ## 总结
1. 要分清虚拟dom 和直接操作dom本质上的区别,在jq的时代需要开发既要**关心数据**,又要对对应的**dom进行操作**,例如新增数据的时候需要开发对所在**新增数据dom区域进行新增数据的dom创建并且插入**。那是否可以让jq也变成只关心数据dom直接改变?
* 这里提出一个假设将对应的数据要渲染的**js模板**写好,当数据变化的时候整个该数据地方的dom全部重新渲染。这样我们就**可以不再关心模板只要关心数据**,但相对的问题我们需要将数据重新大批量重新加载这些中有些数据其实**没有变化应该不用刷新**,当然如果我们把这类情况考虑好自然就解决了这类问题
* 用js数据格式表现的数据结构成**为虚拟dom**,每次数据改变生成的新虚拟dom 结构和老的虚拟dom 结构进行比较哪里不一样重新渲染哪里(**这是理想状态下**)当然虚拟dom 开销也不能忽略
~~~
let heroes = [
{ name: "剑圣", age: 80, offsetTop: 0, elmHeight: 20 },
{ name: "盲僧", age: 30, offsetTop: 0, elmHeight: 20 },
{ name: "暗夜猎手", age: 50, offsetTop: 0, elmHeight: 20 },
{ name: "寒冰射手", age: 20, offsetTop: 0, elmHeight: 20 },
{ name: "赏金猎人", age: 40, offsetTop: 0, elmHeight: 20 }
];
function render() {
let html = "";
heroes.forEach(hero => {
html += `
<li class="hero" style="opacity: 0; transform: translateX(0px) translateY(${
hero.offsetTop
}px)">
<div>
<span class="left">姓名:${hero.name}</span>
<span class="left l30">年龄:${hero.age}</span>
<span class="right close">x</span>
</div>
</li>
`;
});
$(".content > ul").html(html);
$(".content > ul > li").each((index, li) => {
heroes[index].elmHeight = $(li).height();
});
heroes = heroes.reduce((arr, hero) => {
let last = arr[arr.length - 1];
hero.offsetTop = last ? last.elmHeight + last.offsetTop + 10 : 10;
return arr.concat(hero);
}, []);
~~~
[jq案例链接](https://codesandbox.io/s/jq-demo-5i7qp?file=/src/index.js:25-1034)
[虚拟dom链接](https://codesandbox.io/s/snabbdom-demo-forked-8lsvb?file=/src/index.js:769-944)
>[danger] ##### 文章参考来源
[本段内容来自拉勾前端高手进阶](https://kaiwu.lagou.com/course/courseInfo.htm?courseId=180#/detail/pc?id=3190)
[参考内容来源](https://github.com/lagoufed/vuejs-enhancement)
- 工程化 -- Node
- vscode -- 插件
- vscode -- 代码片段
- 前端学会调试
- 谷歌浏览器调试技巧
- 权限验证
- 包管理工具 -- npm
- 常见的 npm ci 指令
- npm -- npm install安装包
- npm -- package.json
- npm -- 查看包版本信息
- npm - package-lock.json
- npm -- node_modules 层级
- npm -- 依赖包规则
- npm -- install 安装流程
- npx
- npm -- 发布自己的包
- 包管理工具 -- pnpm
- 模拟数据 -- Mock
- 页面渲染
- 渲染分析
- core.js && babel
- core.js -- 到底是什么
- 编译器那些术语
- 词法解析 -- tokenize
- 语法解析 -- ast
- 遍历节点 -- traverser
- 转换阶段、生成阶段略
- babel
- babel -- 初步上手之了解
- babel -- 初步上手之各种配置(preset-env)
- babel -- 初步上手之各种配置@babel/helpers
- babel -- 初步上手之各种配置@babel/runtime
- babel -- 初步上手之各种配置@babel/plugin-transform-runtime
- babel -- 初步上手之各种配置(babel-polyfills )(未来)
- babel -- 初步上手之各种配置 polyfill-service
- babel -- 初步上手之各种配置(@babel/polyfill )(过去式)
- babel -- 总结
- 各种工具
- 前端 -- 工程化
- 了解 -- Yeoman
- 使用 -- Yeoman
- 了解 -- Plop
- node cli -- 开发自己的脚手架工具
- 自动化构建工具
- Gulp
- 模块化打包工具为什么出现
- 模块化打包工具(新) -- webpack
- 简单使用 -- webpack
- 了解配置 -- webpack.config.js
- webpack -- loader 浅解
- loader -- 配置css模块解析
- loader -- 图片和字体(4.x)
- loader -- 图片和字体(5.x)
- loader -- 图片优化loader
- loader -- 配置解析js/ts
- webpack -- plugins 浅解
- eslit
- plugins -- CleanWebpackPlugin(4.x)
- plugins -- CleanWebpackPlugin(5.x)
- plugin -- HtmlWebpackPlugin
- plugin -- DefinePlugin 注入全局成员
- webapck -- 模块解析配置
- webpack -- 文件指纹了解
- webpack -- 开发环境运行构建
- webpack -- 项目环境划分
- 模块化打包工具 -- webpack
- webpack -- 打包文件是个啥
- webpack -- 基础配置项用法
- webpack4.x系列学习
- webpack -- 常见loader加载器
- webpack -- 移动端px转rem处理
- 开发一个自己loader
- webpack -- plugin插件
- webpack -- 文件指纹
- webpack -- 压缩css和html构建
- webpack -- 清里构建包
- webpack -- 复制静态文件
- webpack -- 自定义插件
- wepack -- 关于静态资源内联
- webpack -- source map 对照包
- webpack -- 环境划分构建
- webpack -- 项目构建控制台输出
- webpack -- 项目分析
- webpack -- 编译提速优护体积
- 提速 -- 编译阶段
- webpack -- 项目优化
- webpack -- DefinePlugin 注入全局成员
- webpack -- 代码分割
- webpack -- 页面资源提取
- webpack -- import按需引入
- webpack -- 摇树
- webpack -- 多页面打包
- webpack -- eslint
- webpack -- srr打包后续看
- webpack -- 构建一个自己的配置后续看
- webpack -- 打包组件和基础库
- webpack -- 源码
- webpack -- 启动都做了什么
- webpack -- cli做了什么
- webpack - 5
- 模块化打包工具 -- Rollup
- 工程化搭建代码规范
- 规范化标准--Eslint
- eslint -- 扩展配置
- eslint -- 指令
- eslint -- vscode
- eslint -- 原理
- Prettier -- 格式化代码工具
- EditorConfig -- 编辑器编码风格
- 检查提交代码是否符合检查配置
- 整体流程总结
- 微前端
- single-spa
- 简单上手 -- single-spa
- 快速理解systemjs
- single-sap 不使用systemjs
- monorepo -- 工程
- Vue -- 响应式了解
- Vue2.x -- 源码分析
- 发布订阅和观察者模式
- 简单 -- 了解响应式模型(一)
- 简单 -- 了解响应式模型(二)
- 简单 --了解虚拟DOM(一)
- 简单 --了解虚拟DOM(二)
- 简单 --了解diff算法
- 简单 --了解nextick
- Snabbdom -- 理解虚拟dom和diff算法
- Snabbdom -- h函数
- Snabbdom - Vnode 函数
- Snabbdom -- init 函数
- Snabbdom -- patch 函数
- 手写 -- 虚拟dom渲染
- Vue -- minVue
- vue3.x -- 源码分析
- 分析 -- reactivity
- 好文
- grpc -- 浏览器使用gRPC
- grcp-web -- 案例
- 待续