Vue实现流程-模版解析(二)

Vue的模板在HTML中并不直接被浏览器解析,而是经过模版解析成JavaScript的render函数。通过查看Vue源码,我们可以找到编译后的render函数,它包含了模板中的数据属性、指令逻辑,并构建出类似snabbdom的虚拟DOM结构。Vue利用with关键字将模板内容转化为实例上的变量,通过响应式系统监听数据变化并更新视图。
摘要由CSDN通过智能技术生成

Vue模版解析

首先我们来写一个Vue的todo-list

<!--  HTML -->
<div id="app">
    <div>
        <input type="text" v-model="title">
        <button @click="add">submit</button>
    </div>
    <ul>
        <li v-for="item in list">{{item}}</li>
    </ul>
</div>
// JavaScript
<script src="./vue2.5.13.js"></script>
<script>
    var data = {
        title: '',
        list: []
    }
    var app = new Vue({
        el: "#app",
        data: data,
        methods: {
            add: function() {
                if(this.title){
                    this.list.push(this.title)
                }
                this.title = ''
            }
        }
    })
</script>

看到这段代码大家肯定不陌生,这些v-for、v-model、@click命令是vue定义的。但是HTML根本不认识这些玩意啊,从来没见过这些。而且最后我们打开浏览器控制台,生成的HTML结构里面也没有这些,那么这之间是发生了事情呢?

解析模版成render函数

其实todo-list所写的HTML代码,看似是HTML代码,但是实际上并不是,它会被Vue模版解析成一段JavaScript代码,

那我们在哪里能看到render函数呢?

Vue-2.5.13源代码
搜索code.render,并且在其函数内添加alert(code.render)来获取整个code.render返回的东西

        //10677code.render
        alert(code.render);
        return {
            ast: ast,
            render: code.render,
            staticRenderFns: code.staticRenderFns
        }

还是以上面的todo-list为例,我们最终生成得到的是编译后的数据:

with(this){return _c('div',{attrs:{"id":"app"}},[_c('div',[_c('input',{directives:[{name:"model",rawName:"v-model",value:(title),expression:"title"}],attrs:{"type":"text"},domProps:{"value":(title)},on:{"input":function($event){if($event.target.composing)return;title=$event.target.value}}}),_v(" "),_c('button',{on:{"click":add}},[_v("submit")])]),_v(" "),_c('ul',_l((list),function(item){return _c('li',[_v(_s(item))])}))])}

让我们手动格式化一下:

with(this){
    return _c(
        // 创建节点 _c create
        'div',
        {
            attrs:{"id":"app"}
        },
        [
            _c(
                'div',
                [
                    _c(
                        'input',
                        {
                            // v-model
                            directives:[
                                {
                                    name:"model",
                                    rawName:"v-model",
                                    value:(title),
                                    expression:"title"
                                 }
                            ],
                            attrs:{"type":"text"},
                            domProps:{"value":(title)},
                            on:{
                                "input":function($event){
                                    if($event.target.composing)return;
                                    title=$event.target.value
                                }
                            }
                        }
                    ),
                    // 模版的换行符
                    _v(" "),
                    _c(
                        'button',
                        {
                            on:{
                                "click":add
                            }
                        },
                        // _v 创建文本节点
                        [_v("submit")]
                    )
                ]
            ),
            _v(" "),
            _c(
                'ul',
                // _l for循环
                _l(
                    (list),
                    function(item){
                        return _c(
                            'li',
                            [
                                _v(
                                    _s(item)
                                    // _s toString
                                )
                            ]
                        )
                    }
                )
            )
        ]
    )
}



这和snabbdom的vdom结构非常相似。

注意: with 这是Vue在内部使用的,平时开发不推荐使用,这里 with(this)中的this指向了Vue的实例vm,在其后面value:(title)访问的title可以理解为vm.title

JavaScript查找某个未使用命名空间的变量时,会通过作用域链来查找,作用域链是跟执行代码的context或者包含这个变量的函数有关,具体查看MDN-with

这段代码我们看到了什么?

  1. 模版中所有的信息都被render函数包裹着了

  2. 模版中所有的data中的属性,都变成了JS的变量

  3. 模版中所有的v-model v-for v-on 都变成了JS的逻辑

  4. 最终render函数返回了一个vnode

最后说一句话:其实在最初Vue模版其实就是通过Vue中的render函数编译解析,返回一个vnode对象,之后会通过响应式来监听数据变化更新视图

render函数和vdom

vm._update(vnode) {
  // 上一次更新的vnode
  const prevVnode = vm._vnode
  // 下一次对比的vnode
  vm._vnode = vnode
  // 第一次执行
  if(!prevVnode) {
    vm.$el = vm.__patch__(vm.$el,vnode)
  } else {
    vm.$el = vm.__patch__(prevVnode, vnode)
  }
}
function updateComponent() {
  // 将生成的JS模版当参数传递
  vm._update(vm._render())
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值