## 一:自定义事件$emit
```
this.$emit('事件名','传递的数据')
//例如定义了一个onChange事件,并且传递了一个数组
this.$emit('onChange',[0,1,2,3,4])
```
## 二:自定义组件的`v-model`
```
<input v-model="searchText">
```
等价于:
```
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
```
当用在组件上时,`v-model`则会这样:
```
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
```
为了让它正常工作,这个组件内的`<input>`必须:
* 将其`value`特性绑定到一个名叫`value`的 prop 上
* 在其`input`事件被触发时,将新的值通过自定义的`input`事件抛出
写成代码之后是这样的:
~~~
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
~~~
现在`v-model`就应该可以在这个组件上完美地工作起来了:
~~~
<custom-input v-model="searchText"></custom-input>
~~~
## 三:绑定原生事件到组件
在组件的根元素绑定原生事件,只需要使用`v-on`的`.native`修饰符:
```
<base-input v-on:focus.native="onFocus"></base-input>
```
但是当组件的根元素不具备一些DOM事件,但是根元素内部元素具备相对应的DOM事件,那么可以使用$listeners获取父组件传递进来的所有事件函数,再通过v-on="xxxx"绑定到相对应的内部元素上即可。
```
<base-input v-model="name" v-on:click.native="click" v-on:focus="focus" ></base-input>
```
因为`base-input`的根元素是一个`label`元素,所以默认情况下使用`v-on:focus`是无效的,所以需要配合`$listeners`使用,该属性可以把事件的监听指向组件中某个特定的元素
> 注意:如果父级的事件添加了.native修饰符,在$listeners中不会体现出来的
```
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
computed: {
inputListeners: function () {
var vm = this
// `Object.assign` 将所有的对象合并为一个新对象
return Object.assign({},
// 我们从父级添加所有的监听器
this.$listeners,
// 然后我们添加自定义监听器,
// 或覆写一些监听器的行为
{
// 这里确保组件配合 `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" //focus事件将会作用于input元素
>
</label>
`
})
```
## 四:`.sync` 修饰符
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。
这也是为什么我们推荐以`update:myPropName`的模式触发事件取而代之。举个例子,在一个包含`title`prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:
> update:myPropName的形式是指自定义事件名为`update:属性名称`
~~~,
this.$emit('update:title', newTitle)
~~~
然后父组件可以监听那个事件并根据需要更新一个本地的数据属性。例如:
~~~
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
~~~
为了方便起见,我们为这种模式提供一个缩写,即`.sync`修饰符:
~~~
<text-document v-bind:title.sync="doc.title"></text-document>
~~~
**使用`.sync`修饰符实现"双向绑定"需要满足以下条件**
* 在子组件中需要使用`update:myPropName`的形式定义自定义事件,例如:
~~~,
this.$emit('update:title', newTitle)
~~~
* 在父组件中使用`:title.sync="title"`的形式,无需在传入`title`这个Porp
```
<text-document v-bind:title.sync="doc.title"></text-document>
```