FAQ

哇,非常长的一页!是否意味着 Vue 2.0 已经完全不同了呢,是否需要从头学起呢,Vue 1.0 的项目是不是没法迁移了?

非常开心地告诉你,并不是!几乎 90% 的 API 和核心概念都没有变。因为本节包含了很多详尽的阐述以及许多迁移的例子,所以显得有点长。不用担心,你不必从头到尾把本节读一遍!

我该从哪里开始项目迁移呢?

  1. 首先,在当前项目下运行迁移工具。我们非常谨慎地把高级 Vue 升级过程简化为使用一个简单的命令行工具。当工具识别出旧有的特性后,就会告知你并给出建议,同时附上关于详细信息的链接。

  2. 然后,浏览本页面的侧边栏列出的内容。如果发现有的标题对你的项目有影响,但是迁移工具没有给出提示,请检查自己的项目。

  3. 如果你的项目有测试代码,运行并查看仍然失败的地方。如果没有测试代码,在浏览器中打开你的程序,通过导航环顾并留意那些报错或警告信息。

  4. 现在,你的应用程序应该已彻底完成迁移。如果你渴望了解更多,可以阅读本页面剩余部分 - 或者从介绍部分,从头开始深入新的文档和改进过的指南。由于你已经熟悉一些核心概念,所以许多部分已经被删除掉。

将 Vue 1.x 版本的应用程序迁移到 2.0 要花多长时间?

这取决于几个因素:

  • 取决于你应用程序的规模(中小型的基本上一天内就可以搞定)。

  • 取决于你分心和开始 2.0 最酷的新功能的次数。 😉  无法判断时间,我们构建 2.0 应用的时候也经常发生这种事!

  • 取决于你使用了哪些旧有的特性。大部分可以通过查找和替换(find-and-replace)来实现升级,但有一些可能还是要花点时间。如果你没有遵循最佳实践,Vue 2.0 会尽力强迫你去遵循。这有利于项目的长期运行,但也可能意味着重大重构(尽管有些需要重构的部分可能已经过时)。

如果我升级到到 Vue 2 ,我还必须同时升级 Vuex 和 Vue-Router?

只有 Vue-Router 2 与 Vue 2 保持兼容,所以 Vue-Router 是需要升级的,你必须遵循 Vue-Router 迁移方式来处理。幸运的是, 大多数应用没有很多 router 相关代码,所以迁移可能不会超过一个小时。

对于 Vuex ,版本 0.8+ 与 Vue 2 保持兼容,所以部分不必强制升级。可以促使你立即升级的唯一理由,是你想要使用那些 Vuex 2 中新的高级特性,比如模块(modules)和减少的样板文件(reduced boilerplate)。

模板

片段实例 移除

每个组件必须只有一个根元素。不再允许片段实例,如果你有这样的模板:

<p>foo</p>
<p>bar</p>

最好把整个内容都简单包裹到一个新的元素里,如下所示:

<div>
  <p>foo</p>
  <p>bar</p>
</div>

升级方式

升级后运行端到端测试套件(end-to-end test suite)或运行应用程序,并查看控制台警告(console warnings)来找出那些模板中有多个根元素的地方。

生命周期钩子函数

beforeCompile 移除

使用 created 钩子函数替代。

升级方式

在代码库中运行迁移工具来找出所有使用此钩子函数的示例。

compiled 替换

使用 mounted 钩子函数替代。

升级方式

在代码库中运行迁移工具来找出所有使用此钩子函数的示例。

attached 移除

使用其他钩子函数内置的 DOM 检测(DOM check)方法。例如,替换如下:

attached: function () {
  doSomething()
}

可以这样使用:

mounted: function () {
  this.$nextTick(function () {
    doSomething()
  })
}

升级方式

在代码库中运行迁移工具来找出所有使用此钩子函数的示例。

detached 移除

使用其他钩子函数内的 DOM 检测(DOM check)方法。例如,替换如下:

detached: function () {
  doSomething()
}

可以这样使用:

destroyed: function () {
  this.$nextTick(function () {
    doSomething()
  })
}

升级方式

在代码库中运行迁移工具来找出所有使用此钩子函数的示例。

init 重新命名

使用新的 beforeCreate 钩子函数替代,本质上 beforeCreate 和 init 完全相同。init 被重新命名是为了和其他的生命周期方法的命名方式保持一致。

升级方式

在代码库中运行迁移工具来找出所有使用此钩子函数的示例。

ready 替换

使用新的 mounted 钩子函数替代。应该注意的是,使用 mounted 并不能保证钩子函数中的 this.$el 在 document 中。为此还应该引入 Vue.nextTick/vm.$nextTick。例如:

mounted: function () {
  this.$nextTick(function () {
    // 代码保证 this.$el 在 document 中
  })
}

升级方式

在代码库中运行迁移工具来找出所有使用此钩子函数的示例。

v-for

v-for 遍历数组时的参数顺序 变更

当包含 index 时,之前遍历数组时的参数顺序是 (index, value)。现在是 (value, index) ,来和 JavaScript 的原生数组方法(例如 forEachmap)保持一致。

升级方式

在代码库中运行迁移工具来找出那些使用旧有参数顺序的示例。注意,如果你将你的 index 参数命名为一些不通用的名字(例如 positionnum),迁移工具将不会把它们标记出来。

