查看原文
其他

[VueJS] V1 与 V2 组件实体之差异

2016-10-07 kuro 前端圈

狂贺!  终于正式发布!

关于 Vue 2.0 的新特性,作者也在官方 Blog -  ()一文中叙述地相当详细,这里就不多说。


如果你也与我一样是从 V1 就开始接触的开发者,一定都知道 VueJS 最核心的一部分是 Component,而 Component 是由实体 (VueInstance) 来实现。我们谈谈 Vue 1.x 2.x 组件实体的差异。

Vue 2.0 组件实体注册


像上面这样的网站,我们可以将它抽象化为一棵「组件树」,而每个组件树都会有个根节点,或称为根实体 (root Vueinstance)

那么,每个 Vue 组件树的根实体其实是透过  Vue  这个建构函式所产生:

1

2

3

var vm = new Vue({

// options

});

Vue 组件与实体 DOM 结合的方式有两种,一种是直接写在 el option 内:

1

2

3

var vm = new Vue({

el: '#app'

});

而另一种方式则是透过 $mount 来指定节点:

1

2

3

4

5

var vm = new Vue({

// options without 'el'

});

vm.$mount('#app');

这部分跟 Vue 1.x 的注册是完全一样的,但是需要注意的是,在 vue 1.x 允许开发者以 <body>  <html> 作为根实体的挂载点,到了 VueJS 2.0 后,只能透过 独立的节点挂载 ,如: div 等。否则会产生错误,警告讯息如下:


“Do not mount Vue to <html> or <body> - mount to normal elements instead.“


换成用独立的 DOM 节点,如 <div id="app"></div>,就可以正常运作了。

Vue 2.0 组件实体的生命周期


基本上 Vue 2.0 实体生命周期中,大部分的阶段都与 Vue 1.x 是一样的,最大的不同在于 lifecyclehook 名称的改变,以及在组件被挂载  mounted  之后,还新增了  beforeUpdate  以及  updated  这两组侦测更新的 hook


vue 1.x  init  变成  beforeCreate   beforeCompiled  改为  beforeMount而原本的  complied   ready  则是统一收敛成  mounted


