zoukankan      html  css  js  c++  java
  • 8.30vue响应式原理

    1. 编译模块
      效果//姓名:{{name}},年龄:{{age}},居住:{{addr.province}}
      //返回 姓名:mon,年龄:17,居住:dd
      //obj = { 姓名:mon,年龄:17,addr:{
                province:'等等',
                city:'ddd'
              },}
      //只有嵌套对象没有数组
      function compile(template,obj) {
       let res = gettemplate(template) //把模版字符串中需要替换的{{}}找出来
       for(let i = 0; i < res.length; i++) {
         template = replace (template,res[i],obj) //然后把{{}}替换对应的属性值
       }
       return template
      }
      function gettemplate(template) { return template ? template.match(/{{[^}]+}}/g) : [] // {{}}数组 }
      function replace (template,subTemplate,obj){ let prop = subTemplate.replace('{{','').replace('}}','') //根据{{}}找出对应的属性 let value = getValue(obj,prop)//根据属性得到属性值 return template.replace(subTemplate,value) //把{{}}替换成属性值 }
      function getValue(obj,prop) { let props = prop.split('.')//嵌套对象的属性数组 let value = obj for(let i = 0; i < props.length; i++) { value = value[props[i]] } return value }
    2. 创建虚拟节点
      function node(realDom,template) { //真实节点,模版字符串===节点文本
       this.realDom = realDom
       this.template = template
       this.children = [] //子节点数组
      }
      
      function createNode(realDom){
       let template = ''  
       if(realDom.nodeType === Node.TEXT_NODE) {//判断是否是文本节点
       template = realDom.nodeValue 
       } 
       let vnode = node(realDom,template)
       for (let i = 0; i < realDom.childNodes.length; i++) { //子节点
         let childnode = realDom.childNodes[i] 
         let childVnode  = createNode(childnode)
         node.children.push(childVnode)
       }
       return node
      }

      虚拟节点
      //
      node {realDom: div#app, template: "", children: Array(5)}
        1. children: (5) [node, node, node, node, node]
        2. realDom: div#app
        3. template: ""
        4. __proto__: Object
      
      
    3. 渲染页面的文本
      function render (node,obj) {
       //找到包含{{}}的文本节点
       node.template = node.template.trim()
       if(node.template) {
       let newText = compile( node.template,obj) //如果有{{}}就得到编译后的字符串
        if(newText !==node.realDom.nodeValue){//如果有更新就让节点更新
        node.realDom.nodeValue  = newText
        }
       }else {
        for (let i = 0; i < node.children.length; i++) { //没有{{}}就递归渲染子节点
            render(node.children[i],obj)
          } 
       }
      }

      //
      <p>姓名:a</p>
      <p>年龄:17</p>
      <p>居住:等等</p>
      
      
    4. 响应式
      //Object.defineProperty
      //将原始对象obj的所有属性复制到targetobj,并且让targetobj属性都具有响应式,当改变时就运行回调函数
      
      function createResponse((obj,targetobj,callback) {
       for(const key in obj) {
       clone(obj,key,targetobj,callback)
       }
      }
      
      function clone(obj,key,targetobj,callbac){ //克隆对象并且有每个属性有响应式
       if(typeof obj[prop] === 'object') {//如果属性是对象
        let newObj = {}//把属性对象又用新的对象这样克隆并且拥有响应式
        createResponse((obj[prop],newObj,callback) 
        Object.defineProperty(target,prop,{
          get:function (params) {
              return newobj
            },
          set:function (params) {
              obj[prop] = params //响应式
              if (typeof params === 'object') { //如果修改的属性值是对象 又需要创建新的对象来让修改的属性拥有响应式
                newobj = {}
                createResponse(params,newobj,callback)
              }else {
                newobj = params //不是对象就直接赋值
              }
              callback && callback()
            }
        })
       }else {       //属性不是对象就直接defineProperty
       Object.defineProperty(target,prop,{
         get:function(){
           return obj[prop] //返回原来的属性
         },
         set:function(val){
          obj[prop] = params //响应式
          callback && callback()
         }
        })
       }
      }
      //

      vm.age = 10
      10

      <p>年龄:10</p>

      
      
    5. 合并
      export default function Vue(options) { //绑定实例
        let el = options.el
        this.$data = options.data
        this.$el = document.querySelector(el) 
        
        this.$node = createNode( this.$el) //虚拟节点
         render(this.$node,this.$data) //渲染文本
         createResponse(this.$data,this,() => { //响应式
           render(this.$node,this.$data)
         })
      
      }
    6. html
       <div id="app">
          <p>姓名:{{name}}</p>
          <p>年龄:{{age}}</p>
      <p>居住:{{addr.province}}</p>
      </div>
        <button onclick='vm.age++'>+</button> 
      
      
       let obj = {
              name:'moc',
              age:17,
              addr:{
                province:'等等',
                city:'ddd'
              },
              
            }
            let newobj = {}
            createResponse(obj,newobj,() => {
              console.log('有属性改变了')
            })
            window.newobj = newobj
      
         window.vm = new Vue({
          el:'#app',
          data:{
            name:'a',
            age:17,
            addr:{
                province:'等等',
                city:'ddd'
              },
          }
        }) 
  • 相关阅读:
    面向对象(接口 ,多态)
    面向对象(继承,重写,this,super,抽象类)
    IO(字符流 字符缓冲流)
    ArrayList集合
    字符串常用API
    面向对象(类,封装,this,构造方法)
    不同类型问题代码训练
    java中的方法
    04慕课网《进击Node.js基础(一)》HTTP讲解
    《JavaScript设计模式与开发实践》——第3章 闭包和高阶函数
  • 原文地址:https://www.cnblogs.com/zjj-study/p/13584694.html
Copyright © 2011-2022 走看看