Перейти к русской документации для v3.x.

Эта документация для версий v2.x и ранее. Для v3.x, документация на русском здесь.

Миграция с Vue 1.x

ЧАВО

Ого! - это длиииииинная страница! Значит ли это, что 2.0 - совсем другая, снова будет нужно всему учиться, а миграция будет практически невозможной?

Хорошо, что спросили! Ответ — нет. Около 90% API осталось тем же, основные концепции не изменились. А длинная страничка просто потому, что мы хотим максимально подробно объяснить все детали и привести много примеров. И уж точно не предполагается что кто-то будет читать эту страницу от начала до конца!

С чего мне начать миграцию?

  1. Начните с запуска migration helper в текущем проекте. Мы тщательно минимизировали и скомпилировали сложные Vue разработки в простой интерфейс командной строки. Всякий раз, когда они признают устаревшую функцию, они сообщат вам, выдадут предложения и предоставят ссылки на дополнительную информацию.

  2. После этого просмотрите оглавление этой страницы на боковой панели. Если вы видите тему, проблема которой может повлиять на вас, но помощник по миграции не поймал её - проверьте её.

  3. Если у вас есть какие-либо тесты, запустите их и посмотрите, какие из них не проходят. Если у вас нет тестов, просто откройте приложение в своём браузере и следите за предупреждениями или ошибками при навигации по нему.

  4. К настоящему времени ваше приложение должно быть полностью перенесено. Если вы всё ещё голодны и хотите больше, то вы можете прочитать остальную часть этой страницы - или просто погрузиться в новое и улучшенное руководство с начала. Многие части можно будет прочесть бегло, поскольку вы уже знакомы с основными понятиями.

Сколько времени потребуется, чтобы перенести приложение 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>

Как обновлять

Запустите ваше end-to-end тестирование или приложение после обновления и проверьте предупреждения консоли о множестве корневых элементов в шаблоне.

Хуки жизненного цикла

beforeCompile удалён

Вместо этого используйте created в вашем компоненте.

Как обновлять

Запустите миграционного помощника в вашем проекте, чтобы найти все примеры использования этого хука.

compiled заменён

Вместо этого используйте новый хук mounted.

Как обновлять

Запустите миграционного помощника в вашем проекте, чтобы найти все примеры использования этого хука.

attached удалён

Используйте пользовательскую проверку DOM в других хуках. Например, чтобы заменить:

attached: function () {
doSomething()
}

Вы можете использовать:

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

Как обновлять

Запустите миграционного помощника в вашем проекте, чтобы найти все примеры использования этого хука.

detached удалён

Используйте пользовательскую проверку DOM в других хуках. Например, чтобы заменить:

detached: function () {
doSomething()
}

Вы можете использовать:

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

Как обновлять

Запустите миграционного помощника в вашем проекте, чтобы найти все примеры использования этого хука.

init переименован

Вместо этого используйте новый хук beforeCreate, который фактически ничем не отличается. Данный хук был переименован для логической взаимосвязи с другими методами жизненного цикла.

Как обновлять

Запустите миграционного помощника в вашем проекте, чтобы найти все примеры использования этого хука.

ready заменён

Вместо этого используйте новый хук mounted. Однако, следует отметить, что использование хука mounted не даёт гарантии существования в документе. Для этого также используйте Vue.nextTick/vm.$nextTick. Например:

mounted: function () {
this.$nextTick(function () {
// код, уже предполагающий наличие this.$el в документе
})
}

Как обновлять

Запустите миграционного помощника в вашем проекте, чтобы найти все примеры использования этого хука.

v-for

Очерёдность аргументов для массивов в v-for изменено

При использовании index очерёдность аргументов для массивов выглядела так (index, value). Теперь она имеет вид (value, index), чтобы не противоречить нативным методам массивов JavaScript, таким как forEach и map.

Как обновлять

Запустите миграционного помощника в вашем проекте, чтобы найти примеры устаревших очерёдностей аргументов. Обратите внимание: если вы дали нестандартное наименование индексу аргументов как position или num, помощник не выделит их.

Очерёдность аргументов для объектов в v-for изменено

При использовании имени свойства/ключа очерёдность аргументов для объектов выглядела так (name, value). Теперь она имеет вид (value, name), чтобы не противоречить распространённым итераторам объекта, таким как 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 Option удалён

