Vue学习笔记-四

升级vue2.0

为什么要升级Vue2.0呢?个人觉得以下改变比较吸引人:

  • 更轻更快;
  • 加入虚拟DOM;
  • 更清晰合理的生命周期架构;
  • 更简洁迷你的API;
  • 更符合未来技术规范的设计;
  • 解锁JSX和render函数;
  • ······

  • ······

vue-migration-helper

第一步是使用官方的升级助手vue-migration-helper检测项目代码中可能需要升级的地方。我的小项目代码中共检测出 40 个地方可能需要修改,具体会在下面介绍。

render函数

关于render函数,官方是这样说的:

大多数情况下使用基于 template 构件组件都是推荐的,但是 render()函数可以让你在组件中运用更强大的JS。

render() 接收一个叫 createElement 的函数作为形参,它的作用是创建虚拟DOM节点createElement说明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 返回虚拟DOM对象
createElement(
// {String | Object | Function}
// 必选项,HTML节点名,自定义组件或者返回这些的函数
'div',
// {Object}
// 一个对象,描述了用在template中的属性
{
// (比如props)
},
// {String | Array}
// 子节点集合,可以是字符串或者是另一个createElement函数
[
createElement('h1', 'hello world'),
createElement(MyComponent, {
props: {
someProp: 'foo'
}
}),
'bar'
]
)

createElement第二个形参详解

上文说了这是个描述template中涉及属性的对象,一般来说我们在template中用到的无非:v-bindv-onslotkeyref和某些原生DOM属性,下面是一个较为完整的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
{
// Same API as `v-bind:class`
'class': {
foo: true,
bar: false
},
// Same API as `v-bind:style`
style: {
color: 'red',
fontSize: '14px'
},
// Normal HTML attributes
attrs: {
id: 'foo'
},
// Component props
props: {
myProp: 'bar'
},
// DOM properties
domProps: {
innerHTML: 'baz'
},
// 使用v-on绑定的事件处理函数
on: {
click: this.clickHandler
},
// 仅用于在自定义组件上绑定原生事件的native描述符
nativeOn: {
click: this.nativeClickHandler
},
// 自定义指令
directives: [
{
name: 'my-custom-directive',
value: '2'
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// The name of a slot if the child of a component
slot: 'name-of-slot'
// Other special top-level properties
key: 'myKey',
ref: 'myRef'
}

在reder中使用JSX

通过 Babel plugin 的支持,现在你可以在vue中使用JSX语法了!(插件地址)它所做的事是将JSX语法的模板转换为render函数:

1
2
3
4
5
6
7
8
<div id="foo">{this.text}</div>
// To the following JavaScript:
h('div', {
attrs: {
id: 'foo'
}
}, [this.text])

使用jsx语法编写的render组件:

1
2
3
4
5
6
7
8
9
10
11
import AnchoredHeading from './AnchoredHeading.vue'
new Vue({
el: '#demo',
render (h) {
return (
<AnchoredHeading level={1}>
<span>Hello</span> world!
</AnchoredHeading>
)
}
})

函数化组件

函数化的组件意味着:无状态,非实例,内部没有this:

1
2
3
4
5
6
7
8
9
10
11
12
Vue.component('my-component', {
functional: true,
// To compensate for the lack of an instance,
// we are now provided a 2nd context argument.
render: function (createElement, context) {
// ...
},
// Props are optional
props: {
// ...
}
})

具体介绍见:Functional Components

生命周期

生命周期改动比较大,但是升级起来也很容易,具体见下图,有需要照着改就行,不再多说: img

组件通信

这部分是比较麻烦的,因为之前有用的 $dispatch$broadcast 都被废弃了,组件 events选项也被废弃了,因此这次不得不重构事件部分的代码,原则和注意点如下:

  • 父组件向子组件传递数据使用props,子组件中禁止修改props属性,同时绑定props不再支持双向绑定;
  • 子组件向父组件传递事件使用v-on,子组件中使用$emit('test')触发事件,父组件使用v-on:test订阅事件。在自定义组件上订阅原生事件需要加.native修饰符;
  • 兄弟组件或者嵌套比较深的组件之间可以通过新建一个Vue实例作为event hub,当然也推荐使用vuex
  • 使用$emit触发自定义事件时,事件名称需要以xx-xxx的方式命名;

特别注意: 父组件上不能使用 v-on 订阅其子组件中嵌套组件触发的事件。也就是说 $emit 触发的事件不会像原生事件一样冒泡!

动画

vue2.0对动画做了非常大的更新,原来的transition属性被彻底废弃,取而代之的是更强大的 <transition>元素,以前如果用到了动画必然是要重写的,而且css的命名规则也变了,css也得重写······

filter

之前是直接使用vue提供的filterBy 方法,但是在2.0中被废弃了,这部分也得使用计算属性重构。这里需要说明的是,本应用中用到了两层嵌套的 v-for ,第二层的v-for依赖于第一层v-for给的数据,且每一个列表都需要 filter,第一层可以使用计算属性,那么第二层呢? 答案是用方法:

1
2
3
4
5
6
7
8
<!--itemsData是计算属性,itemsFilter是方法-->
<ul>
<li v-for="items in itemsData">
<ol>
<li v-for="item in itemsFilter(items)"></li>
</ol>
</li>
</ul>

其它

  • v-for中废弃了$index,使用时改为主动声明:
1
2
3
<ul class="catalog">
<li v-for="(catalog, index) in catalogs" v-on:click="updateCatalog(index)"></li>
</ul>
  • v-elv-ref 合并为一个 ref 属性,当元素为自定义组件时ref指向组件,否则指向真实的DOM元素;
  • vue2.0默认输出vue.common.js,common不支持template选项,所以如果你在组件选项中用到了template(通过vue-loader处理过的.vue文件中的template不会有问题)需要在webpack中设置vue的别名
  • 随着升级2.0,vue生态的其它插件也有升级情况,webpack配置也有变化,建议更换。(ps:yarn第一次的install的时候也很慢···)
谢谢你请我吃糖果