diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js index 2b6e141773..af6106dce0 100644 --- a/src/.vuepress/config.js +++ b/src/.vuepress/config.js @@ -90,6 +90,7 @@ const sidebar = { 'migration', 'migration/global-api', 'migration/treeshaking', + 'migration/v-model', 'migration/functional-components', 'migration/async-components', 'migration/custom-directives' diff --git a/src/guide/migration.md b/src/guide/migration.md index a5979610df..397e854567 100644 --- a/src/guide/migration.md +++ b/src/guide/migration.md @@ -37,58 +37,3 @@ It depends on a few factors: > If I upgrade to Vue 3, will I also have to upgrade Vuex and Vue Router? [//]: # 'TODO: still need to see where this lands' - -## Built-in Directives - -### `v-model` API Change - -In Vue 2, the `v-model` directive required developers to always use the `value` prop. And if developers required different props for different purposes, they would have to resort to using `v-bind.sync`. In addition, this hard-coded relationship between `v-model` and `value` led to issues with how native elements and custom elements were handled. - -However, with Vue 3, the API for two-way data binding is being standardized in order to reduce confusion and to allow developers more flexibility with the `v-model` directive. - -Using v-model in Vue 3 -In Vue 3, by detaching the `v-model` from the `value` prop, developers now have the ability to pass arguments to `v-model` which will allow them to create multiple `v-model` bindings on a single component. - -```html - -``` - -#### Modifiers - -In Vue 2.x, hard-coded modifiers such as `.trim` on `v-model` were introduced to provide an intuitive way to solve common scenarios. However, - -[//]: # 'TODO: still need to finish, and perhaps add in caveats' - -### `v-model.sync` Replaced with `v-model` Argument - -In Vue 2, the `.sync` modifier was created in order to offer a shorthand way to create two-way data binding for a prop. For example, in the event we want a child component to update its own title property, we would have done something like this: - -**ChildComponent.vue** - -```html -this.$emit('onUpdate:title', newTitle) -``` - -**ParentComponent.vue** - -```html - -``` - -However, this led to some confusion since two-way data flow is closely tied to the `v-model` directive, whereas `v-bind` is normally used for one-way data flow for props. - -#### How to Sync Props in Vue 3 - -In Vue 3, we no longer need the `.sync` modifier anymore. Similar to how we can listen for changes to a form input value, Vue 3 allows us to perform "two way data binding" on props by allowing you to pass the prop as an argument to `v-model`. - -![v-bind anatomy](/images/v-bind-instead-of-sync.png) - -Using the example from before, it can now be simplified to: - -**ParentComponent.vue** - -```html - -``` - -By passing our prop title to the `v-model` directive, Vue will listen for an `onUpdate:title` event that will be emitted from the child component in order to update the data accordingly. diff --git a/src/guide/migration/v-model.md b/src/guide/migration/v-model.md new file mode 100644 index 0000000000..fef5daf1e4 --- /dev/null +++ b/src/guide/migration/v-model.md @@ -0,0 +1,147 @@ +# Changes to `v-model` on custom components + +## Overview + +In terms of what has changed, at a high level: + +- When used on custom components, `v-model` prop and event default names are changed: + - prop: `value` -> `modelValue`; + - event: `input` -> `update:modelValue`; +- Multiple `v-model` bindings on the same component are possible now; +- **BREAKING:** `v-bind`'s `.sync` modifier and component `model` option are removed and replaced with an argument on `v-model`; +- **NEW:** Added the ability to create custom `v-model` modifiers. + +For more information, read on! + +## Introduction + +In Vue 2, the `v-model` directive required developers to always use the `value` prop. And if developers required different props for different purposes, they would have to resort to using `v-bind.sync`. In addition, this hard-coded relationship between `v-model` and `value` led to issues with how native elements and custom elements were handled. + +In 2.2 we introduced the `model` component option that allows the component to customize the prop and event to use for `v-model`. However, this still only allowed a single `v-model` to be used on the component. + +With Vue 3, the API for two-way data binding is being standardized in order to reduce confusion and to allow developers more flexibility with the `v-model` directive. + +## Previous Syntax + +In v2, using a `v-model` on a component was an equivalent of passing a `value` prop and emitting an `input` event: + +```html + + + + + +``` + +If we wanted to change prop or event names to something different, we would need to add a `model` option to `ChildComponent` component: + +```html + + + +``` + +```js +// ChildComponent.vue + +export default { + model: { + prop: 'title', + event: 'change' + }, + props: { + // this allows using the `value` prop for a different purpose + value: String, + // use `title` as the prop which take the place of `value` + title: { + type: String, + default: 'Default title' + } + } +} +``` + +So, `v-model` in this case would be a shorthand to + +```html + +``` + +### Using `v-bind.sync` + +In some cases, we might need "two-way binding" for a prop (sometimes in addition to existing `v-model` for the different prop). To do so, we recommended emitting events in the pattern of `update:myPropName`. For example, for `ChildComponent` from the previous example with the `title` prop, we could communicate the intent of assigning a new value with: + +```js +this.$emit('update:title', newValue) +``` + +Then the parent could listen to that event and update a local data property, if it wants to. For example: + +```html + +``` + +For convenience, we had a shorthand for this pattern with the .sync modifier: + +```html + +``` + +## Current Syntax + +In v3 `v-model` on the custom component is an equivalent of passing a `modelValue` prop and emitting an `update:modelValue` event: + +```html + + + + + +``` + +### `v-model` arguments + +To change a model name, instead of a `model` component option, now we can pass an _argument_ to `v-model`: + +```html + + + + + +``` + +![v-bind anatomy](/images/v-bind-instead-of-sync.png) + +This also serves as a replacement to `.sync` modifier and allows us to have multiple `v-model`s on the custom component. + +```html + + + + + +``` + +### `v-model` modifiers + +In addition to v2 hard-coded `v-model` modifiers like `.trim`, now v3 supports custom modifiers: + +```html + +``` + +Read more about custom `v-model` modifiers in the [Custom Events](../component-custom-events.html#handling-v-model-modifiers) section. + +## Next Steps + +For more information on the new `v-model` syntax, see: + +- [Using `v-model` on Components](../component-basics.html#using-v-model-on-components) +- [`v-model` arguments](../component-custom-events.html#v-model-arguments) +- [Handling `v-model` modifiers](../component-custom-events.html#v-model-arguments)