Vue中模板渲染原理

Vue中模板渲染原理

1、概念

  • 模板:本质字符串。
  • 与字符串的区别
  1. 有逻辑(vue中有v-if、v-for)
  2. 嵌入js变量({{变量}})
  3. 需要转化为html,页面才会识别并正确解析。

2、实现过程

  • 过程:模板(字符串)解析成render函数---->render函数执行返回JS的vnode的结构,是如何实现嵌入变量和执行逻辑。转化为html则由updateComponent函数调用patch方法实现。
  • 例子1(只有js变量、无涉及逻辑):
  <div id="app">
    <p>{{price}}</p>
  </div>
  • 经过vue模板生成的结果(实现了模板转化为JS的vnode并填充data中的变量):
// 此处vm为VUE的实例
//在控制台可以打印vm._c创建元素的,vm_v创建文本节点,vm_s是用来转化为字符串的
vm._c(
        'div',
        {
          attrs: {'id': 'app'}
        },
        [
          vm._c('p', [vm._v(vm._s(vm.price))])
        ]
      )

用法备注:

  1. vm._c是基于snabbdom中的h(‘节点标签’,{属性、特性、事件},[子节点]/文本)实现的,是用来创建vnode的。vue中的render函数,实现了传入Vue实例后返回vnode的功能。
  2. vm._v是用来创建文本节点或实现换行的。
  3. vm._s是用来转化字符串的。
  4. render内部实际是使用with(vm),这样在内部就可以直接使用_c、_v、_s和data中的属性
  • 例子2(以todolist为例子,涉及v-for逻辑):
  <div id="app">
    <div>
      <input v-model="inputValue" type="text" />
      <button v-on:click="handleClick">submit</button>
    </div>
    <div>
      <ul>
        <li v-for='item of list'>
          {{item}}
        </li>
      </ul>
    </div>
  </div>
  • v-for逻辑实现是通过v._l()方法,生成对应的li结构后返回数组,将此数组作为ul节点的子节点。以下是返回的vnode:
with(vm) {
      _c(
        // 第一层(根元素)div
        'div',
        {
          attrs:{"id":"app"}
        },
        // 包含所有子节点的数组
        [
          _c(
            // 第二层第一个div(包含input、button以及其attrs、绑定事件还有值)
           'div',
           [
             _c(
                 'input',
                 {
                  //  v-model数据的双向绑定
                   directives:[
                     {
                       name:"model",
                       rawName:"v-model",
                       value:(inputValue),
                       expression:"inputValue"
                      }
                    ],
                   attrs:{
                     "type":"text"
                    },
                   domProps:{
                     "value":(inputValue)
                    },
                   on:{
                    // 监听input内容,数据改变时,让Model层的数据更新
                     "input":function($event){
                       if($event.target.composing)return;
                       inputValue=$event.target.value
                      }
                    }
                  }
                ),
               _v(" "),
               _c(
                   'button',
                   {
                    // 渲染绑定事件
                     on:{
                       "click":handleClick
                      }
                    },
                   [_v("submit")]
                  )
            ]),
          _v(" "),//创建空文本节点,用于换行
          _c(
            // 第二层第二个div(包含ul、li,其中li是通过for循环生成的)
            'div',
              [
                _c(
                  // ul标签
                  'ul',
                  // _l返回的是包含子元素的数组
                  _l((list),function(item){
                    // v-for循环,实际是返回所有创建li标签的数组
                    return _c(
                      'li',
                      [
                        _v("\n          "+_s(item)+"\n        ")
                      ]
                     )
                  }),0)//数字表示list有多少项,要返回多少个li
              ]
            )
        ]
        )}
 }

3、总结:

  • 个人理解(有误的话,欢迎指正)
    1、 模板解析成render函数---->返回JS模拟的虚拟DOM结构:模板是一段字符串,模板解析生成render函数,执行render函数返回为vnode,vnode表明了各个节点的层级关系、特性、样式、绑定的事件
    2、 vnode---->html:通过 updateComponent函数调用vm._update()传入vnode,利用基于snabbdom的patch()方法改造的生成真实DOM节点并渲染页面。
    注:vm.__patch__初次渲染时,调用vm.__patch__(containe, vnode),生成真实的DOM结构渲染到容器中。re-render时,调用vm.__patch__(vnode, newVnode)利用diff算法对比新旧vnode之间的差异,生成需要更新的真实DOM,渲染到容器的对应位置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值