![]() |
还单身的镜子 · 《被禁止的历史》试读:42 ...· 5 月前 · |
![]() |
坐怀不乱的山羊 · 《西游》里的太上老君-中国吉林网· 9 月前 · |
![]() |
八块腹肌的牙膏 · Ansible用法—playbook(二)_ ...· 9 月前 · |
![]() |
要出家的火车 · 在Ubuntu系统中查看依赖库信息 – ...· 11 月前 · |
![]() |
有腹肌的扁豆 · 动漫《富士见二丁目交响乐团:寒冷前线的指挥官 ...· 1 年前 · |
Woah - this is a super long page! Does that mean 2.0 is completely different, I’ll have to learn the basics all over again, and migrating will be practically impossible?
I’m glad you asked! The answer is no. About 90% of the API is the same and the core concepts haven’t changed. It’s long because we like to offer very detailed explanations and include a lot of examples. Rest assured, this is not something you have to read from top to bottom!
Where should I start in a migration?
Start by running the migration helper on a current project. We’ve carefully minified and compressed a senior Vue dev into a simple command line interface. Whenever they recognize an obsolete feature, they’ll let you know, offer suggestions, and provide links to more info.
After that, browse through the table of contents for this page in the sidebar. If you see a topic you may be affected by, but the migration helper didn’t catch, check it out.
If you have any tests, run them and see what still fails. If you don’t have tests, just open the app in your browser and keep an eye out for warnings or errors as you navigate around.
By now, your app should be fully migrated. If you’re still hungry for more though, you can read the rest of this page - or dive in to the new and improved guide from the beginning . Many parts will be skimmable, since you’re already familiar with the core concepts.
How long will it take to migrate a Vue 1.x app to 2.0?
It depends on a few factors:
The size of your app (small to medium-sized apps will probably be less than a day)
How many times you get distracted and start playing with a cool new feature. 😉 Not judging, it also happened to us while building 2.0!
Which obsolete features you’re using. Most can be upgraded with find-and-replace, but others might take a few minutes. If you’re not currently following best practices, Vue 2.0 will also try harder to force you to. This is a good thing in the long run, but could also mean a significant (though possibly overdue) refactor.
If I upgrade to Vue 2, will I also have to upgrade Vuex and Vue Router?
Only Vue Router 2 is compatible with Vue 2, so yes, you’ll have to follow the migration path for Vue Router as well. Fortunately, most applications don’t have a lot of router code, so this likely won’t take more than an hour.
As for Vuex, even version 0.8 is compatible with Vue 2, so you’re not forced to upgrade. The only reason you may want to upgrade immediately is to take advantage of the new features in Vuex 2, such as modules and reduced boilerplate.
|
It’s recommended to wrap the entire contents in a new element, like this:
|
Run your end-to-end test suite or app after upgrading and look for console warnings about multiple root elements in a template.
beforeCompile
removed
Run the migration helper on your codebase to find all examples of this hook.
compiled
replaced
Use the new
mounted
hook instead.
Run the migration helper on your codebase to find all examples of this hook.
attached
removed
Use a custom in-DOM check in other hooks. For example, to replace:
|
You could use:
|
Run the migration helper on your codebase to find all examples of this hook.
detached
removed
Use a custom in-DOM check in other hooks. For example, to replace:
|
You could use:
|
Run the migration helper on your codebase to find all examples of this hook.
init
renamed
Run the migration helper on your codebase to find all examples of this hook.
ready
replaced
|
Run the migration helper on your codebase to find all examples of this hook.
v-for
v-for
Argument Order for Arrays
changed
Run the
migration helper
on your codebase to find examples of the obsolete argument order. Note that if you name your index arguments something unusual like
position
or
num
, the helper will not flag them.
v-for
Argument Order for Objects
changed
Run the
migration helper
on your codebase to find examples of the obsolete argument order. Note that if you name your key arguments something like
name
or
property
, the helper will not flag them.
$index
and
$key
removed
Run the
migration helper
on your codebase to find examples of these removed variables. If you miss any, you should also see
console errors
such as:
Uncaught ReferenceError: $index is not defined
track-by
replaced
|
You would now write:
|
Run the
migration helper
on your codebase to find examples of
track-by
.
v-for
Range Values
changed
Search your codebase for the regex
/\w+ in \d+/
. Wherever it appears in a
v-for
, check to see if you may be affected.
coerce
Prop Option
removed
|
You could write:
|
There are a few advantages:
Run the
migration helper
on your codebase to find examples of the
coerce
option.
twoWay
Prop Option
removed
Run the
migration helper
on your codebase to find examples of the
twoWay
option.
.once
and
.sync
Modifiers on
v-bind
removed
Run the
migration helper
on your codebase to find examples of the
.once
and
.sync
modifiers.
Most use cases of mutating a prop can be replaced by one of these options:
Run your end-to-end test suite or app after upgrading and look for console warnings about prop mutations.
Run your end-to-end test suite, if you have one. The failed tests should alert to you to the fact that props passed to root instances are no longer working.
cache: false
deprecated
For example:
|
Or with component methods:
|
Run the
migration helper
on your codebase to find examples of the
cache: false
option.
v-bind
changed
For enumerated attributes, in addition to the falsy values above, the string
"false"
will also render as
attr="false"
.
Note that for other directives (e.g.
v-if
and
v-show
), JavaScript’s normal truthiness still applies.
Run your end-to-end test suite, if you have one. The failed tests should alert to you to any parts of your app that may be affected by this change.
v-on
changed
|
Run your end-to-end test suite, if you have one. The failed tests should alert to you to any parts of your app that may be affected by this change.
debounce
Param Attribute for
v-model
removed
These limitations become apparent when designing a search indicator, like this one for example:
Using the
debounce
attribute, there’d be no way to detect the “Typing” state, because we lose access to the input’s real-time state. By decoupling the debounce function from Vue however, we’re able to debounce only the operation we want to limit, removing the limits on features we can develop:
|
|
Another advantage of this approach is there will be times when debouncing isn’t quite the right wrapper function. For example, when hitting an API for search suggestions, waiting to offer suggestions until after the user has stopped typing for a period of time isn’t an ideal experience. What you probably want instead is a
throttling
function. Now since you’re already using a utility library like lodash, refactoring to use its
throttle
function instead takes only a few seconds.
Run the
migration helper
on your codebase to find examples of the
debounce
attribute.
lazy
or
number
Param Attributes for
v-model
replaced
|
You would use:
|
Run the migration helper on your codebase to find examples of the these param attributes.
value
Attribute with
v-model
removed
That means this element:
|
backed by this data:
|
will render with a value of “bar” instead of “foo”. The same goes for a
<textarea>
with existing content. Instead of:
|
You should ensure your initial value for
text
is “hello world”.
Run your end-to-end test suite or app after upgrading and look for
console warnings
about inline value attributes with
v-model
.
v-model
with
v-for
Iterated Primitive Values
removed
Cases like this no longer work:
|
The reason is this is the equivalent JavaScript that the
<input>
would compile to:
|
As you can see,
v-model
‘s two-way binding doesn’t make sense here. Setting
str
to another value in the iterator function will do nothing because it’s only a local variable in the function scope.
Instead, you should use an array of
objects
so that
v-model
can update the field on the object. For example:
|
Run your test suite, if you have one. The failed tests should alert to you to any parts of your app that may be affected by this change.
v-bind:style
with Object Syntax and
!important
removed
|
If you really need to override another
!important
, you must use the string syntax:
|
Run the
migration helper
on your codebase to find examples of style bindings with
!important
in objects.
v-el
and
v-ref
replaced
Since
v-ref
is no longer a directive, but a special attribute, it can also be dynamically defined. This is especially useful in combination with
v-for
. For example:
|
Previously,
v-el
/
v-ref
combined with
v-for
would produce an array of elements/components, because there was no way to give each item a unique name. You can still achieve this behavior by giving each item the same
ref
:
|
Unlike in 1.x, these
$refs
are not reactive, because they’re registered/updated during the render process itself. Making them reactive would require duplicate renders for every change.
On the other hand,
$refs
are designed primarily for programmatic access in JavaScript - it is not recommended to rely on them in templates, because that would mean referring to state that does not belong to the instance itself. This would violate Vue’s data-driven view model.
Run the
migration helper
on your codebase to find examples of
v-el
and
v-ref
.
v-else
with
v-show
removed
|
You can use:
|
Run the
migration helper
on your codebase to find examples of the
v-else
with
v-show
.
Some of the most notable differences include:
this
inside directive hooks. Instead, they receive everything they might need as arguments. If you really must persist state across hooks, you can do so on
el
.
acceptStatement
,
deep
,
priority
, etc have all been removed. To replace
twoWay
directives, see
this example
.
Fortunately, since the new directives are much simpler, you can master them more easily. Read the new Custom Directives guide to learn more.
Run the migration helper on your codebase to find examples of defined directives. The helper will flag all of them, as it's likely in most cases that you'll want to refactor to a component.
.literal
Modifier
removed
For example, you can update:
|
|
Run the migration helper on your codebase to find examples of the `.literal` modifier on a directive.
transition
Attribute
replaced
Vue’s transition system has changed quite drastically and now uses
<transition>
and
<transition-group>
wrapper elements, rather than the
transition
attribute. It’s recommended to read the new
Transitions guide
to learn more.
Run the
migration helper
on your codebase to find examples of the
transition
attribute.
Vue.transition
for Reusable Transitions
replaced
With the new transition system, you can now use components for reusable transitions .
Run the
migration helper
on your codebase to find examples of
Vue.transition
.
stagger
Attribute
removed
If you need to stagger list transitions, you can control timing by setting and accessing a
data-index
(or similar attribute) on an element. See
an example here
.
Run the
migration helper
on your codebase to find examples of the
transition
attribute. During your update, you can transition (pun very much intended) to the new staggering strategy as well.
events
option
removed
The
events
option has been removed. Event handlers should now be registered in the
created
hook instead. Check out the
$dispatch
and
$broadcast
migration guide
for a detailed example.
Vue.directive('on').keyCodes
replaced
The new, more concise way to configure
keyCodes
is through
Vue.config.keyCodes
. For example:
|
Run the
migration helper
on your codebase to find examples of the the old
keyCode
configuration syntax.
$dispatch
and
$broadcast
replaced
$dispatch
and
$broadcast
have been removed in favor of more explicitly cross-component communication and more maintainable state management solutions, such as
Vuex
.
The problem is event flows that depend on a component’s tree structure can be hard to reason about and are very brittle when the tree becomes large. They don’t scale well and only set you up for pain later.
$dispatch
and
$broadcast
also do not solve communication between sibling components.
One of the most common uses for these methods is to communicate between a parent and its direct children. In these cases, you can actually
listen to an
$emit
from a child with
v-on
. This allows you to keep the convenience of events with added explicitness.
However, when communicating between distant descendants/ancestors,
$emit
won’t help you. Instead, the simplest possible upgrade would be to use a centralized event hub. This has the added benefit of allowing you to communicate between components no matter where they are in the component tree - even between siblings! Because Vue instances implement an event emitter interface, you can actually use an empty Vue instance for this purpose.
For example, let’s say we have a todo app structured like this:
|
We could manage communication between components with this single event hub:
|
Then in our components, we can use
$emit
,
$on
,
$off
to emit events, listen for events, and clean up event listeners, respectively:
|
|
|
This pattern can serve as a replacement for
$dispatch
and
$broadcast
in simple scenarios, but for more complex cases, it’s recommended to use a dedicated state management layer such as
Vuex
.
Run the
migration helper
on your codebase to find examples of
$dispatch
and
$broadcast
.
In general, whenever something can be achieved in plain JavaScript, we want to avoid introducing a special syntax like filters to take care of the same concern. Here’s how you can replace Vue’s built-in directive filters:
debounce
Filter
|
|
Use
lodash’s
debounce
(or possibly
throttle
) to directly limit calling the expensive method. You can achieve the same as above like this:
|
|
For more on the advantages of this strategy, see
the example here with
v-model
.
limitBy
Filter
|
Use JavaScript’s built-in
.slice
method
in a computed property:
|
|
filterBy
Filter
|
Use JavaScript’s built-in
.filter
method
in a computed property:
|
|
JavaScript’s native
.filter
can also manage much more complex filtering operations, because you have access to the full power of JavaScript within computed properties. For example, if you wanted to find all active users and case-insensitively match against both their name and email:
|
orderBy
Filter
|
Use
lodash’s
orderBy
(or possibly
sortBy
) in a computed property:
|
|
You can even order by multiple columns:
|
Run the migration helper on your codebase to find examples of filters being used inside directives. If you miss any, you should also see console errors .
|
We surround the arguments with parentheses and delimit the arguments with commas:
|
Run the migration helper on your codebase to find examples of the old filter syntax. If you miss any, you should also see console errors .
Although filters within text interpolations are still allowed, all of the filters have been removed. Instead, it’s recommended to use more specialized libraries for solving problems in each domain (e.g.
date-fns
to format dates and
accounting
for currencies).
For each of Vue’s built-in text filters, we go through how you can replace them below. The example code could exist in custom helper functions, methods, or computed properties.
json
Filter
capitalize
Filter
|
uppercase
Filter
|
lowercase
Filter
|
pluralize
Filter
The
pluralize
package on NPM serves this purpose nicely, but if you only want to pluralize a specific word or want to have special output for cases like
0
, then you can also easily define your own pluralize functions. For example:
|
currency
Filter
For a very naive implementation, you could do something like this:
|
In many cases though, you’ll still run into strange behavior (e.g.
0.035.toFixed(2)
rounds up to
0.04
, but
0.045
rounds down to
0.04
). To work around these issues, you can use the
accounting
library to more reliably format currencies.
Run the migration helper on your codebase to find examples of the obsolete text filters. If you miss any, you should also see console errors .
As an example, we’ll now walk the migration of a two-way currency filter:
It mostly works well, but the delayed state updates can cause strange behavior. For example, try entering
9.999
into one of those inputs. When the input loses focus, its value will update to
$10.00
. When looking at the calculated total however, you’ll see that
9.999
is what’s stored in our data. The version of reality that the user sees is out of sync!
To start transitioning towards a more robust solution using Vue 2.0, let’s first wrap this filter in a new
<currency-input>
component:
This allows us add behavior that a filter alone couldn’t encapsulate, such as selecting the content of an input on focus. Now the next step will be to extract the business logic from the filter. Below, we pull everything out into an external
currencyValidator
object
:
This increased modularity not only makes it easier to migrate to Vue 2, but also allows currency parsing and formatting to be:
Having this validator extracted out, we’ve also more comfortably built it up into a more robust solution. The state quirks have been eliminated and it’s actually impossible for users to enter anything wrong, similar to what the browser’s native number input tries to do.
We’re still limited however, by filters and by Vue 1.0 in general, so let’s complete the upgrade to Vue 2.0:
You may notice that:
v-model
directly on our custom inputs, which is not only more consistent with normal inputs, but also means our component is Vuex-friendly.
Run the
migration helper
on your codebase to find examples of filters used in directives like
v-model
. If you miss any, you should also see
console errors
.
Run your end-to-end test suite or app after upgrading and look for
console warnings
about duplicate slots
v-model
.
slot
Attribute Styling
removed
Content inserted via named
<slot>
no longer preserves the
slot
attribute. Use a wrapper element to style them, or for advanced use cases, modify the inserted content programmatically using
render functions
.
Run the
migration helper
on your codebase to find CSS selectors targeting named slots (e.g.
[slot="my-slot-name"]
).
keep-alive
Attribute
replaced
|
This makes it possible to use
<keep-alive>
on multiple conditional children:
|
When
<keep-alive>
has multiple children, they should eventually evaluate to a single child. Any child other than the first one will be ignored.
When used together with
<transition>
, make sure to nest it inside:
|
Run the
migration helper
on your codebase to find
keep-alive
attributes.
Interpolation within attributes is no longer valid. For example:
|
Should either be updated to use an inline expression:
|
Or a data/computed property:
|
|
Run the migration helper on your codebase to find examples of interpolation used within attributes.
HTML interpolations (
{{{ foo }}}
) have been removed in favor of the
v-html
directive
.
Run the migration helper on your codebase to find HTML interpolations.
One time bindings (
{{* foo }}
) have been replaced by the new
v-once
directive
.
Run the migration helper on your codebase to find one-time bindings.
vm.$watch
changed
If you were previously relying on
vm.$watch
to do something with the DOM after a component updates, you can instead do so in the
updated
lifecycle hook.
Run your end-to-end test suite, if you have one. The failed tests should alert to you to the fact that a watcher was relying on the old behavior.
vm.$set
changed
vm.$set
is now an alias for
Vue.set
.
Run the migration helper on your codebase to find examples of the obsolete usage.
vm.$delete
changed
vm.$delete
is now an alias for
Vue.delete
.
Run the migration helper on your codebase to find examples of the obsolete usage.
Array.prototype.$set
removed
Run the
migration helper
on your codebase to find examples of
.$set
on an array. If you miss any, you should see
console errors
from the missing method.
Array.prototype.$remove
removed
Use
Array.prototype.splice
instead. For example:
|
Or better yet, pass removal methods an index:
|
Run the
migration helper
on your codebase to find examples of
.$remove
on an array. If you miss any, you should see
console errors
from the missing method.
Vue.set
and
Vue.delete
on Vue instances
removed
Run the
migration helper
on your codebase to find examples of
Vue.set
or
Vue.delete
on a Vue instance. If you miss any, they'll trigger
console warnings
.
vm.$data
removed
Run the
migration helper
on your codebase to find examples of overwriting
vm.$data
. If you miss any,
console warnings
will be emitted.
vm.$get
removed
Instead, retrieve reactive data directly.
Run the
migration helper
on your codebase to find examples of
vm.$get
. If you miss any, you'll see
console errors
.
vm.$appendTo
removed
|
Run the
migration helper
on your codebase to find examples of
vm.$appendTo
. If you miss any, you'll see
console errors
.
vm.$before
removed
|
Run the
migration helper
on your codebase to find examples of
vm.$before
. If you miss any, you'll see
console errors
.
vm.$after
removed
|
Or if
myElement
is the last child:
|
Run the
migration helper
on your codebase to find examples of
vm.$after
. If you miss any, you'll see
console errors
.
vm.$remove
removed
|
Run the
migration helper
on your codebase to find examples of
vm.$remove
. If you miss any, you'll see
console errors
.
vm.$eval
removed
No real use. If you do happen to rely on this feature somehow and aren’t sure how to work around it, post on the forum for ideas.
Run the
migration helper
on your codebase to find examples of
vm.$eval
. If you miss any, you'll see
console errors
.
vm.$interpolate
removed
No real use. If you do happen to rely on this feature somehow and aren’t sure how to work around it, post on the forum for ideas.
Run the
migration helper
on your codebase to find examples of
vm.$interpolate
. If you miss any, you'll see
console errors
.
vm.$log
removed
Use the Vue Devtools for the optimal debugging experience.
Run the
migration helper
on your codebase to find examples of
vm.$log
. If you miss any, you'll see
console errors
.
replace: false
removed
|
Or with a render function:
|
Run the
migration helper
on your codebase to find examples of
replace: false
.
Vue.config.debug
removed
No longer necessary, since warnings come with stack traces by default now.
Run the
migration helper
on your codebase to find examples of
Vue.config.debug
.
Vue.config.async
removed
Async is now required for rendering performance.
Run the
migration helper
on your codebase to find examples of
Vue.config.async
.
Vue.config.delimiters
replaced
This has been reworked as a component-level option . This allows you to use alternative delimiters within your app without breaking 3rd-party components.
Run the
migration helper
on your codebase to find examples of
Vue.config.delimiters
.
Vue.config.unsafeDelimiters
removed
HTML interpolation has been
removed in favor of
v-html
.
Run the
migration helper
on your codebase to find examples of
Vue.config.unsafeDelimiters
. After this, the helper will also find instances of HTML interpolation so that you can replace them with `v-html`.
Vue.extend
with
el
removed
The el option can no longer be used in
Vue.extend
. It’s only valid as an instance creation option.
Run your end-to-end test suite or app after upgrading and look for
console warnings
about the
el
option with
Vue.extend
.
Vue.elementDirective
removed
Run the
migration helper
on your codebase to find examples of
Vue.elementDirective
.
Vue.partial
removed
Partials have been removed in favor of more explicit data flow between components, using props. Unless you’re using a partial in a performance-critical area, the recommendation is to use a
normal component
instead. If you were dynamically binding the
name
of a partial, you can use a
dynamic component
.
If you happen to be using partials in a performance-critical part of your app, then you should upgrade to
functional components
. They must be in a plain JS/JSX file (rather than in a
.vue
file) and are stateless and instanceless, like partials. This makes rendering extremely fast.
A benefit of functional components over partials is that they can be much more dynamic, because they grant you access to the full power of JavaScript. There is a cost to this power however. If you’ve never used a component framework with render functions before, they may take a bit longer to learn.
Run the
migration helper
on your codebase to find examples of
Vue.partial
.