v-for 遍历对象时的参数顺序 变更

当包含 key 时,之前遍历对象的参数顺序是 (key, value)。现在是 (value, key),来和常见的对象迭代器(例如 lodash)保持一致。

升级方式

在代码库中运行迁移工具来找出那些使用旧有参数顺序的示例。注意,如果你将你的 key 参数命名为一些不通用的名字(例如 nameproperty),迁移工具将不会把它们标记出来。

$index and $key 移除

已经移除了 $index$key 这两个隐式声明变量,以便在 v-for 中显式定义。这可以使没有太多 Vue 开发经验的开发者更好地阅读代码,并且在处理嵌套循环时也能产生更清晰的行为。

升级方式

在代码库中运行迁移工具来找出使用这些移除变量的示例。如果你没有找到,也可以在控制台错误中查找(例如 Uncaught ReferenceError: $index is not defined)。

track-by 替换

track-by 已经替换为 key,它的工作方式与其他属性一样,没有 v-bind 或者 : 前缀,它会被作为一个字符串处理。多数情况下,你需要使用具有完整表达式的动态绑定(dynamic binding)来替换静态的 key。例如,替换:

<div v-for="item in items" track-by="id">

你现在应该写为:

<div v-for="item in items" v-bind:key="item.id">

升级方式

在代码库中运行迁移工具来找出那些使用track-by的示例。

v-for 范围值 变更

之前,v-for="number in 10"number 从 0 开始到 9 结束,现在从 1 开始,到 10 结束。

升级方式

在代码库中使用正则 /\w+ in \d+/搜索。当出现在 v-for 中,请检查是否受到影响。

Props

coerce Prop的参数 移除

如果需要检查 prop 的值,创建一个内部的 computed 值,而不再在 props 内部去定义,例如:

props: {
  username: {
    type: String,
    coerce: function (value) {
      return value
        .toLowerCase()
        .replace(/\s+/, '-')
    }
  }
}

现在应该写为:

props: {
  username: String,
},
computed: {
  normalizedUsername: function () {
    return this.username
      .toLowerCase()
      .replace(/\s+/, '-')
  }
}

这样有一些好处:

  • 你可以对保持原始 prop 值的操作权限。
  • 通过给予验证后的值一个不同的命名,强制开发者使用显式申明。

升级方式

运行迁移工具找出包含 coerce 选项的实例。

twoWay Prop 的参数 移除

Props 现在只能单项传递。为了对父组件产生反向影响,子组件需要显式地传递一个事件而不是依赖于隐式地双向绑定。详见:

升级方式

运行 迁移工具,找出含有 twoWay 参数的实例。

v-bind.once.sync 修饰符 移除

Props 现在只能单向传递。为了对父组件产生反向影响,子组件需要显式地传递一个事件而不是依赖于隐式地双向绑定。详见:

升级方式

运行迁移工具找到使用 .once.sync 修饰符的实例。

修改 Props 弃用

组件内修改 prop 是反模式(不推荐的)的。比如,先声明一个 prop ,然后在组件中通过 this.myProp = 'someOtherValue' 改变 prop 的值。根据渲染机制,当父组件重新渲染时,子组件的内部 prop 值也将被覆盖。

大多数情况下,改变 prop 值可以用以下选项替代:

  • 通过 data 属性,用prop去设置一个data属性的默认值。
  • 通过 computed 属性。

升级方式

运行端对端测试,查看关于 prop 修改的控制台警告信息

根实例的 Props 替换

对于一个根实例来说 (比如:用 new Vue({ ... }) 创建的实例),只能用 propsData 而不是 props

升级方式

运行端对端测试,将会弹出 failed tests 来通知你使用 props 的根实例已经失效。

Built-In 指令

v-bind 真/假值 变更

在2.0中使用 v-bind 时,只有 null, undefined , 和 false 被看作是假。这意味着,0 和空字符串将被作为真值渲染。比如 v-bind:draggable="''" 将被渲染为 draggable="true"

对于枚举属性,除了以上假值之外,字符串 "false" 也会被渲染为 attr="false"

注意,对于其它钩子函数 (如 `v-if` 和 `v-show`), 他们依然遵循 js 对真假值判断的一般规则。

升级方式

运行端到端测试,如果你app的任何部分有可能被这个升级影响到,将会弹出failed tests

v-on 监听原生事件 变更

现在在组件上使用 v-on 只会监听自定义事件(组件用 $emit 触发的事件)。如果要监听根元素的原生事件,可以使用 .native 修饰符,比如:

<my-component v-on:click.native="doSomething"></my-component>

升级方式

运行端对端测试,如果你app的任何部分有可能被这个升级影响到,将会弹出failed tests

带有 debouncev-model移除

Debouncing 曾经被用来控制 Ajax 请求及其它高耗任务的频率。 Vue 中v-modeldebounce 属性参数使得在一些简单情况下非常容易实现这种控制。但实际上,这是控制了 状态更新 的频率,而不是控制高耗时任务本身。这是个微小的差别,但是会随着应用增长而显现出局限性。

例如在设计一个搜索提示时的局限性:

{{ searchIndicator }}