【Vue源码】Vue核心应用之模板参数解析

404 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

Vue全家桶的系统学习,其中包括Vue源码分析Vue-Router的使用和原理Vuex的用法和原理Vue-ssr、如何进行单元测试 和 一些常见的Vue面试题


参数解析

我们都知道,Vue中有一种特殊的模板语法 {{}}Mustache语法,也就是我们经常说的 胡子语法

<div id="app">
    <div>{{name}}</div>
    <span>{{age}}</span>
</div>
<script src="../dist/umd/vue.js"></script>
<script>
    let vm = new Vue({
        el: "#app", // 将数据解析到 el 元素上
        data() {
            return {
                name: "MXShang",
                age: 25,
            };
        },
    });
</script>

在Vue框架中,数据就被渲染到视图中了。

所以现在我们需要将 模板中的内容数据 进行替换。

数据渲染的几种方式

  • 模板引擎模板引擎 的使用方法在我之前的文章中有提到过,感兴趣的可以去了解一下。 其大概思路就是每次渲染时,将模板中的内容拿到,并进行正则匹配与替换。 这样操作会有一个问题,那就是 性能很差。而在 Vue1.0 时,并没有引入 虚拟DOM 的概念,所以它的性能是很差的。
  • 虚拟DOM:数据变化后,比较虚拟DOM的差异,最后更新需要改变的地方。

核心思路就是,将模板变成 JS语法,并通过 JS语法 生成 虚拟DOM

从一种东西转换成另一种东西,比如 语法间的转换、css的压缩 等等。我们都需要先将其变成 语法树 ,然后再重新组装成新的代码。

在Vue中,我们就需要将 template 转变成 render函数

let vm = new Vue({
  el: "#app",
  template: "<div>hello</div>", // template属性可以将内容渲染在el元素中
  render() {
    // h 就相当于 createElement
    return h("div", {});
  },
});

数据挂载

首先,我们在初始化的时候,要先判断是否传入了 el属性

Vue.prototype._init = function (options) {
    const vm = this;
    vm.$options = options;
    initState(vm);
    // 实现数据挂载
    if (vm.$options.el) {
    	vm.$mount(vm.$options.el);
    }
}

如果传入了 el属性,则将其传入 $mount 函数中。

(注:所以我们在实际项目中,使用 el 挂载和在全局中使用 vm.$mount 挂载效果是一样的。)

$mount函数

$mount 函数其实就是一个 挂载函数,它用来判断当前实例中是否包含 eltemplaterender函数 等。

  1. 在Vue原型上添加一个 $mount 方法,将 el 传入。

    Vue.prototype.$mount = function (el) {
    	// ...
    }
    
  2. 获取 el 对应的Dom元素。

    Vue.prototype.$mount = function (el) {
        const vm = this;
        const options = vm.$options; // 将options也提取出来,因为后面会频繁使用
        el = document.querySelector(el);
    }
    
  3. 判断是否传入了 rendertemplate 等属性,随后通过 compileToFunctions函数,将 template 编译成 render函数

    Vue.prototype.$mount = function (el) {
    		// ...
      	// 如果没有render方法
        if (!options.render) {
            let template = options.template;
            // 如果没有模板但是有el
            if (!template && el) {
            	template = el.outerHTML;
            }
            const render= compileToFunctions(template);
            options.render = render; // 导出最终的 render 方法
        }
    }
    

compileToFunctions函数 其实就是将传入的 template 转变成对应的 AST语法树 ,并生成对应的代码,然后再生成 render函数

我们现在需要在目录中新建一个模块 compiler

|-- src
    |-- index.js
    |-- init.js
    |-- state.js
    |-- util.js
    |-- compiler
    |   |-- index.js
    |-- observer
        |-- array.js
        |-- index.js

这个模块就是用来对 compileToFunctions函数 进行封装与完善的。

// compiler/index.js
export function compileToFunctions(template) {
  console.log(template);
}

在后续的文章中,我们会详细介绍一下如何生成 AST语法树

本篇文章由 莫小尚 创作,文章中如有任何问题和纰漏,欢迎您的指正与交流。 您也可以关注我的 个人站点博客园掘金,我会在文章产出后同步上传到这些平台上。 最后感谢您的支持!