27. Migration from Vue 1.x(从Vue 1.x迁移)
从Vue 1.x迁移
常问问题
哇 - 这是一个超长的页面!这是否意味着2.0是完全不同的,我将不得不重新学习基础知识,而迁移实际上是不可能的?
我很高兴你问了!答案是不。大约90%的API是相同的,核心概念没有改变。这很长,因为我们希望提供非常详细的解释并包含大量示例。放心吧,这不是你必须自上而下阅读的东西!
我应该从哪里开始迁移?
- 首先在当前项目上运行迁移助手。我们仔细缩小并压缩了一个高级的Vue开发工具,使其成为一个简单的命令行界面。每当他们识别出过时的功能时,他们都会通知您,提供建议并提供更多信息的链接。
将Vue 1.x应用程序迁移到2.0需要多长时间?
这取决于几个因素:
- 您的应用程序的大小(小到中等大小的应用程序可能会少于一天)
如果我升级到Vue 2,我还需要升级Vuex和Vue Router吗?
只有Vue Router 2与Vue 2兼容,所以是的,你也必须遵循Vue Router的迁移路径。幸运的是,大多数应用程序没有太多的路由器代码,所以这可能不会超过一个小时。
至于Vuex,甚至0.8版本都与Vue 2兼容,所以你不需要升级。您可能想要立即升级的唯一原因是利用Vuex 2中的新功能,例如模块和简化的样板。
模板
碎片实例已删除
每个组件必须只有一个根元素。碎片实例不再被允许。如果你有这样的模板:
<p>foo</p>
<p>bar</p>
建议将全部内容包装在一个新元素中,如下所示:
<div>
<p>foo</p>
<p>bar</p>
</div>
升级路径
升级后运行您的端到端测试套件或应用程序,并查找有关模板中多个根元素的控制台警告
。
Lifecycle Hooks
beforeCompile 去除
改用created
hook。
Upgrade Path
在您的代码库上运行迁移助手以查找此hook的所有示例。
compiled replaced
改用新的mounted
hook。
升级路径
在您的代码库上运行迁移助手以查找此钩子的所有示例。
attached removed
在其他钩子中使用自定义的DOM内检查。例如,要替换:
attached: function () {
doSomething()
}
你可以使用:
mounted: function () {
this.$nextTick(function () {
doSomething()
})
}
Upgrade Path
在您的代码库上运行迁移助手以查找此钩子的所有示例。
detached removed
在其他钩子中使用自定义的DOM内检查。例如,要替换:
detached: function () {
doSomething()
}
你可以使用:
destroyed: function () {
this.$nextTick(function () {
doSomething()
})
}
升级路径
在您的代码库上运行迁移助手以查找此钩子的所有示例。
init renamed
改用新的beforeCreate
钩子,这本质上是一回事。它被重命名为与其他生命周期方法保持一致。
升级路径
在您的代码库上运行迁移助手以查找此钩子的所有示例。
ready replaced
改用新的mounted
钩子。应该指出的是,mounted
没有保证在文件中。为此,还包括Vue.nextTick
/ vm.$nextTick
。例如:
mounted: function () {
this.$nextTick(function () {
// code that assumes this.$el is in-document
})
}
升级路径
在您的代码库上运行迁移助手以查找此钩子的所有示例。
v-for
v-for Argument Order for Arrays changed
包含一个index
数组时,过去的数组的参数顺序是(index, value)
。现在它(value, index)
与JavaScript的本地数组方法(如forEach
and)更加一致map
。
升级路径
在您的代码库上运行迁移助手以查找过时的参数顺序的示例。请注意,如果您将索引参数命名为position
或不正常num
,助手将不会标记它们。
v-for Argument Order for Objects changed
当包含a时key
,过去的对象的参数顺序是(key, value)
。它现在(value, key)
与常见的对象迭代器(如lodash)更加一致。
升级路径
在您的代码库上运行迁移助手以查找过时的参数顺序的示例。请注意,如果您将关键参数命名为name
或property
,助手将不会标记它们。
删除$index和$key
隐式赋值$index
和$key
变量已被删除,有利于明确定义它们v-for
。这使得对于Vue经验较少的开发人员来说代码更容易阅读,并且在处理嵌套循环时也会产生更清晰的行为。
升级路径
在您的代码库上运行迁移助手以查找这些已删除变量的示例。如果你错过了,你还应该看到控制台错误,
例如:Uncaught ReferenceError: $index is not defined
替代track-by
track-by
已被替换为key
,其工作方式与任何其他属性一样:没有v-bind:
或:
前缀时,它被视为文字字符串。在大多数情况下,您希望使用一个动态绑定,它需要一个完整的表达式而不是一个键。例如,代替:
<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 选项已删除
如果你想强制一个道具,建立一个基于它的本地计算值。例如,而不是:
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 选项已删除
Prop 现在一直是单向的。为了在父范围中产生副作用,组件需要显式地发出事件,而不是依赖于隐式绑定。有关更多信息,请参阅:
- 自定义组件事件
升级路径
在代码库上运行迁移助手以查找twoWay
选项的示例。
.once和.sync修饰符在v-bind已删除
Prop 现在一直是单向的。为了在父范围中产生副作用,组件需要显式地发出事件,而不是依赖于隐式绑定。有关更多信息,请参阅:
- 自定义组件事件
升级路径
在您的代码库上运行迁移助手以查找.once
和.sync
修饰符的示例。
Prop Mutation已弃用
现在在本地修改道具现在被认为是反模式,例如声明道具然后this.myProp = 'someOtherValue'
在组件中设置。由于新的渲染机制,无论父组件重新呈现何时,子组件的本地更改都将被覆盖。
大多数使用突变道具的用例都可以用下列其中一个选项来代替:
- 一个数据属性,用于设置其默认值的 prop
升级路径
升级后运行您的端到端测试套件或应用程序,并查找有关 prop 突变的控制台警告
。
替换根实例上的道具
Vue 根实例(即使用创建的实例new Vue{ ... }))
上,您必须使用propsData而
不是props。
升级路径
运行你的端到端测试套件,如果你有的话。在失败的测试
应提醒你一个事实,即传递给 root 用户实例道具都不再工作。
计算属性
cache: false 弃用
计算属性的缓存失效将在 Vue 的未来主要版本中删除。使用方法替换所有未缓存的计算属性,这些方法将具有相同的结果。
例如:
template: '<p>message: {{ timeMessage }}</p>',
computed: {
timeMessage: {
cache: false,
get: function () {
return Date.now() + this.message
}
}
}
或者使用组件方法:
template: '<p>message: {{ getTimeMessage }}</p>',
methods: {
getTimeMessage: function () {
return Date.now() + this.message
}
}
升级路径
在代码库上运行迁移助手以查找cache: false
选项的示例。
内置指令
带有 v-bind 改变的
Truthiness / Falsiness
当使用v-bind
时,唯一的错误值现在是:null
,undefined
,和false
。这意味着0
空串会渲染成真理。例如,v-bind:draggable="''"
将渲染为draggable="true"
。
对于枚举属性,除了上面的虚假值之外,该字符串"false"
也将呈现为attr="false"
。
请注意,对于其他指令(例如v-if
和v-show
),JavaScript 的正常真实性仍然适用。
升级路径
运行你的端到端测试套件,如果你有的话。在失败的测试
应该提醒您注意可能会受到这一更改的影响你的应用程序的任何部分。
在v-on更改的组件上监听本地事件
在组件上使用时,v-on
现在只会侦听$emit
由该组件定制的自定义事件。要在根元素上侦听本地 DOM 事件,可以使用.native
修饰符。例如:
<my-component v-on:click.native="doSomething"></my-component>
升级路径
运行你的端到端测试套件,如果你有的话。失败的测试
应该提醒您注意可能会受到这一更改的影响你的应用程序的任何部分。
已删除v-model的debounce参数属性
Debouncing 用于限制我们执行 Ajax 请求和其他昂贵操作的频率。Vue 的debounce
属性参数对于v-model
非常简单的情况很容易实现,但它实际上会消除状态更新
而不是昂贵的操作本身。这是一个微妙的差异,但随着应用程序的增长它会有局限性。
这些限制在设计搜索指示器时变得明显,例如:
使用该debounce
属性,将无法检测“打字”状态,因为我们无法访问输入的实时状态。然而,通过将去抖功能与 Vue 分离,我们只能够去除我们想要限制的操作,消除了我们可以开发的功能限制:
<!--
By using the debounce function from lodash or another dedicated
utility library, we know the specific debounce implementation we
use will be best-in-class - and we can use it ANYWHERE. Not only
in our template.
-->
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.js"></script>
<div id="debounce-search-demo">
<input v-model="searchQuery" placeholder="Type something">
<strong>{{ searchIndicator }}</strong>
</div>
new Vue{
el: '#debounce-search-demo',
data: {
searchQuery: '',
searchQueryIsDirty: false,
isCalculating: false
},
computed: {
searchIndicator: function () {
if (this.isCalculating) {
return '⟳ Fetching new results'
} else if (this.searchQueryIsDirty) {
return '... Typing'
} else {
return '✓ Done'
}
}
},
watch: {
searchQuery: function () {
this.searchQueryIsDirty = true
this.expensiveOperation()
}
},
methods: {
// This is where the debounce actually belongs.
expensiveOperation: _.debounce(function () {
this.isCalculating = true
setTimeout(function () {
this.isCalculating = false
this.searchQueryIsDirty = false
}.bind(this), 1000)
}, 500)
}
})
这种方法的另一个优点是有些时候反弹并不是正确的包装功能。例如,当点击搜索建议的 API 时,在用户停止键入一段时间之后等待提供建议并不是理想的体验。你可能想要的是一个节流
功能。现在,由于您已经在使用像 lodash 这样的实用程序库,重构使用其throttle
功能只需要几秒钟。
升级路径
在代码库上运行迁移助手以查找debounce
属性的示例。
v-model替换的lazy或numberParam属性
在lazy
和number
param 属性现在修饰,使其更清楚这意味着什么,而不是:
<input v-model="name" lazy>
<input v-model="age" type="number" number>
你会使用:
<input v-model.lazy="name">
<input v-model.number="age" type="number">
升级路径
在您的代码库上运行迁移助手以查找这些参数属性的示例。
删除v-model的value属性
v-model
不再关心内联value
属性的初始值。为了可预测性,它总是将 Vue 实例数据视为真相的来源。
这意味着这个元素:
<input v-model="text" value="foo">
这个数据支持:
data: {
text: 'bar'
}
将以“bar”而不是“foo”的值进行渲染。这同样适用于一个<textarea>与现有内容。代替:
<textarea v-model="text">
hello world
</textarea>
你应该确保你的初始值text
是“hello world”。
升级路径
升级后运行您的端到端测试套件或应用程序,并查找关于内联值属性v-model
的控制台警告
。
v-model with v-for Iterated Primitive Values removed
像这样的情况不再有效:
<input v-for="str in strings" v-model="str">
原因是这是<input>将编译为的等效 JavaScript :
strings.map(function (str) {
return createElement('input', ...)
})
正如你所看到的,v-model
双向绑定在这里没有意义。str
在迭代器函数中设置为另一个值将不会执行任何操作,因为它只是函数作用域中的局部变量。
相反,您应该使用一组对象,
以便v-model
可以更新对象上的字段。例如:
<input v-for="obj in objects" v-model="obj.str">
升级路径
运行你的测试套件,如果你有的话。在失败的测试
应该提醒您注意可能会受到这一更改的影响你的应用程序的任何部分。
带有对象语法的v-bind:style以及!important被删除
这将不再起作用:
<p v-bind:style="{ color: myColor + ' !important' }">hello</p>
如果您确实需要重写另一个!important
,则必须使用字符串语法:
<p v-bind:style="'color: ' + myColor + ' !important'">hello</p>
升级路径
在代码库上运行迁移助手以查找!important
对象中样式绑定的示例。
v-el和v-ref被取代
为了简单起见,v-el
并v-ref
已被合并到ref
属性中,可以通过组件实例访问$refs
。这意味着v-el:my-element
将成为ref="myElement"
和v-ref:my-component
将成为ref="myComponent"
。在正常元素上使用时,ref
将会是 DOM 元素,并且在组件上使用时,ref
将会是组件实例。
既然v-ref
不再是一个指令,而是一个特殊的属性,它也可以被动态定义。这与组合使用特别有用v-for
。例如:
<p v-for="item in items" v-bind:ref="'item' + item.id"></p>
之前,v-el
/ v-ref
与v-for
结合会产生一组元素/组件,因为没有办法给每个项目一个唯一的名称。您仍然可以通过赋予每个项目相同的方式ref
来实现此行为:
<p v-for="item in items" ref="items"></p>
与1.x不同,这些$refs
不是被动的,因为它们在渲染过程本身期间被注册/更新。使其处于被动状态需要对每次更改进行重复呈现。
另一方面,$refs
主要用于 JavaScript 中的程序化访问 - 不建议在模板中依赖它们,因为这意味着指的是不属于实例本身的状态。这会违反 Vue 的数据驱动视图模型。
升级路径
在您的代码库上运行迁移助手以查找v-el
和v-ref
的示例。
v-else与v-show被删除
v-else
不再适合与v-show
一起使用。v-if
改为使用否定表达式。例如,代替:
<p v-if="foo">Foo</p>
<p v-else v-show="bar">Not foo, but bar</p>
您可以使用:
<p v-if="foo">Foo</p>
<p v-if="!foo && bar">Not foo, but bar</p>
升级路径
在您的代码库上运行迁移助手以查找带有v-show
的v-else
的示例。
自定义指令简化
指令的责任范围大大缩小:它们现在仅用于应用低级别的直接 DOM 操作。在大多数情况下,您应该更喜欢使用组件作为主要代码重用抽象。
一些最显着的差异包括:
- 指令不再有实例。这意味着没有更多的
this
内部指令钩子。相反,他们会收到他们可能需要的一切参数。如果你真的必须坚持通过钩子状态,你可以这样做el
。
幸运的是,由于新指令更简单,您可以更轻松地掌握它们。阅读新的“自定义指令”指南以了解更多信息。
升级路径
在您的代码库上运行迁移助手以查找定义的指令的示例。助手会标记所有这些元素,因为在大多数情况下,您可能需要重构元素。
指令.literal修饰符被删除
该.literal
修饰符已被删除,因为通过提供字符串文字作为值可以轻松实现该修饰符。
例如,您可以更新:
<p v-my-directive.literal="foo bar baz"></p>
至:
<p v-my-directive="'foo bar baz'"></p>
升级路径
在您的代码库上运行迁移助手以查找.literal
指令中修饰符的示例。
转变
transition 属性被替换
Vue 的转换系统已经发生了巨大的变化,现在使用<transition>和<transition-group>包装元素,而不是transition属性。建议阅读新的 Transitions 指南以了解更多信息。
升级路径
在代码库上运行迁移助手以查找transition
属性的示例。
Vue.transition 为可重用转换取代
借助新的转换系统,您现在可以使用组件进行可重复使用的转换。
升级路径
在代码库上运行迁移助手以查找示例Vue.transition
。
转移stagger属性已删除
如果您需要错开列表转换,您可以通过设置和访问data-index
元素(或类似属性)来控制时间。在这里看到一个例子。
升级路径
在代码库上运行迁移助手以查找transition
属性的示例。在更新过程中,您可以将(非常有意的)转换为新的交错策略。
事件
events 选项已删除
该events
选项已被删除。事件处理程序现在应该在created
钩子中注册。退房$dispatch
和$broadcast
迁移指南进行了详细的例子。
Vue.directive('on').keyCodes 更换
新的,更简洁的配置方式keyCodes
是通过Vue.config.keyCodes
。例如:
// enable v-on:keyup.f1
Vue.config.keyCodes.f1 = 112
升级路径
在代码库上运行迁移助手以查找旧keyCode
配置语法的示例。
$dispatch和$broadcast被取代
$dispatch
和$broadcast
已被删除,以支持更明确的跨组件通信和更易维护的状态管理解决方案,如 Vuex 。
问题在于,当树变大时,依赖于组件树结构的事件流可能难以推理并且非常脆弱。它不能很好地扩展,我们不想让你以后疼痛。$dispatch
和$broadcast
也没有解决同级组件之间的通信。
这些方法最常见的用途之一是在父及其子之间直接进行沟通。在这些情况下,你实际上可以从带有v-on
的子处侦听$emit
。这使您可以更加明确地保持事件的便利性。
但是,当遥远的后代/上代进行交流时,$emit
不会帮助你。相反,最简单的升级可能是使用集中式事件中心。这还具有额外的好处,即允许您在组件树之间进行通信,无论它们在组件树中的哪个位置 - 即使是在兄弟之间!因为 Vue 实例实现了事件发射器接口,所以实际上可以为此使用一个空的 Vue 实例。
例如,假设我们有一个结构如下的待办应用程序:
Todos
|-- NewTodoInput
|-- Todo
|-- DeleteTodoButton
我们可以用这个单一事件中心管理组件之间的通信:
// This is the event hub we'll use in every
// component to communicate between them.
var eventHub = new Vue()
然后在我们的组件,我们可以使用$emit
,$on
,$off
分别发射事件,侦听事件,并清理事件侦听:
// NewTodoInput
// ...
methods: {
addTodo: function () {
eventHub.$emit('add-todo', { text: this.newTodoText })
this.newTodoText = ''
}
}
// DeleteTodoButton
// ...
methods: {
deleteTodo: function (id) {
eventHub.$emit('delete-todo', id)
}
}
// Todos
// ...
created: function () {
eventHub.$on('add-todo', this.addTodo)
eventHub.$on('delete-todo', this.deleteTodo)
},
// It's good to clean up event listeners before
// a component is destroyed.
beforeDestroy: function () {
eventHub.$off('add-todo', this.addTodo)
eventHub.$off('delete-todo', this.deleteTodo)
},
methods: {
addTodo: function (newTodo) {
this.todos.push(newTodo)
},
deleteTodo: function (todoId) {
this.todos = this.todos.filter(function (todo) {
return todo.id !== todoId
})
}
}
这种模式可以在简单的场景作为一个替代$dispatch
和$broadcast
,但对于更复杂的情况,建议使用专用的状态管理层如 Vuex 。
升级路径
在您的代码库上运行迁移助手以查找$dispatch
和$broadcast
的示例。
过滤器
滤除外部文本插入删除
过滤器现在只能在文本插值({{ }}
标签)中使用。在过去,我们已经指令,如内使用过滤器发现v-model
,v-on
等导致超过便捷的复杂性。对于列表过滤v-for
,最好将该逻辑作为计算属性移动到
JavaScript 中,以便它可以在整个组件中重用。
一般来说,只要在普通 JavaScript 中可以实现某些功能,我们就不希望引入像过滤器这样的特殊语法来照顾同样的问题。以下是您可以如何替换 Vue 的内置指令过滤器:
更换debounce过滤器
代替:
<input v-on:keyup="doStuff | debounce 500">
methods: {
doStuff: function () {
// ...
}
}
使用lodashdebounce
(或可能throttle
)直接限制调用昂贵的方法。你可以像上面这样达到同样的效果:
<input v-on:keyup="doStuff">
methods: {
doStuff: _.debounce(function () {
// ...
}, 500)
}
有关此策略的更多优点,请参阅此处的示例v-model
。
更换limitBy过滤器
代替:
<p v-for="item in items | limitBy 10">{{ item }}</p>
在计算属性中使用 JavaScript 的内置.slice
方法:
<p v-for="item in filteredItems">{{ item }}</p>
computed: {
filteredItems: function () {
return this.items.slice(0, 10)
}
}
更换filterBy过滤器
代替:
<p v-for="user in users | filterBy searchQuery in 'name'">{{ user.name }}</p>
在计算属性中使用 JavaScript 的内置.filter
方法:
<p v-for="user in filteredUsers">{{ user.name }}</p>
computed: {
filteredUsers: function () {
var self = this
return self.users.filter(function (user) {
return user.name.indexOf(self.searchQuery) !== -1
})
}
}
JavaScript 的本地.filter
还可以管理更复杂的过滤操作,因为您可以在计算属性中访问 JavaScript 的全部功能。例如,如果您想查找所有活动用户,并且不区分大小写地匹配他们的姓名和电子邮件地址:
var self = this
self.users.filter(function (user) {
var searchRegex = new RegExp(self.searchQuery, 'i')
return user.isActive && (
searchRegex.test(user.name) ||
searchRegex.test(user.email)
)
})
更换orderBy过滤器
代替:
<p v-for="user in users | orderBy 'name'">{{ user.name }}</p>
在计算属性中使用 lodashorderBy
(或可能sortBy
):
<p v-for="user in orderedUsers">{{ user.name }}</p>
computed: {
orderedUsers: function () {
return _.orderBy(this.users, 'name')
}
}
您甚至可以按多列排序:
_.orderBy(this.users, ['name', 'last_login'], ['asc', 'desc'])
升级路径
在代码库上运行迁移助手以查找指令内使用的过滤器示例。如果你错过了,你也应该看到控制台错误
。
过滤参数语法已更改
过滤器的参数语法现在更好地与 JavaScript 函数调用保持一致。因此,不要使用空格分隔的参数:
<p>{{ date | formatDate 'YY-MM-DD' timeZone }}</p>
我们用括号括住参数并用逗号分隔参数:
<p>{{ date | formatDate('YY-MM-DD', timeZone) }}</p>
升级路径
在您的代码库上运行迁移助手以查找旧的过滤器语法的示例。如果你错过了,你也应该看到控制台错误
。
内置的文本过滤器被删除
尽管文本插值内的滤镜仍然允许使用,但所有滤镜均已删除。相反,建议使用更专业的库来解决每个域中的问题(例如date-fns
格式化日期和accounting
货币)。
对于 Vue 的每个内置文本过滤器,我们都会经历如何在下面替换它们。示例代码可以存在于自定义帮助函数,方法或计算属性中。
更换json过滤器
您实际上不需要再进行调试,因为 Vue 会自动为您输出格式良好的输出,无论它是字符串,数字,数组还是普通对象。如果你需要与 JavaScript 完全相同的功能JSON.stringify
,那么你可以在方法或计算属性中使用它。
更换capitalize过滤器
text[0].toUpperCase() + text.slice(1)
更换uppercase过滤器
text.toUpperCase()
更换lowercase过滤器
text.toLowerCase()
更换pluralize过滤器
NPM 上的 pluralize 包很好地满足了这个目的,但是如果你只想复数化一个特定的单词或者想要针对某些情况进行特殊输出0
,那么你也可以很容易地定义你自己的复数函数。例如:
function pluralizeKnife (count) {
if (count === 0) {
return 'no knives'
} else if (count === 1) {
return '1 knife'
} else {
return count + 'knives'
}
}
更换currency过滤器
对于一个非常天真的实现,你可以做这样的事情:
'$' + price.toFixed(2)
虽然在很多情况下,你仍然会遇到奇怪的行为(例如,0.035.toFixed(2)
向上舍入为0.04
,但0.045
向下取整为0.04
)。要解决这些问题,您可以使用该accounting
库更可靠地格式化货币。
升级路径
在代码库上运行迁移助手以查找过时的文本过滤器的示例。如果你错过了,你也应该看到控制台错误
。
双向过滤器被替换
一些用户喜欢使用双向过滤器,v-model
以很少的代码创建有趣的输入。尽管看起来很
简单,但双向过滤器也可能隐藏很多复杂性 - 甚至通过延迟状态更新来鼓励糟糕的用户体验。相反,包装输入的组件被推荐为更加明确且功能丰富的创建自定义输入的方式。
举例来说,我们现在将介绍双向货币过滤器的迁移:
它大多运行良好,但延迟的状态更新可能会导致奇怪的行为。例如,点击Result
标签并尝试输入9.999
其中一个输入。当输入失去焦点时,其值将更新为$10.00
。然而,当查看计算出的总数时,您会看到这9.999
是我们数据中存储的数据。用户看到的现实版本不同步!
为了开始转向使用 Vue 2.0 的更强大的解决方案,我们首先将此过滤器包装在一个新<currency-input>组件中:
这允许我们添加一个单独的过滤器无法封装的行为,例如选择焦点上的输入内容。现在下一步将是从过滤器中提取业务逻辑。下面,我们把所有东西都拉到外部currencyValidator
对象中:
这种增加的模块化不仅使迁移到 Vue 2 变得更加容易,而且还允许货币解析和格式化:
- 单元与 Vue 代码隔离进行测试
有了这个验证器,我们也可以更轻松地将它构建成更强大的解决方案。状态怪异已被消除,用户实际上不可能输入任何错误,类似于浏览器的本机号码输入尝试执行的操作。
然而,我们仍然受限于过滤器和一般的 Vue 1.0,所以让我们完成升级到 Vue 2.0:
您可能会注意到:
- 我们输入的每个方面都更加明确,使用生命周期钩子和 DOM 事件代替双向过滤器的隐藏行为。
升级路径
在代码库上运行迁移助手以查找指令中使用的过滤器的示例v-model
。如果你错过了,你也应该看到控制台错误
。
Slots
删除重复的插槽
不再支持<slot>在同一模板中具有相同名称的s。当一个插槽被渲染时,它被“用完了”,并且不能在同一个渲染树的其他地方渲染。如果您必须在多个位置呈现相同的内容,请将该内容作为道具传递。
升级路径
升级后运行您的端到端测试套件或应用程序,并查找有关重复插槽的控制台警告
v-model
。
slot 属性样式已删除
通过 named 插入的内容<slot>不再保留slot属性。使用包装元素来设置它们的样式,或者对于高级用例,使用渲染函数以编程方式修改插入的内容。
升级路径
在您的代码库上运行迁移助手以查找以命名空位为目标的 CSS 选择器(例如[slot="my-slot-name"]
)。
特殊属性
keep-alive 属性被替换
keep-alive不再是一个特殊的属性,而是一个包装组件,类似于<transition>。例如:
<keep-alive>
<component v-bind:is="view"></component>
</keep-alive>
这使得<keep-alive>可以在多个条件的子上使用:
<keep-alive>
<todo-list v-if="todos.length > 0"></todo-list>
<no-todos-gif v-else></no-todos-gif>
</keep-alive>
当<keep-alive>有多个子时,他们最终应该评估一个子。第一个子以外的都会被忽略。
与<transition>一起使用时,请务必将其嵌入其中:
<transition>
<keep-alive>
<component v-bind:is="view"></component>
</keep-alive>
</transition>
升级路径
在代码库上运行迁移助手来查找keep-alive
属性。
插值
删除属性中的插值
属性内插不再有效。例如:
<button class="btn btn-{{ size }}"></button>
应该更新为使用内联表达式:
<button v-bind:class="'btn btn-' + size"></button>
或数据/计算属性:
<button v-bind:class="buttonClasses"></button>
computed: {
buttonClasses: function () {
return 'btn btn-' + size
}
}
升级路径
在代码库上运行迁移助手以查找属性中使用的插值示例。
删除了 HTML 插值
HTML 内插({{{ foo }}}
)已被删除,以支持该v-html
指令。
升级路径
运行代码库上的迁移助手来查找 HTML 插值。
一次性绑定取代
一次绑定({{* foo }}
)已被新v-once
指令取代。
升级路径
在您的代码库上运行迁移助手以查找一次性绑定。
反应
vm.$watch 改变
通过创建的观察者vm.$watch
现在在关联组件重新呈现之前被触发。这使您有机会在组件重新提交之前进一步更新状态,从而避免不必要的更新。例如,您可以观察组件 prop,并在 prop 改变时更新组件自己的数据。
如果您之前依靠在vm.$watch
组件更新后依靠 DOM 来执行某些操作,则可以在updated
生命周期钩子中这样做。
升级路径
运行你的端到端测试套件,如果你有的话。在失败的测试
应提醒你一个事实,即观察者是依靠旧的行为。
vm.$set 改变
vm.$set
现在是Vue.set
的别名。
升级路径
在您的代码库上运行迁移助手以查找过时用法的示例。
vm.$delete 改变
vm.$delete
现在是Vue.delete
的别名。
升级路径
在您的代码库上运行迁移助手以查找过时用法的示例。
Array.prototype.$set 删除
改为使用Vue.set
。
升级路径
在您的代码库上运行迁移助手以查找.$set
数组上的示例。如果你错过了,你应该从缺少的方法中看到控制台错误
。
Array.prototype.$remove 删除
改为使用Array.prototype.splice
。例如:
methods: {
removeTodo: function (todo) {
var index = this.todos.indexOf(todo)
this.todos.splice(index, 1)
}
}
或者更好的是,传递删除方法的索引:
methods: {
removeTodo: function (index) {
this.todos.splice(index, 1)
}
}
升级路径
在您的代码库上运行迁移助手以查找.$remove
数组上的示例。如果你错过了,你应该从缺少的方法中看到控制台错误
。
Vue.set和Vue.delete在 Vue 实例中删除
Vue.set
和Vue.delete
不能再处理 Vue 实例。现在必须正确声明数据选项中的所有顶级反应属性。如果您想要删除 Vue 实例或其实例的属性$data
,请将其设置为 null 。
升级路径
运行迁移助手在你的代码库找到的例子Vue.set
或Vue.delete
在 Vue 的实例。如果你错过了,他们会触发控制台警告
。
更换已移除的vm.$data
现在禁止替换组件实例的根 $data。这可以防止反应性系统中的一些边缘情况,并使组件状态更具可预测性(特别是对于类型检查系统)。
升级路径
在您的代码库上运行迁移助手以查找覆盖的示例vm.$data
。如果你错过了,控制台警告
将会发出。
vm.$get 删除
相反,直接检索反应数据。
升级路径
在代码库上运行迁移助手以查找示例vm.$get
。如果你错过了,你会看到控制台错误
。
基于 DOM 的实例方法
vm.$appendTo 删除
使用本地 DOM API:
myElement.appendChild(vm.$el)
升级路径
在代码库上运行迁移助手以查找示例vm.$appendTo
。如果你错过了,你会看到控制台错误
。
已移除的vm.$before
使用本地 DOM API:
myElement.parentNode.insertBefore(vm.$el, myElement)
升级路径
在代码库上运行迁移助手以查找示例vm.$before
。如果你错过了,你会看到控制台错误
。
已移除的vm.$after
使用本地 DOM API:
myElement.parentNode.insertBefore(vm.$el, myElement.nextSibling)
或者如果myElement
是最后一个子:
myElement.parentNode.appendChild(vm.$el)
升级路径
在代码库上运行迁移助手以查找示例vm.$after
。如果你错过了,你会看到控制台错误
。
已移除的vm.$remove
使用本地 DOM API:
vm.$el.remove()
升级路径
在代码库上运行迁移助手以查找示例vm.$remove
。如果你错过了,你会看到控制台错误
。
元实例方法
vm.$eval 去除
没有真正的用途。如果您碰巧依靠此功能,并且不确定如何解决此问题,请在论坛上发布想法。
升级路径
在代码库上运行迁移助手以查找示例vm.$eval
。如果你错过了,你会看到控制台错误
。
vm.$interpolate 去除
没有真正的用途。如果您碰巧依靠此功能,并且不确定如何解决此问题,请在论坛上发布想法。
升级路径
在代码库上运行迁移助手以查找示例vm.$interpolate
。如果你错过了,你会看到控制台错误
。
vm.$log 去除
使用 Vue Devtools 获得最佳的调试体验。
升级路径
在代码库上运行迁移助手以查找示例vm.$log
。如果你错过了,你会看到控制台错误
。
实例 DOM 选项
replace: false 去除
组件现在总是替换它们绑定的元素。要模拟其行为replace: false
,可以使用与要替换的元素类似的元素来包装根组件。例如:
new Vue{
el: '#app',
template: '<div id="app"> ... </div>'
})
或者使用渲染功能:
new Vue{
el: '#app',
render: function (h) {
h('div', {
attrs: {
id: 'app',
}
}, /* ... */)
}
})
升级路径
在代码库上运行迁移助手以查找示例replace: false
。
全局配置
Vue.config.debug 去除
不再需要,因为现在默认情况下警告会带有堆栈跟踪。
升级路径
在代码库上运行迁移助手以查找示例Vue.config.debug
。
Vue.config.async 去除
渲染性能现在需要异步。
升级路径
在代码库上运行迁移助手以查找示例Vue.config.async
。
Vue.config.delimiters 更换
这已被重新设计为组件级选项。这使您可以在应用程序内使用替代分隔符而不会破坏第三方组件。
升级路径
在代码库上运行迁移助手以查找示例Vue.config.delimiters
。
Vue.config.unsafeDelimiters 去除
HTML内插已被删除赞成v-html
。
升级路径
在代码库上运行迁移助手以查找示例Vue.config.unsafeDelimiters
。在此之后,助手还将找到 HTML 插值的实例,以便您可以替换它们v-html
。
全局 API
已去除el的Vue.extend
el选项不能再用于Vue.extend
。它仅作为实例创建选项有效。
升级路径
升级后运行您的端到端测试套件或应用程序,并查找有关该elVue.extend
选项的控制台警告
。
Vue.elementDirective 去除
改用组件。
升级路径
在代码库上运行迁移助手以查找示例Vue.elementDirective
。
Vue.partial 去除
部分已被删除,以支持使用道具的组件之间更明确的数据流。除非您在性能关键区域使用局部区域,否则建议使用正常组件。如果您动态绑定了name
某个部分,则可以使用动态组件。
如果您碰巧在应用程序的性能关键部分使用 partials,那么您应该升级到功能组件。它们必须处于普通的 JS / JSX 文件中(而不是.vue
文件中),并且是无状态和无实例的,就像部分一样。这使渲染速度非常快。
功能组件相对于部分功能的好处是它们可以更加动态,因为它们授予您访问 JavaScript 全部功能的权限。然而,这种能力是有成本的。如果以前从未使用过渲染函数的组件框架,则可能需要更长时间才能学习。
升级路径
在代码库上运行迁移助手以查找示例Vue.partial
。