虚拟DOM
通过普通的JS对象来描述DOM对象 ,解决重绘和重排性能开销问题。
作用:维护视图和状态的关系;复杂视图情况下提升渲染性能;首次渲染会增加开销
使用虚拟DOM
- 安装Parcel
npm i parcel-bundler -D
- 安装引入snabbdom
npm i snabbdom
- 引入snabbdom中的init 和 h 模块
//通过h函数创建 VNode。h函数第一个参数:标签+选择器;第二个参数:如果是字符串就是标签中的内容
let vNode = h('div#box.container','默认内容')
// 获取挂载元素
const dom = document.querySelector('#app')
// 通过init 函数得到patch函数,patch函数第一个参数:旧的VNode,可以是DOM元素,第二个参数是新的VNode,返回新的Vnode
const patch = init([])
// 通过patch,将vNode渲染到Dom
let oldvNode = patch(dom, vNode)
// 创建新的vNode,更新给oldVnode
vNode = h('div#vNode','这是p标签的内容')// 包含单个节点的vNode
vNode1 = h('div#vNodes', [
h('h1','标题内容')
h('p','文本内容')
])
patch(oldvNode, vNode) //挂载单标签元素
patch(oldvNode, vNode1) //挂载含子节点的元素
patch(oldvNode, h('!')) //代表注释节点,清空所有内容
模块使用
Snabbdom核心库不能操作DOM元素的样式、事件、和属性,可以通过默认提供的模块实现。模块实现通过注册全局的钩子函数实现。
官方提供模块
- attributes 可以处理布尔值;设置vnode的DOM属性使用setAttribute实现
- props 不可处理布尔值;设置DOOM对象的属性,通过
对象.属性
方式实现 - dataset 处理data-的属性
- class 类模块处理,切换类样式
- style 行内样式设置,可设置过渡动画
- eventlisteners 监听器模块,注册和移除事件
模块操作步骤
- 导入模块(引入的名称必须与导出时一致)
- init()注册模块,参数是数组,将注册的模块放入到数组中
- h()第二个参数使用模块
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 注册模块(为 patch 函数添加模块对应的能力)
const patch = init([
styleModule,
eventListenersModule
])
// 3 使用模块
let vNode = h('div#box', {
style: {
backgroundColor: 'green',
height: '200px',
width: '200px' //样式必须添加单位
}
}, [
h('h1#title', {
style: {
color: '#fff'
},
on: {
click () {
console.log('点击了 h1 标签')
}
}
}, '这是标题内容'),
h('p', '这是内容文本')
])
const dom = document.getElementById('app')
patch(dom, vNode)
h函数:创建节点并可设置子元素
由vm.$createElement(tag,data,children,normalizeChildren)
实现。使用typescript中的函数重载,给不同的数量和类型的参数设置不同的实现。h('标签+选择器','text')
第二个参数如果是字符串就是标签中的内容。如果是包含子元素则为数组。返回VNode对象
let vnode = h('div#container',[h('h1','Hello'),h('p','这是一个p标签')])
patch(vnode,h('!')) //h('!')设置为空的注释节点
VNode函数
作用:渲染节点
patch函数
作用:新旧节点比对,页面虚拟节点设置
语法:patch(oldVnode,newVnode)
- 将新节点中变化的内容渲染到真实DOM,最后返回新节点作为下一次处理的旧节点
- 对比新旧VNode是否相同节点(节点的key和sel相同)如果不是相同节点删除之前的内容重新渲染;如果是相同节点在判断新的VNode是否有text如果有并且和oldVnode的text不同,直接更新文本内容
- 如果新的VNode有children判断子节点是否有变化