Vue源码解析

【尚硅谷】Vue源码解析之虚拟DOM和diff算法

【Vue源码】图解 diff算法 与 虚拟DOM-snabbdom-最小量更新原理解析-手写源码-updateChildren]

文章目录

    • 2. snabbdom 简介 及 准备工作
      • 2.1 简介
      • 2.2 搭建初始环境
        • 1. 安装snabbdom
        • 2. 安装webpack5并配置
        • 3. 复制官方demo Example
    • 3. h函数的介绍与使用
      • 3.1 介绍
      • 3.2 使用h函数 创建虚拟节点
      • 3.3 使用patch函数 将虚拟节点上DOM树
      • 3.4 h函数嵌套使用,得到虚拟DOM树(重要)

2. snabbdom 简介 及 准备工作

2.1 简介

snabbdom(瑞典语,“速度”)是著名的虚拟DOM库,是diff算法的鼻祖
Vue源码借鉴了snabbdom
源码使用TypeScript写的https://github.com/snabbdom/snabbdom
从npm下载的是build出来的JavaScript版本
-D 是开发dev版本的依赖 -S是项目真正依赖

2.2 搭建初始环境

1. 安装snabbdom

npm init
npm install -D snabbdom

下载好的源码在node_modules
Vue源码解析_第1张图片
需要读取一些init等文件,使用webpack5,不能是webpack4(读取的地址不对)。接下来安装webpack5

2. 安装webpack5并配置

cnpm i -D webpack@5 webpack-cli@3 webpack-dev-server@3

配置webpack5
根目录下创建webpack.config.js

cnpm i -D webpack@5 webpack-cli@3 webpack-dev-server@3

“dev”: “webpack-dev-server” npm run dev实际跑的是npm run webpack-dev-server会读取webpack.config.js文件
Vue源码解析_第2张图片
webpack.config.js配置文件


module.exports = {
    // webpack5 不用配置mode
    // 入口
    entry: "./src/index.js",
    // 出口
    output: {
      // 虚拟打包路径,文件夹不会真正生成,而是在8080端口虚拟生成
      publicPath: "xuni",
      // 打包出来的文件名
      filename: "bundle.js",
    },
    // 配置webpack-dev-server
    devServer: {
      // 静态根目录
      contentBase: 'www',
      // 端口号
      port: 8080,
    },
  };
  

3. 复制官方demo Example

src/index.js

import {
  init,
  classModule,
  propsModule,
  styleModule,
  eventListenersModule,
  h,
} from "snabbdom";

const patch = init([
  // Init patch function with chosen modules
  classModule, // makes it easy to toggle classes
  propsModule, // for setting properties on DOM elements
  styleModule, // handles styling on elements with support for animations
  eventListenersModule, // attaches event listeners
]);

const container = document.getElementById("container");

const vnode = h("div#container.two.classes", { on: { click: function () { } } }, [
  h("span", { style: { fontWeight: "bold" } }, "This is bold"),
  " and this is just normal text",
  h("a", { props: { href: "/foo" } }, "I'll take you places!"),
]);
// Patch into empty DOM element – this modifies the DOM as a side effect
patch(container, vnode);

const newVnode = h(
  "div#container.two.classes",
  { on: { click: function () { } } },
  [
    h(
      "span",
      { style: { fontWeight: "normal", fontStyle: "italic" } },
      "This is now italic type"
    ),
    " and this is still just normal text",
    h("a", { props: { href: "/bar" } }, "I'll take you places!"),
  ]
);
// Second `patch` invocation
patch(vnode, newVnode); // Snabbdom efficiently updates the old view to the new state

根目录创建www文件夹,内部有index.html(默认访问该文件)

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    <div id="container">div>
    <script src="/xuni/bundle.js">script>
body>
html>

npm run dev跑起来
Vue源码解析_第3张图片

Vue源码解析_第4张图片
Vue源码解析_第5张图片

3. h函数的介绍与使用

3.1 介绍

diff算法发生在 虚拟DOM上,新旧虚拟DOM的比较
h 函数产生虚拟节点
Vue源码解析_第6张图片
Vue源码解析_第7张图片
虚拟节点vnode的属性

{
	children: undefined// 子元素 数组
	data: {} // 属性、样式、key
	elm: undefined // 对应的真正的dom节点(对象),undefined表示节点还没有上dom树
	key: // 唯一标识
	sel: "" // 选择器
	text: "" // 文本内容
}

3.2 使用h函数 创建虚拟节点

3.3 使用patch函数 将虚拟节点上DOM树

src/index.js

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";
  

  
var myVnode1 = h('a', {
    props: {
        href: "http://www.baidu.com",
        target: '_blank',
      }
}, '百度')
// const myVnode2 = h('div', '我是盒子' )
const myVnode3 = h('div', {class:{'box': true}},  '我是盒子')

console.log(myVnode1)
//   将虚拟节点渲染成真实节点 需要使用patch函数
const patch = init([
    // Init patch function with chosen modules
    classModule, // makes it easy to toggle classes
    propsModule, // for setting properties on DOM elements
    styleModule, // handles styling on elements with support for animations
    eventListenersModule, // attaches event listeners
  ]);
  
const container = document.getElementById("container");
patch(container, myVnode1)

Vue源码解析_第8张图片
console.log(myVnode1)的输出
Vue源码解析_第9张图片

3.4 h函数嵌套使用,得到虚拟DOM树(重要)

Vue源码解析_第10张图片

const myVnode4 = h('ul', [
    h('li', '苹果1'),
    h('li', '苹果2'),
    h('li', '苹果3'),
    h('li', '苹果4'),
])
console.log(myVnode1)
//   将虚拟节点渲染成真实节点 需要使用patch函数
const patch = init([
    // Init patch function with chosen modules
    classModule, // makes it easy to toggle classes
    propsModule, // for setting properties on DOM elements
    styleModule, // handles styling on elements with support for animations
    eventListenersModule, // attaches event listeners
  ]);
  
const container = document.getElementById("container");
patch(container, myVnode4)

Vue源码解析_第11张图片

const myVnode4 = h('ul', [
    h('li', '苹果1'),
    h('li', [
        h('div', [
            h('p', "香蕉皮"),
            h('p', "苹果皮")
        ])
    ]),
    h('li', h('span', '西瓜')),
    h('li', '番茄'),
])

Vue源码解析_第12张图片

你可能感兴趣的:(vue,vue.js,javascript,webpack)