Vue源码学习之实现模板转化成ast语法树(上)

555 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

接上文数据劫持完成以后,就开始需要和视图进行挂钩了,开始写模板了。回到我们的index.html中增加模板。

第一步 增加模板

// index.html
<div id="app">
  <span>{{name}}</span>
  <span>{{age}}</span>
</div>
<script src="vue.js"></script>
<script>
  const vm = new Vue({
    data:{
    name:'i东东',
    age:18
    },
    el:'#app',
  })
</script>

在页面中可以用Mustache语法,也就是双大括号进行取值,但是我们需要对模板进行编译,所以我们就加一个属性el:'#app',表示我们要将数据解析到el元素上,紧接着就需要将模板里面的数据进行替换。首先能够想到的方法就是:

  • 模板引擎:每次拿到模板,用数据进行替换。这样做的缺点就是性能差,需要正则匹配替换(vue1.0的时候没有引入虚拟DOM的改变)
  • 操作虚拟DOM:数据变化后比较虚拟DOM的差异,最后更新需要更新的地方
  • 核心就是将模板转换成js语法,通过js语法去生成虚拟DOM

第二步 判断是否有模板

语法之间的转换,像ES6转到ES5 语法转义需要先变成语法树再重新组装代码成为新的语法,需要将模板先编译成ast语法树再进行转换,那么我们就需先拿到模板,再进行解析。模板可以写在下面这些地方:

  • template
  • el
  • render(){return h('div',{ })} 将template语法转化为render函数
const vm = new Vue({
  data:{
  name:'i东东',
  age:18
  },
  // el:'#app', // 需要将数据解析到el元素上
  template:'<div>hh</div>'
  render(){
    return h('div',{

    })
  }
})
vm.$mount('#app')

紧接着就需要到到我们初始化的地方init.js进行判断是否有el,如果有的话说明有模板,这个时候就需要去挂载数据

// src/init.js
if (options.el) {
  vm.$mount(options.el) // 实现数据挂载
}
Vue.prototype.$mount = function (el) {
  ......
}

第三步 扩展$mount

  Vue.prototype.$mount = function (el) {
    const vm = this
    el = document.querySelector(el)
    let ops = vm.$options
    if (!ops.render) { // 先看有没有写render函数
      let template // 没有render函数再看有没有写template,没写template就用外部的template
      if (!ops.template && el) { // 内有写模板,但是写了el
        template = el.outerHTML
      } else {
        if (el) {
          template = ops.template // 如果有el就采用模板进行编译
        }
      }
      // 写了template就用template
      if (template) {
        // 这里需要对模板进行编译
        const render = compileToFcuntion(template)
        ops.render = render // jsx最终会编译成h('xxx')
      }
    }
  }

script标签引用的vue.global.js这个编译过程是在浏览器运行的,runtime(运行时)是不包含模板编译的 整个编译是打包的时候通过loader来转义.vue文件的,用runtime的时候不能使用template

2.jpg

1111.jpg

运行index.html控制台输出如上信息,就正确拿到了模板,最后就可以通过compileToFcuntion(模板)函数,对模板进行编译了,这个方法属于核心编译方法,所以在src下新增一个模块compiler。

src/compiler/index.js
// 对模板进行编译处理
export function compileToFcuntion(template){
    // 1.将template转换为ast语法树
    // 2.生成render方法 render方法执行后的结果就是虚拟DOM
    console.log(template);
}

1111.jpg 运行index.html当src/compiler/index.jsconsole.log(template)输出如上图,则说明成功了,接下来就可以在src/compiler/index.js进行模板的编译处理。

最后

对模板的编译处理放在下一篇写,不断学习进阶,加油!