VueJs入门-custom component two way binding

这次想说一下自定义组件的赋值问题。
为了在画面中使用日期选择,导入了vue-calendar,示例代码如下:

<v-date-picker v-model="dateValue">
    <template v-slot="{ inputValue, inputEvents }">
        <input class="bg-white border px-2 py-1 rounded"
        :value="inputValue" v-on="inputEvents" 
        />
    </template>
</v-date-picker>

因为需要使用的地方有多处,所以打算把它做成一个自定义组件。

<template>
    <v-date-picker v-model="dateValue">
        <template v-slot="{ inputValue, inputEvents }">
            <input class="bg-white border px-2 py-1 rounded"
            :value="inputValue" v-on="inputEvents"
            />
        </template>
    </v-date-picker>
</template>

<script>
export default {
    props: {
        value: Date
    },
    data() {
        return {
            dateValue: this.value
        }
    }
}
</script>

然后,在view界面就可以通过下面的方式使用了:

<calendar v-model="date"></calendar>

这里说一下,component 里面,为什么要把value和dateValue分开,因为给component赋值的时候,只能通过props进行赋值。如果赋值完需要更新的话,就必须使用data或者compute进行绑定。不然的话,就会爆出下面的错误:

mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"

上面的组件的写法,可以实现父到子之间的赋值传递,但是子组件里的值改变的时候,不会跟父组件进行联动。为了实现子组件到组件的赋值联动,还需要加上下面这么一段:

watch: {
    dateValue: function(val) {
        console.log('value changed:' + val)
        this.$emit('input', val)
    }
}

子组件的值改变的时候,通过watch检测出来,然后执行 this.$emit(‘input’, val), 这段代码需要解释一下,下面两种方式作用其实是相同的。

<calendar v-model="date"></calendar>
<calendar v-bind:value="date" v-on:input="data = $event.target.value"></calendar> 
// By default, v-model on a component uses value as the prop and input as the event (from VueJs Official Document)

在子组件执行 this.$emit(‘input’, val) ,其实是触发了父组件的input event。这样就可以把值传递会去了。

所以,总结一下就是,父→子之间通过props进行传值,然后子→父通过$emit进行传值。
最后,完整的示例代码如下:

<template>
    <v-date-picker v-model="dateValue">
        <template v-slot="{ inputValue, inputEvents }">
            <input class="bg-white border px-2 py-1 rounded"
            :value="inputValue" v-on="inputEvents"
            />
        </template>
    </v-date-picker>
</template>

<script>
export default {
    props: {
        value: Date
    },
    data() {
        return {
            dateValue: this.value
        }
    },
    watch: {
        dateValue: function(val) {
            console.log('value changed:' + val)
            this.$emit('input', val)
        }
    }
}
</script>

参考文章:
https://jp.vuejs.org/v2/guide/components-custom-events.html
https://vcalendar.io/datepicker.html
https://recruit.cct-inc.co.jp/tecblog/vue-js/vue-emit-props/

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Close Bitnami banner
Bitnami