【VUE】自定义组件数据双向绑定
自定义一个组件
通过 Prop 向子组件传递数据
props: { value: { type: String, default: '' } }
监听子组件事件
子组件可以通过调用内建的 $emit 方法,并传入事件名称来触发一个事件,父级组件就会接收该事件并作出处理
子组件抛出事件
$emit('yourEventName'); // 不传值
$emit('yourEventName', 'hello'); // 传值
父组件处理事件
v-on:yourEventName="doSomething"
doSomething(v) {
}
在组件上使用 v-model
先看 input 组件如何工作
<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 attribute 绑定到一个名叫 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>
问题:如果自定义组件不是一个 input 该如何,使用 model 定制 prop 和 event
model: { prop: 'checked', event: 'change' },
将 value 的事件重新定义为 change
一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框、下拉框等类型的输入控件可能会将 value 属性用于不同的目的,model 选项可以用来避免这样的冲突:
Vue.component('my-checkbox', { model: { prop: 'checked', event: 'change' }, props: { value: String, // 允许 value 属性用户其他目的 // 使用 checked 作为属性来取代 value 地方 checked: { type: Number, default: 0 } }, }) <my-checkbox v-model="foo" value="some value"></my-checkbox> 上述代码相当于: <my-checkbox :checked="foo" @change="val => { foo = val }" value="some value"></my-checkbox>
自定义组件例子
父组件
调用子组件,v-model 绑定
<area-code-select-element v-model="myCode"></area-code-select-element>
子组件
<template> <el-select v-model.trim="selectedCode" :size="btnSize" placeholder="区划编码" filterable clearable @change="selectChange"> <el-option v-for="item in list" :key="item.code" :label="item.codeText" :value="item.code"></el-option> </el-select> </template> <script> import {mapGetters} from 'vuex'; import { getDictionaryByIndexId } from "../../api/admin/dictionary"; export default { name: "area-code-select-element", model: { prop: "value", event: "change" }, props: { value: { type: String, default: '' }, disable: { type: Boolean, default: false } }, data() { return { list: [], selectedCode: undefined, } }, computed: { ...mapGetters([ 'btnSize' ]) }, watch: { value(newValue, oldValue) { console.log(`父组件值:${newValue}`); console.log(`子组件值:${this.selectedCode}`); } }, created() { this.loadDictionaryByIndexId(); }, methods: { loadDictionaryByIndexId() { this.list = []; getDictionaryByIndexId("area_code").then(response => { this.list = response.data; }); }, selectChange(value) { this.$emit('change', value); }, } } </script> <style scoped> </style>