美文网首页
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