【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>

 

posted @ 2022-04-11 15:18  翠微  阅读(570)  评论(0编辑  收藏  举报