If you want to coerce a prop, setup a local computed value based on it instead. For example, instead of:

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

You could write:

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

There are a few advantages:

Как обновлять

Запустите migration helper on your codebase to find examples of the coerce option.

twoWay Prop Option удалён

Props are now always one-way down. To produce side effects in the parent scope, a component needs to explicitly emit an event instead of relying on implicit binding. For more information, see:

Как обновлять

Запустите migration helper on your codebase to find examples of the twoWay option.

.once and .sync Modifiers on v-bind удалён

Props are now always one-way down. To produce side effects in the parent scope, a component needs to explicitly emit an event instead of relying on implicit binding. For more information, see:

Как обновлять

Запустите migration helper on your codebase to find examples of the .once and .sync modifiers.

Prop Mutation deprecated

Mutating a prop locally is now considered an anti-pattern, e.g. declaring a prop and then setting this.myProp = 'someOtherValue' in the component. Due to the new rendering mechanism, whenever the parent component re-renders, the child component’s local changes will be overwritten.

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.

Props on a Root Instance заменён

On root Vue instances (i.e. instances created with new Vue({ ... })), you must use propsData instead of props.

Как обновлять

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.

Computed properties

cache: false deprecated

Caching invalidation of computed properties will be removed in future major versions of Vue. Replace any uncached computed properties with methods, which will have the same result.

For example:

template: '<p>message: {{ timeMessage }}</p>',
computed: {
timeMessage: {
cache: false,
get: function () {
return Date.now() + this.message
}
}
}

Or with component methods:

template: '<p>message: {{ getTimeMessage() }}</p>',
methods: {
getTimeMessage: function () {
return Date.now() + this.message
}
}

Как обновлять

Запустите migration helper on your codebase to find examples of the cache: false option.

Built-In Directives

Truthiness/Falsiness with v-bind changed

When used with v-bind, the only falsy values are now: null, undefined, and false. This means 0 and empty strings will render as truthy. So for example, v-bind:draggable="''" will render as draggable="true".

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.

Listening for Native Events on Components with v-on changed

When used on a component, v-on now only listens to custom events $emitted by that component. To listen for a native DOM event on the root element, you can use the .native modifier. For example:

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

Как обновлять

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 удалён

Debouncing is used to limit how often we execute Ajax requests and other expensive operations. Vue’s debounce attribute parameter for v-model made this easy for very simple cases, but it actually debounced state updates rather than the expensive operations themselves. It’s a subtle difference, but it comes with limitations as an application grows.

These limitations become apparent when designing a search indicator, like this one for example:

{{ searchIndicator }}

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:

<!--
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)
}
})

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.

Как обновлять

Запустите migration helper on your codebase to find examples of the debounce attribute.

lazy or number Param Attributes for v-model заменён

The lazy and number param attributes are now modifiers, to make it more clear what That means instead of:

<input v-model="name" lazy>
<input v-model="age" type="number" number>

You would use:

<input v-model.lazy="name">
<input v-model.number="age" type="number">

Как обновлять

Запустите migration helper on your codebase to find examples of the these param attributes.

value Attribute with v-model удалён

v-model no longer cares about the initial value of an inline value attribute. For predictability, it will instead always treat the Vue instance data as the source of truth.

That means this element:

<input v-model="text" value="foo">

backed by this data:

data: {
text: 'bar'
}

will render with a value of “bar” instead of “foo”. The same goes for a <textarea> with existing content. Instead of:

<textarea v-model="text">
hello world
</textarea>

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 удалён

Cases like this no longer work:

<input v-for="str in strings" v-model="str">

The reason is this is the equivalent JavaScript that the <input> would compile to:

strings.map(function (str) {
return createElement('input', ...)
})

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:

<input v-for="obj in objects" v-model="obj.str">

Как обновлять

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 удалён

This will no longer work:

<p v-bind:style="{ color: myColor + ' !important' }">hello</p>

If you really need to override another !important, you must use the string syntax:

<p v-bind:style="'color: ' + myColor + ' !important'">hello</p>

Как обновлять

Запустите migration helper on your codebase to find examples of style bindings with !important in objects.

v-el and v-ref заменён

For simplicity, v-el and v-ref have been merged into the ref attribute, accessible on a component instance via $refs. That means v-el:my-element would become ref="myElement" and v-ref:my-component would become ref="myComponent". When used on a normal element, the ref will be the DOM element, and when used on a component, the ref will be the component instance.

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:

