Vue解析指令源码

使用new来实例化vue对象时,去compile解析指令从而初始化视图
在这里插入图片描述

//实例化vue对象
class MVue{
  constructor(options){
    this.$el = options.el;
    this.$data = options.data;
    this.$options = options;
    if(this.$el){
      //1.实现一个数据观察者
      //2.实现一个指令解析器
      new Compile(this.$el,this)
    }
  }
}
//解析指令
class Compile{
  constructor(el,vm){
    this.el =  this.isElementNode(el)?el:document.querySelector(el);
    this.vm = vm;
    //1.获取文档碎片对象,放入内存中会介绍页面的回流重绘
    const fragment = this.node2Fragment(this.el);
    //2.编译模板
    this.compile(fragment);
    //3.追加子元素到根节点
    this.el.appendChild(fragment);
  }
  //编译模板
  compile(fragment){
    const childNodes =  fragment.childNodes;
    
    [...childNodes].forEach(child=>{
      if(this.isElementNode(child)){
        //元素节点,编译元素节点
        this.compileElement(child);
      }else{
        //文本节点
        this.compileText(child);
      }
      if(child.childNodes && child.childNodes.length){
      	//递归向下编译
        this.compile(child);
      }
    })
  }
  //编译指令
  compileElement(node){
    const attributes = node.attributes;
    [...attributes].forEach(attr=>{
      const {name,value} = attr;
      console.log();
      //判断是否是一个指令
      if(this.isDirective(name)){
        const [,dirctive] =  name.split('-');
        const [dirName,eventName] = dirctive.split(':');
        compileUtil[dirName](node,value,this.vm,eventName);
        node.removeAttribute('v-'+dirctive);
      }
      else if(this.isEventName(name)){
        let[,eventName]  = name.split('@');
        compileUtil['on'](node,value,this.vm,eventName);
      }
      else if(this.isAttrName(name)){
        let [,attrName] = name.split(':');
        compileUtil['bind'](node,value,this.vm,attrName);
      }
    })
  }
  //判断是否是@(v-on简写)
  isEventName(attrName){
    return attrName.startsWith('@')
  }
  isAttrName(attrName){
    return attrName.startsWith(':')
  }
  //判断是否是vue指令
  isDirective(attrName){
    return attrName.startsWith('v-');
  }
  //编译文本
  compileText(node){
    const content = node.textContent;
    if(/\{\{(.+?)\}\}/.test(content)){
      compileUtil['text'](node,content,this.vm)
    }
  }
  //判断是否是元素节点
  isElementNode(node){
    return node.nodeType==1;
  }
  //生成代码片段
  node2Fragment(el){
    const f= document.createDocumentFragment()
    let firstChild;
    while(firstChild = el.firstChild){
      f.appendChild(firstChild);
    }
    return f;
  }
}
//更新视图
const compileUtil={
  getVal(expr,vm){
    return expr.split('.').reduce((data,current)=>{
      return data[current];
    },vm.$data)
  },
  text(node,expr,vm){
  
  //解析v-text或{{}}
  
    let value;
    if(expr.indexOf('{{')!==-1){
      value = expr.replace(/\{\{(.+?)\}\}/g,(...args)=>{
        return this.getVal(args[1],vm);
      })
    }else{
      value = this.getVal(expr,vm);
    }
    this.updater.textUpdater(node,value);
  },
  html(node,expr,vm){
  //解析v-html
    const value = this.getVal(expr,vm);
    this.updater.htmlUpdater(node,value)
  },
  model(node,expr,vm){
  //解析v-model
    const value = this.getVal(expr,vm);
    this.updater.modelUpdater(node,value)
  },
  on(node,expr,vm,eventName){
  
  //解析v-on或@
  
    let fn = vm.$options.methods && vm.$options.methods[expr];
    node.addEventListener(eventName,fn.bind(vm),false);
  },
  bind(node,expr,vm,attrName){
  //解析v-bind或:
    let attrValue = vm.$options.data[expr];
    this.updater.bindUpdater(node,attrName,attrValue)
  },
  updater:{
  //更新视图
    textUpdater(node,value){
      node.textContent = value;
    },
    htmlUpdater(node,value){
      node.innerHTML = value;
    },
    modelUpdater(node,value){
      node.value = value;
    },
    bindUpdater(node,name,value){
      node.setAttribute(name,value);
    }
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值