• vue源码分析参考---1、准备工作


    vue源码分析参考---1、准备工作

    一、总结

    一句话总结:

    可以直接剖析 github 上某基友仿 vue 实现的 mvvm 库(https://github.com/DMQ/mvvm),用这个分析vue的原理更加简单,弄懂这个再去看vue源码会很简单

    1、分析vue源码 策略?

    可以直接剖析 github 上某基友仿 vue 实现的 mvvm 库(https://github.com/DMQ/mvvm),用这个分析vue的原理更加简单,弄懂这个再去看vue源码会很简单

    2、[].slice.call(lis)?

    将伪数组转换为真数组
      //1. [].slice.call(lis): 根据伪数组生成对应的真数组
      const lis = document.getElementsByTagName('li') // lis是伪数组(是一个特别的对象, length和数值下标属性)
      console.log(lis instanceof Object, lis instanceof Array)
      // 数组的slice()截取数组中指定部分的元素, 生成一个新的数组  [1, 3, 5, 7, 9], slice(0, 3)
      // slice2()
      Array.prototype.slice2 = function (start, end) {
        start = start || 0
        end = start || this.length
        const arr = []
        for (var i = start; i < end; i++) {
          arr.push(this[i])
        }
        return arr
      }
      const lis2 = Array.prototype.slice.call(lis)  // lis.slice()
      console.log(lis2 instanceof Object, lis2 instanceof Array)
      // lis2.forEach()

    3、node.nodeType?

    得到节点类型
      //2. node.nodeType: 得到节点类型
      const elementNode = document.getElementById('test')
      const attrNode = elementNode.getAttributeNode('id')
      const textNode = elementNode.firstChild
      console.log(elementNode.nodeType, attrNode.nodeType, textNode.nodeType)

    4、Object.defineProperty(obj, propName, {})?

    给对象添加/修改属性(指定描述符) configurable: true/false  是否可以重新 define
    enumerable: true/false 是否可以枚举(for..in / keys())
    value: 指定初始值
    writable: true/false value 是否可以修改
    get: 回调函数, 用来得到当前属性值
    set: 回调函数, 用来监视当前属性值的变化
    
    
      //3. Object.defineProperty(obj, propertyName, {}): 给对象添加属性(指定描述符)
      const obj = {
        firstName: 'A',
        lastName: 'B'
      }
      //obj.fullName = 'A-B'
      Object.defineProperty(obj, 'fullName', {
        // 属性描述符:
    
        // 数据描述符
    
        //访问描述符
        // 当读取对象此属性值时自动调用, 将函数返回的值作为属性值, this为obj
        get () {
          return this.firstName + "-" + this.lastName
        },
        // 当修改了对象的当前属性值时自动调用, 监视当前属性值的变化, 修改相关的属性, this为obj
        set (value) {
          const names = value.split('-')
          this.firstName = names[0]
          this.lastName = names[1]
        }
      })
    
      console.log(obj.fullName) // A-B
      obj.fullName = 'C-D'
      console.log(obj.firstName, obj.lastName) // C D
    
      Object.defineProperty(obj, 'fullName2', {
        configurable: false, //是否可以重新define
        enumerable: true, // 是否可以枚举(for..in / keys())
        value: 'A-B', // 指定初始值
        writable: false // value是否可以修改
      })
      console.log(obj.fullName2)  // A-B
      obj.fullName2 = 'E-F'
      console.log(obj.fullName2) // A-B
    
      /*Object.defineProperty(obj, 'fullName2', {
        configurable: true,
        enumerable: true,
        value: 'G-H',
        writable: true
      })*/

    5、Object.keys(obj)?

    得到对象自身可枚举的属性名的数组
      //4. Object.keys(obj): 得到对象自身可枚举属性组成的数组
      const names = Object.keys(obj)
      console.log(names)

    6、obj.hasOwnProperty(prop)?

    判断 prop 是否是 obj 自身的属性
      //5. obj.hasOwnProperty(prop): 判断prop是否是obj自身的属性
      console.log(obj.hasOwnProperty('fullName'), obj.hasOwnProperty('toString'))  // true false

    7、DocumentFragment?

    文档碎片(高效批量更新多个节点)
      //6. DocumentFragment: 文档碎片(高效批量更新多个节点)
      // document: 对应显示的页面, 包含n个elment  一旦更新document内部的某个元素界面更新
      // documentFragment: 内存中保存n个element的容器对象(不与界面关联), 如果更新framgnet中的某个element, 界面不变
      /*
      <ul id="fragment_test">
        <li>test1</li>
        <li>test2</li>
        <li>test3</li>
      </ul>
       */
      const ul = document.getElementById('fragment_test')
      // 1. 创建fragment
      const fragment = document.createDocumentFragment()
      // 2. 取出ul中所有子节点取出保存到fragment
      let child
      while(child=ul.firstChild) { // 一个节点只能有一个父亲
        fragment.appendChild(child)  // 先将child从ul中移除, 添加为fragment子节点
      }
    
      // 3. 更新fragment中所有li的文本
      Array.prototype.slice.call(fragment.childNodes).forEach(node => {
        if (node.nodeType===1) { // 元素节点 <li>
          node.textContent = 'atguigu'
        }
      })
    
      // 4. 将fragment插入ul
      ul.appendChild(fragment)

    8、使用DocumentFragment(文档碎片)高效批量更新多个节点 步骤?

    1、创建fragment
    2、取出ul中所有子节点取出保存到fragment
    3、更新fragment中所有li的文本
    4、将fragment插入ul
      //6. DocumentFragment: 文档碎片(高效批量更新多个节点)
      // document: 对应显示的页面, 包含n个elment  一旦更新document内部的某个元素界面更新
      // documentFragment: 内存中保存n个element的容器对象(不与界面关联), 如果更新framgnet中的某个element, 界面不变
      /*
      <ul id="fragment_test">
        <li>test1</li>
        <li>test2</li>
        <li>test3</li>
      </ul>
       */
      const ul = document.getElementById('fragment_test')
      // 1. 创建fragment
      const fragment = document.createDocumentFragment()
      // 2. 取出ul中所有子节点取出保存到fragment
      let child
      while(child=ul.firstChild) { // 一个节点只能有一个父亲
        fragment.appendChild(child)  // 先将child从ul中移除, 添加为fragment子节点
      }
    
      // 3. 更新fragment中所有li的文本
      Array.prototype.slice.call(fragment.childNodes).forEach(node => {
        if (node.nodeType===1) { // 元素节点 <li>
          node.textContent = 'atguigu'
        }
      })
    
      // 4. 将fragment插入ul
      ul.appendChild(fragment)

    二、数据代理和模板解析

    博客对应课程的视频位置:

    1.  说明

    1)  分析 vue 作为一个 MVVM 框架的基本实现原理数据代理
    模板解析
    数据绑定
    2)  不直接看 vue.js 的源码
    3)  剖析 github 上某基友仿 vue 实现的 mvvm 库
    4)  地址: https://github.com/DMQ/mvvm

    2.  准备知识

    1)  [].slice.call(lis): 将伪数组转换为真数组
    2)  node.nodeType: 得到节点类型
    3)  Object.defineProperty(obj, propName, {}): 给对象添加/修改属性(指定描述符) configurable: true/false  是否可以重新 define
    enumerable: true/false 是否可以枚举(for..in / keys())
    value: 指定初始值
    writable: true/false value 是否可以修改
    get: 回调函数, 用来得到当前属性值
    set: 回调函数, 用来监视当前属性值的变化
    4)  Object.keys(obj): 得到对象自身可枚举的属性名的数组
    5)  DocumentFragment: 文档碎片(高效批量更新多个节点)
    6)  obj.hasOwnProperty(prop): 判断 prop 是否是 obj 自身的属性

    3.  数据代理

    1)  数据代理: 通过一个对象代理对另一个对象(在前一个对象内部)中属性的操作(读/写)
    2)  vue 数据代理: 通过 vm 对象来代理 data 对象中所有属性的操作
    3)  好处: 更方便的操作 data 中的数据
    4)  基本实现流程
    a.  通过 Object.defineProperty()给 vm 添加与 data 对象的属性对应的属性描述符
    b.  所有添加的属性都包含 getter/setter
    c.  getter/setter 内部去操作 data 中对应的属性数据

    4.  模板解析

    4.1.  模板解析的基本流程


    1)  将 el 的所有子节点取出, 添加到一个新建的文档 fragment 对象中
    2)  对 fragment 中的所有层次子节点递归进行编译解析处理
    * 对大括号表达式文本节点进行解析
    * 对元素节点的指令属性进行解析
    * 事件指令解析
    * 一般指令解析
    3)  将解析后的 fragment 添加到 el 中显示

    4.2.  模板解析(1): 大括号表达式解析


    1)  根据正则对象得到匹配出的表达式字符串:  子匹配/RegExp.$1  name
    2)  从 data 中取出表达式对应的属性值
    3)  将属性值设置为文本节点的 textContent

    4.3.  模板解析(2): 事件指令解析


    1)  从指令名中取出事件名
    2)  根据指令的值(表达式)从 methods 中得到对应的事件处理函数对象
    3)  给当前元素节点绑定指定事件名和回调函数的 dom 事件监听
    4)  指令解析完后, 移除此指令属性

    4.4.  模板解析(3): 一般指令解析


    1)  得到指令名和指令值(表达式)  text/html/class msg/myClass
    2)  从 data 中根据表达式得到对应的值
    3)  根据指令名确定需要操作元素节点的什么属性
    * v-text---textContent 属性
    * v-html---innerHTML 属性
    * v-class--className 属性
    4)  将得到的表达式的值设置到对应的属性上
    5)  移除元素的指令属性


     
  • 相关阅读:
    【css系列】创建网页加载进度条
    【大数据系列】apache hive 官方文档翻译
    【大数据系列】问题汇总
    【大数据系列】hive修改默认的derby数据库
    【大数据系列】hive安装及启动
    【大数据系列】MapReduce详解
    【大数据系列】基于MapReduce的数据处理 SequenceFile序列化文件
    【大数据系列】windows下连接Linux环境开发
    【大数据系列】常用命令
    【大数据系列】hadoop脚本分析
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/12664283.html
Copyright © 2020-2023  润新知