From 21df49d619e5532470af0eae992898c16a8a48b6 Mon Sep 17 00:00:00 2001 From: ntepluhina Date: Wed, 5 Feb 2020 18:44:55 +0200 Subject: [PATCH 01/19] Fixed an example --- src/.vuepress/config.js | 6 +- src/guide/component-custom-events.md | 144 +++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 src/guide/component-custom-events.md diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js index 0cb889e6cc..aee406177d 100644 --- a/src/.vuepress/config.js +++ b/src/.vuepress/config.js @@ -46,7 +46,11 @@ module.exports = { { title: 'Components In-Depth', collapsable: true, - children: ['component-registration', 'component-props'] + children: [ + 'component-registration', + 'component-props', + 'component-custom-events' + ] } ] } diff --git a/src/guide/component-custom-events.md b/src/guide/component-custom-events.md new file mode 100644 index 0000000000..0ac723cc0e --- /dev/null +++ b/src/guide/component-custom-events.md @@ -0,0 +1,144 @@ +# Custom Events + +> This page assumes you've already read the [Components Basics](components.md). Read that first if you are new to components. + +## Event Names + +Unlike components and props, event names don't provide any automatic case transformation. Instead, the name of an emitted event must exactly match the name used to listen to that event. For example, if emitting a camelCased event name: + +```js +this.$emit('myEvent') +``` + +Listening to the kebab-cased version will have no effect: + +```html + + +``` + +Unlike components and props, event names will never be used as variable or property names in JavaScript, so there's no reason to use camelCase or PascalCase. Additionally, `v-on` event listeners inside DOM templates will be automatically transformed to lowercase (due to HTML's case-insensitivity), so `v-on:myEvent` would become `v-on:myevent` -- making `myEvent` impossible to listen to. + +For these reasons, we recommend you **always use kebab-case for event names**. + +## `v-model` arguments + +By default, `v-model` on a component uses `modelValue` as the prop and `update:modelValue` as the event. We can modify these names passing an argument to `v-model`: + +```html + +``` + +In this case, child component will expect a `foo` prop and emits `update:foo` event to sync: + +```js +const app = Vue.createApp({}) + +app.component('my-component', { + props: { + foo: String + }, + template: ` + + ` +}) +``` + +Note that this enables multiple v-model bindings on the same component, each syncing a different prop, without the need for extra options in the component: + +```html + +``` + +## Handling `v-model` modifiers + +In 2.x, we have hard-coded support for modifiers like `.trim` on component `v-model`. However, it would be more useful if the component can support custom modifiers. In 3.x, modifiers added to a component `v-model` will be provided to the component via the modelModifiers prop: + +```html + +``` + +```js +app.component('my-component', { + props: { + modelValue: String, + modelModifiers: { + default: () => ({}) + } + }, + template: ` + + `, + created() { + console.log(this.modelModifiers) // { capitalize: true } + } +}) +``` + +We can check `modelModifier` object keys and write a handler to change the emitted value. In the code below we will capitalize the string: + +```html +
+ + {{ myText }} +
+``` + +```js +const app = Vue.createApp({ + data() { + return { + myText: '' + } + } +}) + +app.component('my-component', { + props: { + modelValue: String, + modelModifiers: { + default: () => ({}) + } + }, + methods: { + emitValue(e) { + let value = e.target.value + if (this.modelModifiers.capitalize) { + value = value.charAt(0).toUpperCase() + value.slice(1) + } + this.$emit('update:modelValue', value) + } + }, + template: `` +}) + +app.mount('#app') +``` + +For `v-model` with arguments, the generated prop name will be `arg + "Modifiers"`: + +```html + +``` + +```js +app.component('my-component', { + props: ['foo', 'fooModifiers'], + template: ` + + `, + created() { + console.log(this.fooModifiers) // { capitalize: true } + } +}) +``` From fc03746b8432bedae6a7477d4aa9d486f2a83ad1 Mon Sep 17 00:00:00 2001 From: ntepluhina Date: Thu, 6 Feb 2020 20:36:18 +0200 Subject: [PATCH 02/19] feat: added component-slots --- src/.vuepress/config.js | 3 +- src/guide/component-slots.md | 439 +++++++++++++++++++++++++++++++++++ 2 files changed, 441 insertions(+), 1 deletion(-) create mode 100644 src/guide/component-slots.md diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js index aee406177d..df083364c3 100644 --- a/src/.vuepress/config.js +++ b/src/.vuepress/config.js @@ -49,7 +49,8 @@ module.exports = { children: [ 'component-registration', 'component-props', - 'component-custom-events' + 'component-custom-events', + 'component-slots' ] } ] diff --git a/src/guide/component-slots.md b/src/guide/component-slots.md new file mode 100644 index 0000000000..f46f5baa36 --- /dev/null +++ b/src/guide/component-slots.md @@ -0,0 +1,439 @@ +# Slots + +> This page assumes you've already read the [Components Basics](components.html). Read that first if you are new to components. + +## Slot Content + +Vue implements a content distribution API inspired by the [Web Components spec draft](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md), using the `` element to serve as distribution outlets for content. + +This allows you to compose components like this: + +```html + + Your Profile + +``` + +Then in the template for ``, you might have: + +```html + + + +``` + +When the component renders, `` will be replaced by "Your Profile". Slots can contain any template code, including HTML: + +```html + + + + Your Profile + +``` + +Or even other components: + +```html + + + + Your Profile + +``` + +If ``'s template did **not** contain a `` element, any content provided between its opening and closing tag would be discarded. + +## Compilation Scope + +When you want to use data inside a slot, such as in: + +```html + + Logged in as {{ user.name }} + +``` + +That slot has access to the same instance properties (i.e. the same "scope") as the rest of the template. The slot does **not** have access to ``'s scope. For example, trying to access `url` would not work: + +```html + + Clicking here will send you to: {{ url }} + + +``` + +As a rule, remember that: + +> Everything in the parent template is compiled in parent scope; everything in the child template is compiled in the child scope. + +## Fallback Content + +There are cases when it's useful to specify fallback (i.e. default) content for a slot, to be rendered only when no content is provided. For example, in a `` component: + +```html + +``` + +We might want the text "Submit" to be rendered inside the ` +``` + +Now when we use `` in a parent component, providing no content for the slot: + +```html + +``` + +will render the fallback content, "Submit": + +```html + +``` + +But if we provide content: + +```html + + Save + +``` + +Then the provided content will be rendered instead: + +```html + +``` + +## Named Slots + +There are times when it's useful to have multiple slots. For example, in a `` component with the following template: + +```html +
+
+ +
+
+ +
+
+ +
+
+``` + +For these cases, the `` element has a special attribute, `name`, which can be used to define additional slots: + +```html +
+
+ +
+
+ +
+
+ +
+
+``` + +A `` outlet without `name` implicitly has the name "default". + +To provide content to named slots, we can use the `v-slot` directive on a `