## 一:自定義事件$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>
```