From 7651f2ff0f204647de0c3469f5f0fb2bf84c2440 Mon Sep 17 00:00:00 2001 From: NataliaTepluhina Date: Sun, 12 Jul 2020 17:31:32 +0300 Subject: [PATCH 1/6] feat: added a v-model changes overview --- src/.vuepress/config.js | 3 ++- src/guide/migration/v-model.md | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/guide/migration/v-model.md diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js index b6bf6318bb..6de6410393 100644 --- a/src/.vuepress/config.js +++ b/src/.vuepress/config.js @@ -85,7 +85,8 @@ const sidebar = { children: [ 'migration/global-api', 'migration/treeshaking', - 'migration/functional-components' + 'migration/functional-components', + 'migration/v-model' ] }, { diff --git a/src/guide/migration/v-model.md b/src/guide/migration/v-model.md new file mode 100644 index 0000000000..ba9368def9 --- /dev/null +++ b/src/guide/migration/v-model.md @@ -0,0 +1,14 @@ +# Changes to `v-model` on custom components + +## Overview + +In terms of what has changed, at a high level: + +- **DEPRECATED:** `v-bind`'s `.sync` modifier is removed and replaced with an argument on `v-model`; +- Multiple `v-model` bindings on the same component are possible now; +- When used on custom components, `v-model` prop and event default names are changed: + - prop: `value` -> `modelValue`; + - event: `input` -> `update:modelValue`; +- Added a possibility to create custom `v-model` modifiers. + +For more information, read on! From 9d6b7b4a9fe1eea3e11e7212fb7229022b2f3871 Mon Sep 17 00:00:00 2001 From: NataliaTepluhina Date: Sun, 12 Jul 2020 18:37:44 +0300 Subject: [PATCH 2/6] feat: added separation for priority --- src/.vuepress/config.js | 24 ++++-- src/guide/migration/v-model.md | 150 ++++++++++++++++++++++++++++++++- 2 files changed, 166 insertions(+), 8 deletions(-) diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js index 6de6410393..7f4a6c7f5f 100644 --- a/src/.vuepress/config.js +++ b/src/.vuepress/config.js @@ -48,7 +48,11 @@ const sidebar = { children: [ { title: 'Reactivity', - children: ['/guide/reactivity', '/guide/reactivity-fundamentals', '/guide/reactivity-computed-watchers'] + children: [ + '/guide/reactivity', + '/guide/reactivity-fundamentals', + '/guide/reactivity-computed-watchers' + ] }, { title: 'Composition API', @@ -83,10 +87,20 @@ const sidebar = { title: 'Migration to Vue 3', collapsable: true, children: [ - 'migration/global-api', - 'migration/treeshaking', - 'migration/functional-components', - 'migration/v-model' + { + title: 'Critical', + collapsable: false, + children: [ + 'migration/global-api', + 'migration/treeshaking', + 'migration/v-model' + ] + }, + { + title: 'High', + collapsable: false, + children: ['migration/functional-components'] + } ] }, { diff --git a/src/guide/migration/v-model.md b/src/guide/migration/v-model.md index ba9368def9..bac00256c1 100644 --- a/src/guide/migration/v-model.md +++ b/src/guide/migration/v-model.md @@ -4,11 +4,155 @@ In terms of what has changed, at a high level: -- **DEPRECATED:** `v-bind`'s `.sync` modifier is removed and replaced with an argument on `v-model`; -- Multiple `v-model` bindings on the same component are possible now; - When used on custom components, `v-model` prop and event default names are changed: - prop: `value` -> `modelValue`; - event: `input` -> `update:modelValue`; -- Added a possibility to create custom `v-model` modifiers. +- Multiple `v-model` bindings on the same component are possible now; +- **DEPRECATED:** `v-bind`'s `.sync` modifier and component `model` option are removed and replaced with an argument on `v-model`; +- **NEW:** Added a possibility to create custom `v-model` modifiers. For more information, read on! + +## Introduction + +In Vue 2, `v-model="foo"` on components roughly compiled to the following: + +```js +h(Comp, { + value: foo, + onInput: value => { + foo = value + } +}) +``` + +However, this required the component to always use the `value` prop for binding with `v-model` when the component may want to expose the value prop for a different purpose. + +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. In practice we are seeing some components that need to sync multiple values, and the other values have to use `v-bind.sync`. We noticed that `v-model` and `v-bind.sync` are fundamentally doing the same thing and can be combined into a single construct by allowing `v-model` to accept arguments. + +## 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 `MyBook` component: + +```html + +``` + +```js +// MyBook.vue + +export default { + model: { + prop: 'readers', + event: 'change' + }, + props: { + // this allows using the `value` prop for a different purpose + value: String, + // use `checked` as the prop which take the place of `value` + readers: { + type: Number, + default: 0 + } + } +} +``` + +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 `MyBook` component from the previous example with the `readers` prop, we could communicate the intent of assigning a new value with: + +```js +this.$emit('update:readers', 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 + +Now, `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 `model` component option, now we can pass an _argument_ to `v-model`: + +```html + + + + + +``` + +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) From 3b3b9f1ae90b6451ae52ad0edc90d834e21f2710 Mon Sep 17 00:00:00 2001 From: NataliaTepluhina Date: Mon, 13 Jul 2020 15:55:02 +0300 Subject: [PATCH 3/6] fix: reverted categorization and fixed v-model --- src/.vuepress/config.js | 18 ++------ src/guide/migration.md | 55 ----------------------- src/guide/migration/v-model.md | 79 +++++++++++++++------------------- 3 files changed, 38 insertions(+), 114 deletions(-) diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js index 7f4a6c7f5f..c6c3b1e67e 100644 --- a/src/.vuepress/config.js +++ b/src/.vuepress/config.js @@ -87,20 +87,10 @@ const sidebar = { title: 'Migration to Vue 3', collapsable: true, children: [ - { - title: 'Critical', - collapsable: false, - children: [ - 'migration/global-api', - 'migration/treeshaking', - 'migration/v-model' - ] - }, - { - title: 'High', - collapsable: false, - children: ['migration/functional-components'] - } + 'migration/global-api', + 'migration/treeshaking', + 'migration/v-model', + 'migration/functional-components' ] }, { diff --git a/src/guide/migration.md b/src/guide/migration.md index 550c461aee..909c2e48ab 100644 --- a/src/guide/migration.md +++ b/src/guide/migration.md @@ -38,61 +38,6 @@ It depends on a few factors: [//]: # '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. - ## Custom Directives ### Custom Directive Lifecycle API diff --git a/src/guide/migration/v-model.md b/src/guide/migration/v-model.md index bac00256c1..9a0d8a3c64 100644 --- a/src/guide/migration/v-model.md +++ b/src/guide/migration/v-model.md @@ -15,54 +15,47 @@ For more information, read on! ## Introduction -In Vue 2, `v-model="foo"` on components roughly compiled to the following: +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. -```js -h(Comp, { - value: foo, - onInput: value => { - foo = value - } -}) -``` - -However, this required the component to always use the `value` prop for binding with `v-model` when the component may want to expose the value prop for a different purpose. +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. -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. In practice we are seeing some components that need to sync multiple values, and the other values have to use `v-bind.sync`. We noticed that `v-model` and `v-bind.sync` are fundamentally doing the same thing and can be combined into a single construct by allowing `v-model` to accept arguments. +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 `MyBook` component: +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 -// MyBook.vue +// ChildComponent.vue export default { model: { - prop: 'readers', + prop: 'title', event: 'change' }, props: { // this allows using the `value` prop for a different purpose value: String, - // use `checked` as the prop which take the place of `value` - readers: { - type: Number, - default: 0 + // use `title` as the prop which take the place of `value` + title: { + type: String, + default: 'Default title' } } } @@ -71,42 +64,39 @@ export default { 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 `MyBook` component from the previous example with the `readers` prop, we could communicate the intent of assigning a new value with: +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:readers', newValue) +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 -Now, `v-model` on the custom component is an equivalent of passing a `modelValue` prop and emitting an `update:modelValue` event: +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 @@ -114,28 +104,27 @@ Now, `v-model` on the custom component is an equivalent of passing a `modelValue To change a model name, instead of `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 - + - ``` @@ -144,7 +133,7 @@ This also serves as a replacement to `.sync` modifier and allows us to have mult 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. From b8b576dd46494f6a09d873c23346b4f121e07839 Mon Sep 17 00:00:00 2001 From: Natalia Tepluhina Date: Mon, 13 Jul 2020 15:55:56 +0300 Subject: [PATCH 4/6] Update src/guide/migration/v-model.md Co-authored-by: Ben Hong --- src/guide/migration/v-model.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/guide/migration/v-model.md b/src/guide/migration/v-model.md index 9a0d8a3c64..4c6a905c08 100644 --- a/src/guide/migration/v-model.md +++ b/src/guide/migration/v-model.md @@ -101,7 +101,7 @@ In v3 `v-model` on the custom component is an equivalent of passing a `modelValu ### `v-model` arguments -To change a model name, instead of `model` component option, now we can pass an _argument_ to `v-model`: +To change a model name, instead of a `model` component option, now we can pass an _argument_ to `v-model`: ```html From 67c22c5ad787e2c2d849ea6a5c053a481dc61ae8 Mon Sep 17 00:00:00 2001 From: Natalia Tepluhina Date: Mon, 13 Jul 2020 19:05:22 +0300 Subject: [PATCH 5/6] Update src/guide/migration/v-model.md Co-authored-by: Ben Hong --- src/guide/migration/v-model.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/guide/migration/v-model.md b/src/guide/migration/v-model.md index 4c6a905c08..b4bd077b6f 100644 --- a/src/guide/migration/v-model.md +++ b/src/guide/migration/v-model.md @@ -8,7 +8,7 @@ In terms of what has changed, at a high level: - prop: `value` -> `modelValue`; - event: `input` -> `update:modelValue`; - Multiple `v-model` bindings on the same component are possible now; -- **DEPRECATED:** `v-bind`'s `.sync` modifier and component `model` option are removed and replaced with an argument on `v-model`; +- **BREAKING:** `v-bind`'s `.sync` modifier and component `model` option are removed and replaced with an argument on `v-model`; - **NEW:** Added a possibility to create custom `v-model` modifiers. For more information, read on! From 53ca3cf13251e61b7fa3fe26d0d5853f5fcda6b4 Mon Sep 17 00:00:00 2001 From: Natalia Tepluhina Date: Mon, 13 Jul 2020 19:05:34 +0300 Subject: [PATCH 6/6] Update src/guide/migration/v-model.md Co-authored-by: Ben Hong --- src/guide/migration/v-model.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/guide/migration/v-model.md b/src/guide/migration/v-model.md index b4bd077b6f..fef5daf1e4 100644 --- a/src/guide/migration/v-model.md +++ b/src/guide/migration/v-model.md @@ -9,7 +9,7 @@ In terms of what has changed, at a high level: - 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 a possibility to create custom `v-model` modifiers. +- **NEW:** Added the ability to create custom `v-model` modifiers. For more information, read on!