另外需要注意的是,若组件本身是透过 server-siderendering 的话,除了 beforeCreate 以及 created 以外的所有 hook 都不会被呼叫(https://vuejs.org/api/#Options-Lifecycle-Hooks)


有关组件 V-DOM 的重新渲染与更新后面再提,其他部分则与 Vue 1.x 大同小异。

Vue 2.0 组件与模板的编译 - RenderFunction

在大部分情况下,透过组件的 template 属性,或是直接写在 HTML 中就已经足够操作你的组件了。不过若是你想完全透过 JavaScript 来操作你的组件,那么可以使用 render 这个 function 直接来写底层的 virtual-DOM 来取代 template 属性。 VueJS 2.0 virtual DOM 机制,是采用  这个 virtual DOM library 来实作的。


可以使用 createElement 这个 function 来建立你的组件内容:

  1. // @returns {VNode} 

  2. createElement( 

  3.   // {String | Object | Function} 

  4.   // An HTML tag name, component options, or function 

  5.   // returning one of these. Required. 

  6.   'div'

  7.   // {Object} 

  8.   // A data object corresponding to the attributes 

  9.   // you would use in a template. Optional. 

  10.   { 

  11.     // (see details in the next section below) 

  12.   }, 

  13.   // {String | Array} 

  14.   // Children VNodes. Optional. 

  15.   [ 

  16.     createElement('h1''hello world'

  17.     createElement(MyComponent, { 

  18.       props: { 

  19.         someProp: 'foo' 

  20.       } 

  21.     }), 

  22.     'bar' 

  23.   ] 

  24. )


官方也提供了一个完整的 render function 范例:

  1. var getChildrenTextContent = function (children) { 

  2.   return children.map(function (node) { 

  3.     return node.children 

  4.       ? getChildrenTextContent(node.children) 

  5.       : node.text 

  6.   }).join(''

  7. Vue.component('anchored-heading', { 

  8.   render: function (createElement) { 

  9.     // create kebabCase id 

  10.     var headingId = getChildrenTextContent(this.$slots.default

  11.       .toLowerCase() 

  12.       .replace(/\\W+/g'-'

  13.       .replace(/(^\\-|\\-$)/g''

  14.     return createElement( 

  15.       'h' + this.level, 

  16.       [ 

  17.         createElement('a', { 

  18.           attrs: { 

  19.             name: headingId, 

  20.             href: '#' + headingId 

  21.           } 

  22.         }, this.$slots.default

  23.       ] 

  24.     ) 

  25.   }, 

  26.   props: { 

  27.     level: { 

  28.       type: Number

  29.       required: true 

  30.     } 

  31.   } 

  32. })


当然,你可能跟我一样觉得一层又一层的 createElement 看了总是让人厌烦,你也可以透过这个 Plugin: ,来做 JSX 语法的转换,如果你曾是 react 应用程序的开发者,应该对 JSX 语法不陌生。写起来会像这样:

  1. import AnchoredHeading from './AnchoredHeading.vue' 

  2. new Vue({ 

  3.   el: '#demo'

  4.   render (h) { 

  5.     return ( 

  6.       <AnchoredHeading level={1}> 

  7.         <span>Hello</span> world! 

  8.       </AnchoredHeading> 

  9.     ) 

  10.   } 

  11. })


在预设情况中,VueJS 2.0 会将 template 内的 HTML 透过 parse 转换成 AST,再自动转换优化成 renderfunction 去建立 virtual DOM在建立 virtual DOM 之后,透过 observe 机制与数据进行绑定,再compile 成实体的 DOM 并渲染至网页上:


前面说过,VueJS 2.0 会将 template 内的 HTML 自动编译成 render function,下面这是官方文件以 Vue.compile 提供的 demo


  1. <!-- template --> 

  2. <div> 

  3.   <h1>I'm a template!</h1> 

  4.   <p v-if="message"

  5.     {{ message }} 

  6.   </p> 

  7.   <p v-else

  8.     No message. 

  9.   </p> 

  10. </div>


  1. // render: 

  2. function anonymous() { 

  3.   with(this){return _h('div',[_m(0),(message)?_h('p',[_s(message)]):_h('p',["No message."])])} 

  4. }


  1. // staticRenderFns: 

  2. _m(0): function anonymous() { 

  3.   with(this){return _h('h1',["I'm a template!"])} 

  4. }


Vue 2.0 组件的追踪变化

最后,我们来看看组件内状态的追踪变化。有写过 VueJS 1.x 的朋友应该知道,组件实体内有个 option  data这个 data 对象就是用来存放组件内状态/数据的地方。


Vue 1.x 相同的地方是,data 对象透过 Object.defineProperty() 来为组件内各属性设定getter」与「setter」。就在 data 属性被存取修改时,会透过 getter/setter 来通知对象内属性的变化,当先前设定好的 setter 被呼叫的时候,会去触发 watcher 重新计算,也就会导致 DOM 的更新与重新渲染。


Vue 1.x 不同的是,Vue 1.x 是透过 directive 来重新渲染 DOM 内容:


Vue 2.0 在通知 watcher 更新时,会去呼叫前面介绍的renderfunction」与更新后的 data 去做更新后再次渲染,概念与 1.x 大致相同。但更新 DOM 的手法不同,减少了不必要的比对,也因此大幅度提升了性能。




【第二期读书会送书活动正在进行中】

一、[活动]《CSS揭秘》签名版等您拿,第二期读书会来啦!


【您可能感兴趣的文章】

一、你所不知道的 URL

二、Git学习之路

三、[React启蒙系列]理解React 组件

四、探知JS测试(1)

五、探知JS测试(2)

六、前端学习路径加强版——来自《前端养成记》

七、前端技能图谱

八、重构代码的tricks

九、优化你的DOM

十、Google老板带人的3种方法



前端圈--打造专业的前端技术会议

为web前端开发者提供技术分享和交流的平台

打造一个良好的前端圈生态,推动web标准化的发展

官网:http://fequan.com

微博:fequancom | QQ群:41378087


长按二维码关注我们

投稿:content@fequan.com

赞助合作:apply@fequan.com

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存