Snabbdom 虚拟 dom(一)
为什么使用虚拟 Dom
提升页面性能,用最少的操作来达到最大的性能
虚拟 DOM 作用
- 维护视图和状态的关系
- 复杂视图情况下提升渲染性能
- 跨平台
- 浏览器平台渲染DOM
- 服务端渲染 SSR(Nuxt.js/Next.js)
- 原生应用(Weex/React Native)
- 小程序(mpvue/uni-app)等
Snabbdom 虚拟 DOM 库
因为 Vue 2.x 内部使用的虚拟 DOM 就是结合的 Snabbdom,然后大约 200 行代码,研究这个比直接去看 Vue 源码要轻松
创建项目准备工作
新建目录 snabbdom-demo
初始化 package.json
npm init -y
本地安装 parcel
npm i parcel-bundler -D
配置 scripts 启动命令
"scripts": {
"dev": "parcel index.html --open",
"build": "parcel build index.html"
}
在根目录下新建 index.html,并在 src 下面新建一个 01-demo.js 文件,首页引入这个 js 文件
// 首页代码
<div id="app"></div>
<script src="./src/01-basicusage.js"></script>
导入 Snabbdom
中文文档
安装 snabbdom
npm i snabbdom@2.1.0
例子1
了解 init h patch 模块的基本使用
import { init } from 'snabbdom/build/package/init'
import { h } from 'snabbdom/build/package/h'
const patch = init([])
// 第一个参数 标签 + 选择器
// 第二个参数 如果是字符串就是标签中的文本内容
let vnode = h('div#container.cls', 'hello')
let app = document.querySelector('#app')
// 第一个参数 旧的 VNode,可以是 DOM 元素
// 第二个参数 新的 VNode
// 返回新的 VNode
let oldVnode = patch(app, vnode)
vnode = h('div#container.xxx', 'hai')
patch(oldVnode, vnode)
创建子元素
const patch = init([])
// 多个子元素
let vnode = h('div#container', [h('h1', 'hello zhang'), h('p', '这是一个p')])
let app = document.querySelector('#app')
let oldVnode = patch(app, vnode)
// // 清除 div 中的 内容
patch(oldVnode, h('!'))
snabbdom 模块作用
- Snabbdom 的核心库并不能处理 DOM 元素的属性/样式/事件等, 可以通过注册 Snabbdom 默认提供的模块来实现
- Snabbdom 中的模块可以用来扩展 Snabbdom的功能
- Snabbdom 中的模块的实现是通过注册全局的钩子函数来实现的
官方提供的模块
- attributes
- props
- dataset
- class
- style
- eventlisteners
举个例子
import { init } from 'snabbdom/build/package/init'
import { h } from 'snabbdom/build/package/h'
// 1.导入模块
import { styleModule } from 'snabbdom/build/package/modules/style'
import { eventListenersModule } from 'snabbdom/build/package/modules/eventlisteners'
// 2.注册模块
const patch = init([styleModule, eventListenersModule])
// 3.使用 h() 函数的第二个参数传入模块中使用的数据(对象)
let vnode = h('div', [h('h1', { style: { backgroundColor: 'red' } }, 'hello red'), h('p', { on: { click: eventHandler } }, 'hello p')])
function eventHandler() {
console.log('点击')
}
let app = document.querySelector('#app')
patch(app, vnode)