美文网首页
Vue实践与总结——模板、渲染、响应式

Vue实践与总结——模板、渲染、响应式

作者: xymspace | 来源:发表于2020-06-27 21:09 被阅读0次

    Vue模板

    • 语法名称:插值表达式
    • 表现形式:{{content}}
    • content 可以是:变量、函数、函数调用、算术运算

    在Vue模板中,自动绑定了上下文对象到当前组件实例对象中,即模板可访问实例中定义的数据,访问data可以省略this

    模板与渲染

    template

    • 每一个独立的足见模板有且仅有一个顶层父级元素
    let app = new Vue({
    # 错误,顶级只能有一个div:
      template:`<div>hello world</div><div>hello world</div>`
    # 正确:
    template:`<div>hello world</div>`
      data:{
        name:'xiaoming'
      }
    })
    app.$mount('#app')
    
    • vue-cli中一般用不到---> 如果值以 # 开始,则它将被用作选择符,并使用匹配元素的 innerHTML 作为模板。常用的技巧是用<script type="x-template"> 包含模板。

    el

    • 与$mount的作用一致
    • 支持的数据类型string | Element

    • 限制:只在用 new 创建实例时生效。

    • 特性

      • 提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。

      • 在实例挂载之后,元素可以用 vm.$el 访问。

      • 如果在实例化时存在这个选项,实例将立即进入编译过程,否则,需要显式调用 vm.$mount() 手动开启编译。

    render

    • 类型(createElement: () => VNode) => VNode

    • 详细

      字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个 createElement 方法作为第一个参数用来创建 VNode

      如果组件是一个函数组件,渲染函数还会接收一个额外的 context 参数,为没有实例的函数组件提供上下文信息。

    • 虚拟 DOM(Virtual DOM)

      • html -->vNode(Vue的VDOM)
        通过原生的纯对象来间接描述一个真实 DOM 对象,只提供必要的信息,同时在需要更新的时候,会加入一些算法(diff)来比较上一次的 VDOM 与 更新后的 VDOM 之间的差异,找出确实需要更新点最后统一反馈更新对应的真实 DOM

      • 对比之下, 直接操作原生 DOM 对象有以下缺点:

        • 结构信息复杂
        • 操作耗时
        • 消耗资源

        除此之外还有其它缺点,而且原生DOM中许多的属性,在开发时也并不需要关心。因此,最好不频繁的直接操作原生DOM。

    • render函数执行流程
      html --> AST(将HTML抽象成语法树对象) --> 生成渲染函数 --> vNode --> DOM
      createElement函数的官网解析

    let app = new Vue({
      el: '#app'
      render(h) {
          return createElement(h) {
            'div',
            {
              attrs: {
                id: 'app'
              }
            },
            [
              createElement('h1', 'hello world')
            ]
          };
      }
    })
    

    编译顺序

    • 自动调用 $mount
    • 指定 el 同时又没有指定 template ,则把 elouterHTML 作为 template

    源码节选:

    HTML-->AST-->render

    // template-->el
    var template = options.template
    if (template) {
      if (typeof template === 'string') {
      }
      else if (template.nodeType) {
        template = template.innerHTML
      }
      else {
         warn()
      }
      return this
    }
    else if (el) {
      template = getOuterHTML(el);
    }
    if (template) {
      if (config.performance && mark) {
        mark('compile')
      }
    }
    // AST的具体实现。把template的html字符串,解析成对应的render函数
    // ref 是编译后返回的对象,就含有render函数
    var ref = compileToFunctions(template, {
       ...
    }, this)
    
    var render = ref.render;
    // 赋值给options.render,等待调用
    options.render = render;
    

    render的调用

      if (vm.$options.el) {
        vm.$mount(vm.$options.el)
      }
    
      Vue.prototype.$mount = function (
        el,
        hydrating
      ) {
        el = el && isBrowser ? query(el) : undefined;
        return mountComponent(this , el, hydrating)
      };
    
      Vue.prototype.$mountComponent = function (
        vm,
        el,
      hydrating
      ) {
        // 挂载el属性到对象
        vm.$el = el;
        if (!vm.$options.render) {
            vm.$options.render = createEmptyVNode;
        }
        callHook(vm, 'beforeMount')
        var updateComponent;
        if (config.performance && mark {
        }
        else {
          // 执行_render函数,得到vnode对象
          // 执行_update函数更新真实dom
          vm._update(vm._render(), hydrating)
        }
      )
    }
    
    模板编译顺序

    在源码中,Vue增加了对初始化是否成功的判断,如果非new Vue()创建的对象,Vue会报warn。

    // 初始化:
    Vue()
    // Vue内部的this指向window或者undefined(严格模式下)
    

    初始化工作是通过_init(options)函数完成的。

    模板 与 Vue响应式

    • 响应式

      • 数据发生变化,Vue会拦截并处理),是Vue有别于普通模板引擎的重要特性。
        • Vue2 中响应式数据实现是建立在 Object.defineProperty 方法上,由于该方法的本身的一些特性,在拦截数据处理上会有一些问题需要注意:

          • 对象新增属性无法拦截。
          • 数组变动无法拦截。
            • vue拦截了数组方法:push、pop、shift、unshift、splice、sort、reverse。为方法扩展了ob.dep.notify();,即数据变化时发出通知,跟新数据。
            • 利用索引直接设置一个数组项时。
            • 解决:Vue.set()、(new Vue()).$set(),两者等价。
          • 修改数组的长度时。
            • 解决:方法变异(Vue 内部已处理)。
        • Vue3中使用proxy替换了 Object.defineProperty

    • 当数据发生改变,Vue会自动跟新有关视图(只更新有变化的位置,最小化的更新视图,减少真实dom操作),让开发人员专注于数据和业务的处理。

    • Vue的响应式和性能优化,主要表现在以下特性

      • vdom(不直接操作真实DOM)
      • diff算法(计算得出最小化真实DOM的操作)

    当然,vdom改变并不一定会引起真实DOM操作。在适当情况下,新vdom会经过diff算法,与旧vodm比较,得到最小变动后,才会进行一次真实DOM操作。

    小结

    • 编译顺序:template -> el -> render
    • 直接编写render函数生成dom,最高效

    相关文章

      网友评论

          本文标题:Vue实践与总结——模板、渲染、响应式

          本文链接:https://www.haomeiwen.com/subject/acmvfktx.html