什么是虚拟DOM
- Virtual DOM(虚拟DOM),是由普通的 JS 对象来描述 DOM对象。
为什么使用虚拟DOM
虚拟 DOM 的作用
- 维护视图和状态的关系
- 复杂视图情况下提升渲染性能
- 除了渲染 DOM 以外,还可以实现 SSR(Nuxt.js/Next.js) 、原生应用(Weex/React Native)、小程序(mpvue/uni-app)
Virtual DOM 库
- Snabbdom
- Vue 2.x 内部使用的 Virtual DOM 就是改造的 Snabbdom
- 大约 200 SLOC(single line of code)
- 通过模块可扩展
- 源码使用 TypeScript 开发
- 最快的 Virtual DOM 之一
- Virtual DOM
Snabbdom 基本使用
创建项目
- 打包工具用 parcel
- 创建项目,并安装 parcel
- 配置 package.json 的scripts
- 创建目录结构
- 安装 Snabbdom :yarn add snabbdom
导入 Snabbdom
-
Snabbdom 的官网 demo 中导入使用的是 commonjs 模块化语法,我们使用更流行的 ES6 模块化的语法 import
-
关于模块化的语法请参考阮一峰老师的 Module 的语法
-
ES6 模块与 CommonJS 模块的差异
import { init , h , thunk } from 'snabbdom' - Snabbdom 的核心仅提供最基本的功能,只导出了三个函数 init()、h()、thunk()
- init() 是一个高阶函数,返回 patch()
- h() 返回虚拟节点 VNode,这个函数我们在使用 Vue.js 的时候见过
- thunk() 是一种优化策略,可以在处理不可变数据时使用
代码演示 Snabbdom
// var snabbdom = require('snabbdom)
//导入 snabbdom
import { h, init } from 'snabbdom'
//1. hello world
// 参数:数组,模块
// 返回值: patch函数,作用对比两个vnode的差异更新到真实 DOM
let patch= init([])
//第一个参数:标签 + 选择器
//第二个参数:如果是字符串的话就是标签中的内容
let vnode = h('div#container.cls', 'hello world')
let app = document.querySelector("#app")
//第一个参数:可以是DOM元素,内不会吧DOM元素转换成vnode
//第二个参数:vnode
//返回值:vnode
let oldVode = patch(app, vnode)
//假设的时刻
vnode = h('div', 'hello world snabbdom')
path(oldVode, vnode)
模块
- Snabbdom 的核心库并不能处理元素的属性/样式/事件等,如果需要处理的话,可以使用模块
常用模块
- 官方提供了 6 个模块
- attributes
- 设置 DOM 元素的属性,使用 setAttribute ()
- 处理布尔类型的属性
- props
- 和 attributes 模块相似,设置 DOM 元素的属性 element[attr] = value
- 不处理布尔类型的属性
- class
- 切换类样式
- 注意:给元素设置类样式是通过 sel 选择器
- dataset
- 设置 data-* 的自定义属性
- eventlisteners
- 注册和移除事件
- style
- 设置行内样式,支持动画
- delayed/remove/destroy
- attributes
模块使用
- 导入需要的模块
- init() 中注册模块
- 使用 h() 函数创建 VNode 的时候,可以把第二个参数设置为对象,其他参数往后移
代码演示
import { h, init } from 'snabbdom'
//1. 导入模块
import style from 'snabbdom/modules/style'
import eventlisteners from 'snabbdom/modules/eventlisteners'
//2. 注册模块
let patch = init([
style,
eventlisteners
])
//3. 使用 h() 函数的第二个参数传入模块需要的数据(对象)
let vnode = h('div', {
style: {
backgroundColor:'red'
},
on: {
click:eventHandler
}
}, [
h('h1', 'hello snabbdom'),
h('p', '这是p标签')
])
function eventHandler () {
console.log('惦记我了')
}
let app = document.querySelector("#app")
patch(app, vnode)
patch的整体过程