遇到了v-model綁定computed沒有反應的另一種做法
情境
最近在操作computed的時候,遇到一些很奇怪的狀況,而且官網也沒有特別說明,這邊主要是說明一下我遇到的坑在哪邊,我換成用什麼方式來實做的過程
首先我用一個很簡單的例子來示例這次我遇到的狀況,當我在父元件丟一個對象到子組件,為了不要讓子組件直接改這個props的時候,因為對象有reference的特性會有two way binding的效果,所以我用spread的方式來做出一個新的對象,先看一下程式碼示例。
父
<template>
<div>
<computed-example :data.sync="obj"></computed-example>
</div>
</template>
<script>
import ComputedExample from './ComputedExample.vue'
export default {
name: 'parent',
components: {
ComputedExample
},
data () {
return {
obj: {
one: 1
}
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
子
<template>
<div>
<input type="number" v-model.number="localData.one">
<input type="button" @click="submit" value="submit">
</div>
</template>
<script>
export default {
name: 'computedExample',
props: [
'data'
],
computed: {
localData: {
get () {
return this.data
}
}
},
methods: {
submit () {
console.log(this.localData)
}
}
}
</script>
<style>
</style>
原本會有two way binding的效果,可以看圖下示例
為了不要有two way binding導致的混亂狀況,所以我用spread來做一個pure object出來,結果原本點了值就馬上變的狀況,變成點完要離開焦點了,值才會變,感覺已經變得有點奇怪了
子
<template>
<div>
<input type="number" v-model.number="localData.one">
<input type="button" @click="submit" value="submit">
</div>
</template>
<script>
export default {
name: 'computedExample',
props: [
'data'
],
computed: {
localData: {
get () {
return { ...this.data } // 改成pure object
}
}
},
methods: {
submit () {
console.log(this.localData)
}
}
}
</script>
<style>
</style>
結果
接著因為我要改值的時候,再emit改回父元件的data,所以我就為computed加了set,卻發現當值改變的時候,完全沒有發生任何事情??
<template>
<div>
<input type="number" v-model.number="localData.one">
<input type="button" @click="submit" value="submit">
</div>
</template>
<script>
export default {
name: 'computedExample',
props: [
'data'
],
computed: {
localData: {
get () {
return { ...this.data }
},
// 加了set的部份
set (value) {
console.log(value)
this.$emit('update:data', value)
}
}
},
methods: {
submit () {
console.log(this.localData)
}
}
}
</script>
<style>
</style>
結果可以明顯看得出來,console.log沒有印出來,也沒有改回父元件的值啊
試著不用對象只用數值的話看看是否會正常
真的讓我想不透,所以我就把整個程式碼改成用data的方式,然後按submit的時候,再emit回去了,程式碼示例如下
子
<template>
<div>
<input type="number" v-model.number="localData.one">
<input type="button" @click="submit" value="submit">
</div>
</template>
<script>
export default {
name: 'computedExample',
props: [
'data'
],
data () {
return {
localData: { ...this.data }
}
},
methods: {
submit () {
this.$emit('update:data', this.localData)
}
}
}
</script>
<style>
</style>
結果
結論
雖然最後我改了寫法,也達成我的目的,但是我還是有點好奇為何使用對象,set會沒有反應,畢竟官方網站也沒有說到這方面的議題,而且以我的想法,我的屬性有任何改變,應該都要觸發set才對,如果有任何讀者知道原因的話,請告知我一下,感激不盡。