1. 创建项目
-
打包工具为了方便使用 parcel
-
创建项目,并安装 parcel
# 创建项目目录 md snabbdom-demo # 进入项目目录 cd snabbdom-demo # 创建 package.json npm init -y # 本地安装 parcel npm install parcel-bundler -D
-
配置
package.json
的scripts
"scripts": { "dev": "parcel index.html --open", "build": "parcel build index.html" }
-
创建目录结构
│ index.html │ package.json └─src 01-basicusage.js
2. 安装 Snabbdom
npm install snabbdom@2.1.0
3. 导入 Snabbdom
Snabbdom
的两个核心函数 init
和 h()
-
init()
是一个高阶函数,返回patch()
-
h()
返回虚拟节点VNode
,这个函数我们在使用Vue.js
的时候见过
import { init } from 'snabbdom/init'
import { h } from 'snabbdom/h'
const patch = init([])
注意:此时运行的话会告诉我们找不到
init / h
模块,因为模块路径并不是snabbdom/int
,这个路径是在package.json
中的exports
字段设置的,而我们使用的打包工具不支持exports
这个字段,webpack 4
也不支持,webpack 5
支持该字段。该字段在导入snabbdom/init
的时候会补全路径成snabbdom/build/package/init.js
"exports": {
"./init": "./build/package/init.js",
"./h": "./build/package/h.js",
"./helpers/attachto": "./build/package/helpers/attachto.js",
"./hooks": "./build/package/hooks.js",
"./htmldomapi": "./build/package/htmldomapi.js",
"./is": "./build/package/is.js",
"./jsx": "./build/package/jsx.js",
"./modules/attributes": "./build/package/modules/attributes.js",
"./modules/class": "./build/package/modules/class.js",
"./modules/dataset": "./build/package/modules/dataset.js",
"./modules/eventlisteners": "./build/package/modules/eventlisteners.js",
"./modules/hero": "./build/package/modules/hero.js",
"./modules/module": "./build/package/modules/module.js",
"./modules/props": "./build/package/modules/props.js",
"./modules/style": "./build/package/modules/style.js",
"./thunk": "./build/package/thunk.js",
"./tovnode": "./build/package/tovnode.js",
"./vnode": "./build/package/vnode.js"
}
如果使用不支持 package.json
的 exports
字段的打包工具,我们应该把模块的路径写全
import { h } from 'snabbdom/build/package/h'
import { init } from 'snabbdom/build/package/init'
import { classModule } from 'snabbdom/build/package/modules/class'
- 回顾
Vue
中的render
函数
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
-
thunk()
是一种优化策略,可以在处理不可变数据时使用
4. 代码演示
4.1 基本使用
import { h } from 'snabbdom/build/package/h'
import { init } from 'snabbdom/build/package/init'
// 使用 init() 函数创建 patch()
// init() 的参数是数组,将来可以传入模块,处理属性/样式/事件等
let patch = init([])
// 使用 h() 函数创建 vnode
// 第一个参数:标签+选择器
// 第二个参数:如果时字符串就是标签中的文本内容
let vnode = h('div.cls', [
h('h1', 'Hello Snabbdom')
])
const app = document.querySelector('#app')
/*
把 vnode 渲染到空的 DOM 元素(替换)
第一个参数:旧的 VNODE,可以是 DOM 元素
第二个参数:新的 VNODE
会返回新的 vnode
*/
let oldVnode = patch(app, vnode)
setTimeout(() => {
vnode = h('div.cls', [
h('p', '这是段落')
])
// 把老的视图更新到新的状态
oldVnode = patch(oldVnode, vnode)
/*
清除 div中的内容
h('!') 是创建空的注释节点
*/
patch(oldVnode, h('!'))
}, 2000)
5. 模块
Snabbdom
的核心库并不能处理 DOM
元素的属性/样式/事件等,如果需要处理的话,可以使用模块
5.1 常用模块
-
官方提供了 6 个模块
-
attributes
- 设置
DOM
元素的属性,使用setAttribute
() - 处理布尔类型的属性
- 设置
-
props
- 和
attributes
模块相似,设置DOM
元素的属性element[attr] = value
- 不处理布尔类型的属性
- 和
-
class
- 切换类样式
- 注意:给元素设置类样式是通过
sel
选择器
-
dataset
- 设置
data-*
的自定义属性
- 设置
-
eventlisteners
- 注册和移除事件
-
style
- 设置行内样式,支持动画
delayed/remove/destroy
-
5.2 模块使用
模块使用步骤:
- 导入需要的模块
-
init()
中注册模块 - 使用
h()
函数创建VNode
的时候,可以把第二个参数设置为对象,其他参数往后移
5.3 代码演示
import { h } from 'snabbdom/build/package/h'
import { init } from 'snabbdom/build/package/init'
// 导入需要的模块
import { styleModule } from 'snabbdom/build/package/modules/style'
import { eventListenersModule } from 'snabbdom/build/package/modules/eventlisteners'
// 使用 init() 函数创建 patch()
// init() 的参数是数组,将来可以传入模块,处理属性/样式/事件等
let patch = init([
// 注册模块
styleModule,
eventListenersModule
])
// 使用 h() 函数创建 vnode
// 第一种写法
let vnode = h('div.cls', [
h('h1', { style: { color: '#DEDEDE', backgroundColor: '#181A1B' }} ,'Hello Snabbdom'),
h('p', { on: { click: clickHandler }} ,'这是段落')
])
/*
// 第二种写法
let vnode = h('div.cls', {
// 设置 DOM 元素的行内样式
style: { color: '#DEDEDE', backgroundColor: '#181A1B' },
// 注册事件
on: { click: clickHandler }
}, [
h('h1', 'Hello Snabbdom'),
h('p', '这是段落')
])
*/
function clickHandler () {
// 此处的 this 指向对应的 vnode
console.log(this.elm.innerHTML)
}
网友评论