Vue.jsでのカスタムコンポーネント双方向データバインディング実装

カスタムコンポーネントの双方向バインディング

Vue.jsでは、カスタムコンポーネントに双方向データバインディングを実装するために、プロパティの受け渡しとイベントの発行を組み合わせて使用します。

プロパティによるデータ受け渡し

親コンポーネントから子コンポーネントへデータを渡すにはpropsを使用します:

props: {
    currentValue: {
        type: String,
        default: ''
    }
}

イベント発行によるデータ更新

子コンポーネントでは$emitメソッドを使用してイベントを発行します:

// 値なしでイベント発行
this.$emit('updateValue');

// 値付きでイベント発行  
this.$emit('updateValue', newData);

親コンポーネントではv-onディレクティブでイベントを監視します:

v-on:updateValue="handleValueUpdate"

methods: {
    handleValueUpdate(updatedValue) {
        // 値更新処理
    }
}

v-modelの仕組み

標準のinput要素におけるv-modelの動作:

<input v-model="searchText">

// 以下の糖衣構文と同等
<input 
    v-bind:value="searchText" 
    v-on:input="searchText = $event.target.value">

カスタムコンポーネントでのv-model動作:

<custom-component 
    v-bind:value="searchText" 
    v-on:input="searchText = $event">
</custom-component>

カスタムコンポーネント実装例

基本的なカスタム入力コンポーネント:

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>

カスタムプロパティとイベントの設定

標準のvalue/input以外を使用する場合:

model: {
    prop: 'selected',
    event: 'selectionChanged'
},
props: {
    selected: {
        type: String,
        default: ''
    }
}

実践例:地域コード選択コンポーネント

親コンポーネントでの使用:

<area-selector v-model="regionCode"></area-selector>

子コンポーネント実装:

<template>
    <select 
        v-model="internalValue" 
        @change="onSelectionChange">
        <option 
            v-for="option in options" 
            :key="option.id" 
            :value="option.id">
            {{ option.name }}
        </option>
    </select>
</template>

<script>
export default {
    name: "area-selector",
    model: {
        prop: "value",
        event: "change"
    },
    props: {
        value: {
            type: String,
            default: ''
        }
    },
    data() {
        return {
            internalValue: this.value,
            options: []
        };
    },
    watch: {
        value(newVal) {
            this.internalValue = newVal;
        }
    },
    methods: {
        onSelectionChange() {
            this.$emit('change', this.internalValue);
        }
    }
};
</script>

タグ: vue.js コンポーネント 双方向バインディング v-model カスタムイベント

7月19日 22:59 投稿