Snabbdom基本使用

Vue

# 创建项目并引入文件

  1. 创建项目,打包使用parcel
npm init -y
npm i parcel-bundle --save-dev
1
2
  1. 设置package.json的scripts
"scripts": {
    "dev": "parcel index.html --open",
    "build": "parcel build index.html"
}
1
2
3
4
  1. 创建src/01.js,创建index.html并引入js文件
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>snabbdom-demo</title>
</head>
<body>
  <div id="app"></div>
  <script src="./src/01.js/"></script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
  1. 安装snabbdomnpm i snabbdom --save-dev
  2. 导入snabbdom模块, 遇到问题参考 snabbdom导入问题 (opens new window)
  • CommonJS方式
const { h } = require('snabbdom/build/package/h')
const { thunk } = require('snabbdom/build/package/thunk')
const { init } = require('snabbdom/build/package/init')
1
2
3
  • ESModules方式
// 导入
import { h } from 'snabbdom/build/package/h'
import { thunk } from 'snabbdom/build/package/thunk'
import { init } from 'snabbdom/build/package/init'

console.log(h)
console.log(thunk)
console.log(init)
1
2
3
4
5
6
7
8

# 函数简单介绍

init()、h()、thunk()这三个函数是sanbbdom的核心,实现最基本的功能。

# 名词解释

VNode:即虚拟DOM,用来描述真实DOM的。

# init函数

高阶函数,返回patch()

  • 参数:一个数组形式的参数,里面可以传入模块
  • 返回值:patch函数
let patch = init([])
1

# patch函数

核心函数

  • 作用:对比两个虚拟DOM(VNode)的差异,将差异更新到真实DOM
  • 参数
    • 第一个参数:可以是VNode,也可以是真实DOM元素,内部会把DOM元素转换成VNode,再与第二个参数进行对比
    • 第二个参数:VNode
  • 返回值:VNode

# h函数

返回虚拟节点VNode,创建render的时候里面有见过

  • 作用:h函数用来返回虚拟DOM
  • 参数
    • 第一个参数表示标签+选择器
    • 第二个参数如果是字符串就是设置标签中的内容
    • 第二个参数如果是数组就插入子节点,每个元素都是一个h函数
    • h中如果传入注释节点形式是:h('!')
// 第二个参数是字符串
let vnode = h('div#container.cls','Hello world')
// 第二个参数是数组
let vnode = h('div#container',[
  h('h1', 'Hello Snabbdom'),
  h('p', '这是一个p标签')
])
1
2
3
4
5
6
7

# thunk函数

一种优化策略,可以在处理不可变数据时使用

# 基本用法

# Hello World

// 01.js
import { h } from 'snabbdom/build/package/h'
import { init } from 'snabbdom/build/package/init'

// 1. hello world
// 先用init方法返回一个patch函数,在用h方法创建一个虚拟DOM
let patch = init([])
// 创建虚拟DOM(用来描述真实DOM的)
let vnode = h('div#container.cls','Hello world')
// 上面只有一个VNode,在index.html中有一个app元素是用来占位的,之后会替换
// 所以先获取app元素
let app = document.querySelector('#app')
// 利用patch更新DOM
let oldVnode = patch(app, vnode)

// 2. 从服务器中获取了新的数据要进行更新
vnode = h('div','Hello Snabbdom')
// 利用patch方法将新的vnode和旧的vnode进行比较
oldVnode = patch(oldVnode,vnode)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

在2执行之前,页面显示Hello world,在执行2之后,页面显示Hello Snabbdom

# 在元素中创建子元素

  1. 创建src/02.js,并在index.html中引用
  2. 在02.js中写
// 导入
import { h } from 'snabbdom/build/package/h'
import { init } from 'snabbdom/build/package/init'
// 通过init初始化一个patch函数
let patch = init([])
// 创建一个div,在里面放子元素
// 第二个元素可以是一个数组,里面包含了子元素的信息
let vnode = h('div#container',[
  h('h1', 'Hello Snabbdom'),
  h('p', '这是一个p标签')
])
// 获取占位dom元素app
let app = document.querySelector('#app')
// 比较元素渲染页面
patch(app, vnode)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  1. 在服务器获取新的信息如何更新?
// 给patch的结果赋值一个旧VNode
let oldVnode = patch(app, vnode)

// 在服务器获取了新的内容,2s后更新页面
setTimeout(() => {
  vnode = h('div#container',[
    h('h1','Hello world'),
    h('p','hello p')
  ])
  patch(oldVnode, vnode)
}, 2000)
1
2
3
4
5
6
7
8
9
10
11

可以看到页面上发生了变化

# 清空页面元素

官方给出的清除方法是patch(oldVnode, null)但是用这种方法会报错,所以可以采用创建注释节点的方式清空页面所有元素

...
patch(oldVnode, h('!'))
1
2

# Snabbdom模块

Snabbdom 的核心库并不能处理元素的属性/样式/事件等,如果需要处理的话,可以使用模块。

# 常用模块

官方提供了 6 个模块

  • attributes

设置 DOM 元素的属性,内部使用的是 setAttribute (),会判断并处理布尔类型的属性,如selected等

  • props

和 attributes 模块相似,设置 DOM 元素的属性,内部使用的时候是element[attr] = value的形式,不处理布尔类型的属性

  • class

切换类样式

注意:给元素设置类样式是通过h函数设置的

  • dataset

设置 data-* 的自定义属性

  • eventlisteners

注册和移除事件

  • style

设置行内样式,支持动画 delayed/remove/destroy,增加了额外的功能,增加了相应的属性。

# 模块使用

  1. 创建src/03.js和修改index.html的引用
  2. 在03.js中导入模块

如果你是0.7.4版本,采用下面的写法

import style from 'snabbdom/modules/style'
import eventlisteners from 'snabbdom/modules/eventlisteners'
1
2

如果是1.0.1之后的版本,现在是2.0.1版本,采用下面的写法

import { styleModule } from 'snabbdom/build/package/modules/style'
import { eventListenersModule } from 'snabbdom/build/package/modules/eventlisteners'
1
2
  1. init() 中注册模块,init中的数组就是用来传入模块的。
let patch = init([
  styleModule,
  eventListenersModule
])
1
2
3
4
  1. 使用 h() 函数创建 VNode 的时候,可以把第二个参数设置为对象,通过对象设置行内样式、事件等等,其他参数往后移。
let vnode = h('div',{
  style: {
    backgroundColor: 'red'
  },
  on: {
    click: eventHandler
  }
},[
  h('h1','Hello snabbdom'),
  h('p','这是一个p标签')
])

// 点击事件
function eventHandler () {
  console.log('click me~')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  1. 获取app真实DOM,并比较渲染到页面上
let app = document.querySelector('#app')

patch(app, vnode)
1
2
3

可以看到页面上有了背景为红色的内容。

image

更新时间: 2022-01-10 09:52