🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 一:自定义事件$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> ```