Skip to content

Moving Components Page into its Own Category #1482

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 42 commits into from
Mar 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
b5cd524
create components sidebar
sdras Mar 10, 2018
38ae34c
break up first two sections
sdras Mar 10, 2018
c816498
break it up further
sdras Mar 10, 2018
0a228f5
split up the rest
sdras Mar 10, 2018
12a4b9c
clean up
sdras Mar 10, 2018
7a42b83
initial pass, creating new, much slimmer components intro page that l…
chrisvfritz Mar 12, 2018
65d65c0
finish initial component registration page
chrisvfritz Mar 13, 2018
81f60f2
finish initial refactor of component props page
chrisvfritz Mar 14, 2018
e8ab0ec
beginning work on components custom events page
chrisvfritz Mar 14, 2018
594b1d0
finish initial components custom events page
chrisvfritz Mar 14, 2018
7905383
finish initial components slots page
chrisvfritz Mar 15, 2018
e63512c
finish initial dynamic and async components page
chrisvfritz Mar 15, 2018
8389490
finish initial dynamic-async and edge-cases components pages
chrisvfritz Mar 16, 2018
3f9d882
components review and tweaks up to the props page
chrisvfritz Mar 17, 2018
c37c9d0
fix components mistakes found by @phanan
chrisvfritz Mar 17, 2018
4fae206
fix typo in components-edge-cases
chrisvfritz Mar 17, 2018
c1af324
reorder Compiliation Scope in components-slots
chrisvfritz Mar 17, 2018
57ee320
fix link in components basics
chrisvfritz Mar 17, 2018
c329098
fix codeblock language typo in components
chrisvfritz Mar 17, 2018
60e5c25
add example of local registration in es2015 modules
chrisvfritz Mar 17, 2018
349247c
add keep-alive example
chrisvfritz Mar 17, 2018
4301124
remove redundant word in components
chrisvfritz Mar 17, 2018
512d8cc
make dom template parsing caveats h2
chrisvfritz Mar 17, 2018
869e4dd
change simple example to base example in components
chrisvfritz Mar 17, 2018
ce9b9e9
add async import example to circular references
chrisvfritz Mar 17, 2018
40731be
fix typo in components-custom-events
chrisvfritz Mar 18, 2018
070bfb8
remove redundand language in componenents-custom-events
chrisvfritz Mar 18, 2018
f7ee91c
add missing comma in components-custom-events
chrisvfritz Mar 18, 2018
1db36a0
restate context in component-dynamic-async
chrisvfritz Mar 18, 2018
7901ad1
remove redundant actuallys in components-dynamic-async
chrisvfritz Mar 18, 2018
e3d6f7d
clarify .sync modifier usage
chrisvfritz Mar 19, 2018
1d90cba
set up hash redirects for all old components sections
chrisvfritz Mar 19, 2018
ed09a59
remove note about intentional single root elements
chrisvfritz Mar 22, 2018
62b6cdf
fix dom template parsing caveats example
chrisvfritz Mar 22, 2018
6ccbbe6
fix closing </code> tags in components-edge-cases
chrisvfritz Mar 22, 2018
062afe3
fix typo in components-edge-cases
chrisvfritz Mar 22, 2018
7194e29
fix typo in components-edge-cases
chrisvfritz Mar 22, 2018
f858355
remove extra 'a' in components-registration
chrisvfritz Mar 22, 2018
59ec1e4
add name casing and various tweaks to components-registration
chrisvfritz Mar 23, 2018
b398f94
complete custom v-model example in components-custom-events
chrisvfritz Mar 23, 2018
ab0b0f5
minor tweaks to components pages
chrisvfritz Mar 23, 2018
0d06bd3
rename signature to definition for clarity
chrisvfritz Mar 23, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,3 @@ alias:
examples/svg.html: v2/examples/svg.html
examples/todomvc.html: v2/examples/todomvc.html
examples/tree-view.html: v2/examples/tree-view.html

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vuejs.org",
"private": true,
"hexo": {
"version": "3.4.2"
"version": "3.6.0"
},
"scripts": {
"start": "hexo server",
Expand Down
2 changes: 1 addition & 1 deletion src/v2/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1426,7 +1426,7 @@ type: api

- **Details:**

Contains parent-scope `v-on` event listeners (without `.native` modifiers). This can be passed down to an inner component via `v-on="$listeners"` - useful when creating higher-order components.
Contains parent-scope `v-on` event listeners (without `.native` modifiers). This can be passed down to an inner component via `v-on="$listeners"` - useful when creating transparent wrapper components.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we've talked about this before, are we all ok with transparent wrapper instead of higher-order? I think higher-order is more commonly used so it's possible it will be understood much faster by people learning, but I could go both ways on it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this different from an HOC? The definition used by React is:

a function that takes a component and returns a new component

This is a component rather than a function and it returns raw elements rather than a new component.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily, from the same document just a paragraph lower:

a higher-order component transforms a component into another component.

Having worked with both, I'm not sure I'd make such a distinction, but if you think that it's helpful for understanding, I'm all for it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please correct me if I'm still missing something, 😅 but I don't think this scenario fits that definition either though. Inside this component, we're wrapping a specific element to create a custom version of it, rather than wrapping or transforming a component. Does that make sense?

(Btw, I do agree with you that we should mention the vocabulary of HOCs when we use that pattern, I'm just not sure this is an example of it.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good!


## Instance Methods / Data

Expand Down
168 changes: 168 additions & 0 deletions src/v2/guide/components-custom-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
title: Custom Events
type: guide
order: 103
---

> This page assumes you've already read the [Components Basics](components.html). 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
<my-component v-on:my-event="doSomething"></my-component>
```

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**.

## Customizing Component `v-model`

> New in 2.2.0+

By default, `v-model` on a component uses `value` as the prop and `input` as the event, but some input types such as checkboxes and radio buttons may want to use the `value` attribute for a [different purpose](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#Value). Using the `model` option can avoid a conflict in such cases:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can avoid a conflict in such cases

The indefinite article "a" is unnecessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to leave this in actually, because while many dialects of English would allow omitting the "a", I think it would sound strange in American English.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About to say the same. How is "a" unnecessary?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@znck can correct me if I'm wrong, but I think in Indian English it's more common, and even in American English there will be no article in some contexts. For example, "there was conflict between two countries."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, in American English, omitting the a in this case would sound strange.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I often (read: almost always) rely on Grammarly for this, and it seems to dislike omitting the article in @chrisvfritz's example:

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phanan 👍 for Grammarly - great tool! I do disagree with it sometimes though. 😄 I think this is a phrase people use on the news quite often.


```js
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.value)"
>
`
})
```

Now when using `v-model` on this component:

```js
<base-checkbox v-model="lovingVue"></base-checkbox>
```

the value of `lovingVue` will be passed to the `checked` prop. The `lovingVue` property will then be updated when `<base-checkbox>` emits a `change` event with a new value.

<p class="tip">Note that you still have to declare the <code>checked</code> prop in component's <code>props</code> option.</p>

## Binding Native Events to Components

There may be times when you want to listen directly to a native event on the root element of a component. In these cases, you can use the `.native` modifier for `v-on`:

```html
<base-input v-on:focus.native="onFocus"></base-input>
```

This can be useful sometimes, but it's not a good idea when you're trying to listen on a very specific element, like an `<input>`. For example, the `<base-input>` component above might refactor so that the root element is actually a `<label>` element:

```html
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
```

In that case, the `.native` listener in the parent would silently break. There would be no errors, but the `onFocus` handler wouldn't be called when we expected it to.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There would be no errors, but the onFocus handler wouldn't be called when we expected it to.

Can we simplify this statement?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, nothing is coming to mind, but I'm definitely open to suggestions!


To solve this problem, Vue provides a `$listeners` property containing an object of listeners being used on the component. For example:

```js
{
focus: function (event) { /* ... */ }
input: function (value) { /* ... */ },
}
```

Using the `$listeners` property, you can forward all event listeners on the component to a specific child element with `v-on="$listeners"`. For elements like `<input>`, that you also want to work with `v-model`, it's often useful to create a new computed property for listeners, like `inputListeners` below:

```js
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
computed: {
inputListeners: function () {
var vm = this
// `Object.assign` merges objects together to form a new object
return Object.assign({},
// We add all the listeners from the parent
this.$listeners,
// Then we can add custom listeners or override the
// behavior of some listeners.
{
// This ensures that the component works with v-model
input: function (event) {
vm.$emit('input', event.target.value)
}
}
)
}
},
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on="inputListeners"
>
</label>
`
})
```

Now the `<base-input>` component is a **fully transparent wrapper**, meaning it can be used exactly like a normal `<input>` element: all the same attributes and listeners will work.

## `.sync` Modifier

> New in 2.3.0+

In some cases, we may need "two-way binding" for a prop. Unfortunately, true two-way binding can create maintenance issues, because child components can mutate the parent without the source of that mutation being obvious in both the parent and the child.

That's why instead, we recommend emitting events in the pattern of `update:my-prop-name`. For example, in a hypothetical component with a `title` prop, we could communicate the intent of assigning a new value with:

```js
this.$emit('update:title', newTitle)
```

Then the parent can listen to that event and update a local data property, if it wants to. For example:

```html
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
```

For convenience, we offer a shorthand for this pattern with the `.sync` modifier:

```html
<text-document v-bind:title.sync="doc.title"></text-document>
```

The `.sync` modifier can also be used with `v-bind` when using an object to set multiple props at once:

```html
<text-document v-bind.sync="doc"></text-document>
```

This passes each property in the `doc` object (e.g. `title`) as an individual prop, then adds `v-on` update listeners for each one.

<p class="tip">Using <code>v-bind.sync</code> with a literal object, such as in <code>v-bind.sync="{ title: doc.title }"</code>, will not work. If you want to include multiple, unrelated data properties in the same <code>v-bind.sync</code>, we recommend creating a computed property that returns an object.</p>
Loading