<p v-for="item in items" v-bind:ref="'item' + item.id"></p>

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 given each item the same ref:

<p v-for="item in items" ref="items"></p>

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.

Как обновлять

Запустите migration helper on your codebase to find examples of v-el and v-ref.

v-else with v-show удалён

v-else no longer works with v-show. Use v-if with a negation expression instead. For example, instead of:

<p v-if="foo">Foo</p>
<p v-else v-show="bar">Not foo, but bar</p>

You can use:

<p v-if="foo">Foo</p>
<p v-if="!foo && bar">Not foo, but bar</p>

Как обновлять

Запустите migration helper on your codebase to find examples of the v-else with v-show.

Пользовательские Директивы упрощены

Directives have a greatly reduced scope of responsibility: they are now only used for applying low-level direct DOM manipulations. In most cases, you should prefer using components as the main code-reuse abstraction.

Some of the most notable differences include:

Fortunately, since the new directives are much simpler, you can master them more easily. Read the new Custom Directives guide to learn more.

Как обновлять

Запустите 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.

Directive .literal Modifier удалён

The .literal modifier has been removed, as the same can be easily achieved by providing a string literal as the value.

For example, you can update:

<p v-my-directive.literal="foo bar baz"></p>

to:

<p v-my-directive="'foo bar baz'"></p>

Как обновлять

Запустите migration helper on your codebase to find examples of the `.literal` modifier on a directive.

Transitions

transition Attribute заменён

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.

Как обновлять

Запустите migration helper on your codebase to find examples of the transition attribute.

Vue.transition for Reusable Transitions заменён

With the new transition system, you can now use components for reusable transitions.

Как обновлять

Запустите migration helper on your codebase to find examples of Vue.transition.

Transition stagger Attribute удалён

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.

Как обновлять

Запустите 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

events option удалён

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 заменён

The new, more concise way to configure keyCodes is through Vue.config.keyCodes. For example:

// enable v-on:keyup.f1
Vue.config.keyCodes.f1 = 112

Как обновлять

Запустите migration helper on your codebase to find examples of the the old keyCode configuration syntax.

$dispatch and $broadcast заменён

$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:

Todos
├─ NewTodoInput
└─ Todo
└─ DeleteTodoButton

We could manage communication between components with this single event hub:

// This is the event hub we'll use in every
// component to communicate between them.
var eventHub = new Vue()

Then in our components, we can use $emit, $on, $off to emit events, listen for events, and clean up event listeners, respectively:

// 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
})
}
}

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.

Как обновлять

Запустите migration helper on your codebase to find examples of $dispatch and $broadcast.

Filters

Filters Outside Text Interpolations удалён

Filters can now only be used inside text interpolations ({{ }} tags). In the past we’ve found using filters within directives such as v-model, v-on, etc led to more complexity than convenience. For list filtering on v-for, it’s also better to move that logic into JavaScript as computed properties, so that it can be reused throughout your component.

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:

Replacing the debounce Filter

Instead of:

<input v-on:keyup="doStuff | debounce 500">
methods: {
doStuff: function () {
// ...
}
}

Use lodash’s debounce (or possibly throttle) to directly limit calling the expensive method. You can achieve the same as above like this:

<input v-on:keyup="doStuff">
methods: {
doStuff: _.debounce(function () {
// ...
}, 500)
}

For more on the advantages of this strategy, see the example here with v-model.

Replacing the limitBy Filter

Instead of:

<p v-for="item in items | limitBy 10">{{ item }}</p>

Use JavaScript’s built-in .slice method in a computed property:

<p v-for="item in filteredItems">{{ item }}</p>
computed: {
filteredItems: function () {
return this.items.slice(0, 10)
}
}

Replacing the filterBy Filter

Instead of:

<p v-for="user in users | filterBy searchQuery in 'name'">{{ user.name }}</p>

Use JavaScript’s built-in .filter method in a computed property:

<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’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:

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)
)
})

Replacing the orderBy Filter

Instead of:

<p v-for="user in users | orderBy 'name'">{{ user.name }}</p>

Use lodash’s orderBy (or possibly sortBy) in a computed property:

<p v-for="user in orderedUsers">{{ user.name }}</p>
computed: {
orderedUsers: function () {
return _.orderBy(this.users, 'name')
}
}

You can even order by multiple columns:

