文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

vue解析指令compile源码层面使用解析

2024-04-02 19:55

关注

概述

上篇文章我们已经介绍了Vue的响应式原理,并实现了对数据的监听,监听的目的是为了及时更新视图,所以这篇文章就来介绍下vue解析指令并初始化视图部分。

compile

在Vue的构造函数中对根元素进行编译

class MVue {
  constructor (options) {
    // 保存options
    this.$options = options
    this.$data = options.data
    // 将data进行响应式处理
    observe(this.$data)
    // 代理
    proxy(this)
    // 编译 
    
    new Compile(options.el, this)
  }
}
class Compile {
  constructor (el, vm) {
    this.$vm = vm
    this.$el = document.querySelector(el)

    if (this.$el) {
      this.compile(this.$el)
    }
  }
  compile (node) {
    // 找到该元素的子节点
    const childNodes = node.childNodes
    // childNodes是类数组对象
    Array.from(childNodes).forEach(n => {
      // 判断类型
      if (this.isElment(n)) {
        this.compileElement(n)
        // 递归
        if (n.childNodes.length > 0) {
          this.compile(n)
        }
      } else if (this.isInter(n)) {
        // 动态插值表达式  编译文本
        this.compileText(n)
      }
    })
  }
  isElment (node) {
    return node.nodeType === 1
  }
  isInter (n) {
    return n.nodeType === 3 && /\{\{(.*)\}\}/.test(n.textContent)
  }
  isDir (attrName) {
    return attrName.startsWith('m-')
  }
  isEvent (attrName) {
    return attrName.startsWith('@')
  }
  // 编译元素:遍历它的所有属性,看是否m-开头指令,或者@事件
  compileElement (node) {
    const attrs = node.attributes
    Array.from(attrs).forEach(attr => {
      // m-text="XXX"
      // name = m-text, value=xxx
      const attrName = attr.name
      const exp = attr.value
      // 是指令
      if (this.isDir(attrName)) {
        // 执行特定指令处理函数
        const dir = attrName.substring(2)
        this[dir] && this[dir](node, exp)
      } else if (this.isEvent(attrName)) {
      	//是事件
      	const event = attrName.substring(1)
        // 通过bind改变this指向为vm实例,以便方法内部访问vm.data中的数据
        node.addEventListener(event, this.$vm.$methods[exp].bind(this.$vm))
      }
    })
  }
  compileText (n) {
    // 获取表达式
    // n.textContent = this.$vm[RegExp.$1]
    n.textContent = this.$vm[RegExp.$1.trim()]
  }
  text (node, exp) {
    node.textContent = this.$vm[exp] || exp
  }
  html (node, exp) {
    node.innerHTML = this.$vm[exp]
  }
  model (node, exp) {
    node.value = this.$vm[exp]
  }
}

测试代码

<!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>Document</title>
</head>
<body>
    <div id="app">
        <p>{{ counter }}</p>
        <p m-text="测试"></p>
        <p m-text="counter"></p>
        <p m-html="desc"></p>
        <input m-model="name" />
    </div>
</body>
<script src="./index.js"></script>
<script>
    const app = new MVue({
            el: '#app',
            data: {
                counter: 1,
                desc: '<span style = "color: red">super wanan</span>',
                name: 'wanan'
            }
        })
        // setInterval(() => {
        //     app.counter++
        // }, 1000)
</script>
</html>

结果

延伸及重点讲解

1. 类数组对象

node.childNodes和node.attributes都是一种类数组对象,NodeList用于保存一组有序的节点。可以通过方括号语法来访问NodeList的值,有item方法与length属性。它并不是Array的实例,没有数组对象的方法。

比如我们再compile方法中打印childNodes,会得到这样的结果:

因此需要使用Array.from()方法将类数组对象转换为真正数组。

2. RegExp.$1

RegExp 是javascript中的一个内置对象。为正则表达式。

RegExp.$1是RegExp的一个属性,指的是与正则表达式匹配的第一个 子匹配(以括号为标志)字符串,以此类推,RegExp.$2,RegExp.$3,…RegExp.$99总共可以有99个匹配

其实RegExp这个对象会在我们调用了正则表达式的方法后, 自动将最近一次的结果保存在里面, 所以如果我们在使用正则表达式时, 有用到分组, 那么就可以直接在调用完以后直接使用RegExp.$xx来使用捕获到的分组内容。

所以我们在compileText时可以这样使用:

  compileText (n) {
    // 获取表达式
    // n.textContent = this.$vm[RegExp.$1]
    n.textContent = this.$vm[RegExp.$1.trim()]
  }

需要注意的是,上述代码中还使用了trim方法去除前后空格,这是为了将{{ counter }}前后的空格去掉,正确匹配到this.vm[‘counter’],否则会读取this.vm[’ counter ']导致读取不到。

3. nodeType

DOM(文档对象模型)可以将任何HTML和XML文档描绘成一个由多层node(节点)构成的结构。

DOM1级定义了一个Node接口,该接口将由DOM中的所有节点类型实现。这个Node接口在JavaScript中作为Node类型实现的。除了IE之外,在其他所有浏览器中都可以访问到这个类型。JavaScript中的所有节点类型都继承自Node类型,因此所有节点类型都共享相同的基本属性和方法。每个节点都有一个nodeType属性,用于表明节点的类型。

nodeType的取值如下:

类型nodeType常数值描述
Node.ELEMENT_NODE1元素节点
Node.ATTRIBUTE_NODE2属性节点
Node.TEXT_NODE3文本节点
Node.CDATA_SECTION_NODE4字符数据节点(文本不会被解析器解析)
Node.ENTITY_REFERENCE_NODE5实体引用节点
Node.ENTITY_NODE6实体节点
Node.PROCESSING_INSTRUCTION_NODE7处理指令节点
Node.COMMENT_NODE8注释节点
Node.DOCUMENT_NODE9文档节点(DOM树的根节点)
Node.DOCUMENT_TYPE_NODE10向为文档定义的实体提供接口
Node.DOCUMENT_FRAGMENT_NODE11表示邻接节点和它们的子树
Node.NOTATION_NODE12代表一个符号在DTD中的声明

到此这篇关于vue解析指令compile源码层面使用解析的文章就介绍到这了,更多相关vue compile内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