Snabbdom使用及原理

2021-09-15  本文已影响0人  A_走在冷风中

Virtual DOM

课程目标

什么是 Virtual DOM

为什么使用 Virtual DOM

虚拟 DOM 的作用

Virtual DOM 库

案例演示

Snabbdom 基本使用成

创建项目

导入 Snabbdom

Snabbdom 文档

安装 Snabbdom

导入 Snabbdom

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"
  }
import { h } from 'snabbdom/build/package/h'
import { init } from 'snabbdom/build/package/init'
import { classModule } from 'snabbdom/build/package/modules/class'
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

代码演示

基本使用

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'),
  h('p', '这是段落')
])

const app = document.querySelector('#app')
// 把 vnode 渲染到空的 DOM 元素(替换)
// 会返回新的 vnode
let oldVnode = patch(app, vnode)

setTimeout(() => {
  vnode = h('div.cls', [
    h('h1', 'Hello World'),
    h('p', '这是段落')
  ])
  // 把老的视图更新到新的状态
  oldVnode = patch(oldVnode, vnode)
  // h('!') 是创建注释
  patch(oldVnode, h('!'))
}, 2000)

模块

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

常用模块

模块使用

代码演示

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', {
  // 设置 DOM 元素的行内样式
  style: { color: '#DEDEDE', backgroundColor: '#181A1B' },
  // 注册事件
  on: { click: clickHandler }
}, [
  h('h1', 'Hello Snabbdom'),
  h('p', '这是段落')
])

function clickHandler () {
  // 此处的 this 指向对应的 vnode
  console.log(this.elm.innerHTML)
}

Snabbdom 源码解析

概述

如何学习源码

Snabbdom 的核心

Snabbdom 源码

h 函数

VNode

export interface VNode {
  // 选择器
  sel: string | undefined;
  // 节点数据:属性/样式/事件等
  data: VNodeData | undefined;
  // 子节点,和 text 只能互斥
  children: Array<VNode | string> | undefined;
  // 记录 vnode 对应的真实 DOM
  elm: Node | undefined;
  // 节点中的内容,和 children 只能互斥
  text: string | undefined;
  // 优化用
  key: Key | undefined;
}

export function vnode (sel: string | undefined,
                      data: any | undefined,
                      children: Array<VNode | string> | undefined,
                      text: string | undefined,
                      elm: Element | Text | undefined): VNode {
  const key = data === undefined ? undefined : data.key
  return { sel, data, children, text, elm, key }
}

snabbdom

init

patch

createElm

patchVnode

updateChildren

上一篇 下一篇

猜你喜欢

热点阅读