_.orderBy(this.users, ['name', 'last_login'], ['asc', 'desc'])

Как обновлять

Запустите migration helper on your codebase to find examples of filters being used inside directives. If you miss any, you should also see console errors.

Filter Argument Syntax changed

Filters’ syntax for arguments now better aligns with JavaScript function invocation. So instead of taking space-delimited arguments:

<p>{{ date | formatDate 'YY-MM-DD' timeZone }}</p>

We surround the arguments with parentheses and delimit the arguments with commas:

<p>{{ date | formatDate('YY-MM-DD', timeZone) }}</p>

Как обновлять

Запустите migration helper on your codebase to find examples of the old filter syntax. If you miss any, you should also see console errors.

Built-In Text Filters удалён

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.

Replacing the json Filter

You actually don’t need to for debugging anymore, as Vue will nicely format output for you automatically, whether it’s a string, number, array, or plain object. If you want the exact same functionality as JavaScript’s JSON.stringify though, then you can use that in a method or computed property.

Replacing the capitalize Filter

text[0].toUpperCase() + text.slice(1)

Replacing the uppercase Filter

text.toUpperCase()

Replacing the lowercase Filter

text.toLowerCase()

Replacing the 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:

function pluralizeKnife (count) {
if (count === 0) {
return 'no knives'
} else if (count === 1) {
return '1 knife'
} else {
return count + 'knives'
}
}

Replacing the currency Filter

For a very naive implementation, you could do something like this:

'$' + price.toFixed(2)

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.

Как обновлять

Запустите migration helper on your codebase to find examples of the obsolete text filters. If you miss any, you should also see console errors.

Two-Way Filters заменён

Some users have enjoyed using two-way filters with v-model to create interesting inputs with very little code. While seemingly simple however, two-way filters can also hide a great deal of complexity - and even encourage poor UX by delaying state updates. Instead, components wrapping an input are recommended as a more explicit and feature-rich way of creating custom inputs.

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:

Как обновлять

Запустите 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.

Slots

Duplicate Slots удалён

It is no longer supported to have <slot>s with the same name in the same template. When a slot is rendered it is “used up” and cannot be rendered elsewhere in the same render tree. If you must render the same content in multiple places, pass that content as a prop.

Как обновлять

Run your end-to-end test suite or app after upgrading and look for console warnings about duplicate slots v-model.

slot Attribute Styling удалён

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.

Как обновлять

Запустите migration helper on your codebase to find CSS selectors targeting named slots (e.g. [slot="my-slot-name"]).

Special Attributes

keep-alive Attribute заменён

keep-alive is no longer a special attribute, but rather a wrapper component, similar to <transition>. For example:

<keep-alive>
<component v-bind:is="view"></component>
</keep-alive>

This makes it possible to use <keep-alive> on multiple conditional children:

<keep-alive>
<todo-list v-if="todos.length > 0"></todo-list>
<no-todos-gif v-else></no-todos-gif>
</keep-alive>

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:

<transition>
<keep-alive>
<component v-bind:is="view"></component>
</keep-alive>
</transition>

Как обновлять

Запустите migration helper on your codebase to find keep-alive attributes.

Interpolation

Interpolation within Attributes удалён

Interpolation within attributes is no longer valid. For example:

<button class="btn btn-{{ size }}"></button>

Should either be updated to use an inline expression:

<button v-bind:class="'btn btn-' + size"></button>

Or a data/computed property:

<button v-bind:class="buttonClasses"></button>
computed: {
buttonClasses: function () {
return 'btn btn-' + size
}
}

Как обновлять

Запустите migration helper on your codebase to find examples of interpolation used within attributes.

HTML Interpolation удалён

HTML interpolations ({{{ foo }}}) have been removed in favor of the v-html directive.

Как обновлять

Запустите migration helper on your codebase to find HTML interpolations.

One-Time Bindings заменён

One time bindings ({{* foo }}) have been replaced by the new v-once directive.

Как обновлять

Запустите migration helper on your codebase to find one-time bindings.

Reactivity

vm.$watch changed

Watchers created via vm.$watch are now fired before the associated component rerenders. This gives you the chance to further update state before the component rerender, thus avoiding unnecessary updates. For example, you can watch a component prop and update the component’s own data when the prop changes.

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.

Как обновлять

Запустите migration helper on your codebase to find examples of the obsolete usage.

vm.$delete changed

vm.$delete is now an alias for Vue.delete.

Как обновлять

Запустите migration helper on your codebase to find examples of the obsolete usage.

Array.prototype.$set удалён

Use Vue.set instead.

Как обновлять

Запустите 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 удалён

Use Array.prototype.splice instead. For example:

methods: {
removeTodo: function (todo) {
var index = this.todos.indexOf(todo)
this.todos.splice(index, 1)
}
}

Or better yet, pass removal methods an index:

methods: {
removeTodo: function (index) {
this.todos.splice(index, 1)
}
}

Как обновлять

Запустите 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 удалён

Vue.set and Vue.delete can no longer work on Vue instances. It is now mandatory to properly declare all top-level reactive properties in the data option. If you’d like to delete properties on a Vue instance or its $data, set it to null.

Как обновлять

Запустите 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.

Replacing vm.$data удалён

It is now prohibited to replace a component instance’s root $data. This prevents some edge cases in the reactivity system and makes the component state more predictable (especially with type-checking systems).

Как обновлять

Запустите migration helper on your codebase to find examples of overwriting vm.$data. If you miss any, console warnings will be emitted.

vm.$get удалён

Instead, retrieve reactive data directly.

Как обновлять

Запустите migration helper on your codebase to find examples of vm.$get. If you miss any, you'll see console errors.

DOM-Focused Instance Methods

vm.$appendTo удалён

Use the native DOM API:

myElement.appendChild(vm.$el)

Как обновлять

Запустите migration helper on your codebase to find examples of vm.$appendTo. If you miss any, you'll see console errors.

vm.$before удалён

Use the native DOM API:

myElement.parentNode.insertBefore(vm.$el, myElement)

Как обновлять

Запустите migration helper on your codebase to find examples of vm.$before. If you miss any, you'll see console errors.

vm.$after удалён

Use the native DOM API:

myElement.parentNode.insertBefore(vm.$el, myElement.nextSibling)

Or if myElement is the last child:

myElement.parentNode.appendChild(vm.$el)

Как обновлять

Запустите migration helper on your codebase to find examples of vm.$after. If you miss any, you'll see console errors.

vm.$remove удалён

Use the native DOM API:

vm.$el.remove()

Как обновлять

Запустите migration helper on your codebase to find examples of vm.$remove. If you miss any, you'll see console errors.

Meta Instance Methods

vm.$eval удалён

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.

Как обновлять

Запустите migration helper on your codebase to find examples of vm.$eval. If you miss any, you'll see console errors.

vm.$interpolate удалён

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.

Как обновлять

Запустите migration helper on your codebase to find examples of vm.$interpolate. If you miss any, you'll see console errors.

vm.$log удалён

Use the Vue Devtools for the optimal debugging experience.

Как обновлять

Запустите migration helper on your codebase to find examples of vm.$log. If you miss any, you'll see console errors.

Instance DOM Options

replace: false удалён

Components now always replace the element they’re bound to. To simulate the behavior of replace: false, you can wrap your root component with an element similar to the one you’re replacing. For example:

new Vue({
el: '#app',
template: '<div id="app"> ... </div>'
})

Or with a render function:

new Vue({
el: '#app',
render: function (h) {
h('div', {
attrs: {
id: 'app',
}
}, /* ... */)
}
})

Как обновлять

Запустите migration helper on your codebase to find examples of replace: false.

Global Config

Vue.config.debug удалён

No longer necessary, since warnings come with stack traces by default now.

Как обновлять

Запустите migration helper on your codebase to find examples of Vue.config.debug.

Vue.config.async удалён

Async is now required for rendering performance.

Как обновлять

Запустите migration helper on your codebase to find examples of Vue.config.async.

Vue.config.delimiters заменён

This has been reworked as a component-level option. This allows you to use alternative delimiters within your app without breaking 3rd-party components.

Как обновлять

Запустите migration helper on your codebase to find examples of Vue.config.delimiters.

Vue.config.unsafeDelimiters удалён

HTML interpolation has been removed in favor of v-html.

Как обновлять

Запустите 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`.

Global API

Vue.extend with el удалён

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 удалён

Use components instead.

Как обновлять

Запустите migration helper on your codebase to find examples of Vue.elementDirective.

Vue.partial удалён

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.

Как обновлять

Запустите migration helper on your codebase to find examples of Vue.partial.