溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Vue中不通過v-model怎么實現(xiàn)雙向綁定

發(fā)布時間:2022-02-07 09:39:42 來源:億速云 閱讀:802 作者:iii 欄目:編程語言

本文小編為大家詳細(xì)介紹“Vue中不通過v-model怎么實現(xiàn)雙向綁定”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Vue中不通過v-model怎么實現(xiàn)雙向綁定”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。

Vue中不通過v-model怎么實現(xiàn)雙向綁定

先來看解答:

<template>
  <div class="test-v-model">
    <p>使用v-model</p>
    <input v-model="msg" placeholder="edit me" />
    <p>{{ msg }}</p>

    <p>不使用v-model</p>
    <input :value="msg1" @input="handleInput" placeholder="edit me" />
    <p>{{ msg1 }}</p>
  </div>
</template>

<script>
export default {
  name: 'test-v-model',
  data() {
    return {
      msg: '',
      msg1: ''
    }
  },
  methods: {
    handleInput(e) {
      this.msg1 = e.target.value
    }
  }
}
</script>

不使用 v-model,就需要通過 value 屬性綁定值和 input 事件改變綁定值來實現(xiàn)雙向綁定。

換句話說,v-model只是一種簡寫形式而已

事實上,v-model 的本質(zhì)就是語法糖,它負(fù)責(zé)監(jiān)聽用戶的輸入事件以更新數(shù)據(jù),并對一些極端場景進行一些特殊處理。 -- 官方文檔

v-model 在內(nèi)部為不同的輸入元素使用不同的 property 并拋出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;

  • checkbox 和 radio 使用 checked property 和 change 事件;

  • select 字段將 value 作為 prop 并將 change 作為事件。

與本題相關(guān)聯(lián)的知識延伸

  • 雙向綁定

  • 單向數(shù)據(jù)綁定

  • vue 組件之間交互的單向數(shù)據(jù)流

問:什么是雙向綁定?

雙向綁定就是當(dāng)數(shù)據(jù)變化之后,視圖同步更新,當(dāng)視圖變化之后,數(shù)據(jù)也會更新。

問:什么是單向數(shù)據(jù)綁定?

單向數(shù)據(jù)綁定就是當(dāng)數(shù)據(jù)變化之后,視圖同步更新,當(dāng)視圖變化之后,數(shù)據(jù)不會更新。

在vue中是通過指令 v-model 來實現(xiàn)雙向綁定,通過 v-bind 來實現(xiàn)單向數(shù)據(jù)綁定

看完下面這段代碼和這段代碼運行的gif演示,你就能明白他們的區(qū)別了。

<template>
  <div>
    <p>雙向綁定</p>
    <input v-model="msg" placeholder="edit me" />
    <p>{{ msg }}</p>

    <p>單向數(shù)據(jù)綁定</p>
    <input v-bind:value="msg1" placeholder="edit me" />
    <p>{{ msg1 }}</p>
  </div>
</template>

<script>
export default {
  name: 'test-v-model',
  data() {
    return {
      msg: '',
      msg1: ''
    }
  }
}
</script>

Vue中不通過v-model怎么實現(xiàn)雙向綁定

從gif圖中可以看出,使用 v-model,當(dāng)數(shù)據(jù)變化之后,視圖同步更新,當(dāng)視圖變化之后,數(shù)據(jù)也會更新,這就是雙向綁定。

使用 v-bind,當(dāng)數(shù)據(jù)變化之后,視圖同步更新,當(dāng)視圖變化之后,數(shù)據(jù)不會更新,這就是單向數(shù)據(jù)綁定。

問:什么是 vue 單向數(shù)據(jù)流?

子組件不能改變父組件傳遞給它的 prop 屬性,推薦的做法是它拋出事件,通知父組件自行改變綁定的值。
總結(jié)起來就是數(shù)據(jù)向下,事件向上。

vue 文檔在介紹 Prop 時就提出了單向數(shù)據(jù)流的概念,點擊此處 查看 vue 文檔對單向數(shù)據(jù)流的說明。

所有的 prop 都使得其父子 prop 之間形成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,但是反過來則不行。這樣會防止從子組件意外變更父級組件的狀態(tài),從而導(dǎo)致你的應(yīng)用的數(shù)據(jù)流向難以理解。

額外的,每次父級組件發(fā)生變更時,子組件中所有的 prop 都將會刷新為最新的值。這意味著你應(yīng)該在一個子組件內(nèi)部改變 prop。如果你這樣做了,Vue 會在瀏覽器的控制臺中發(fā)出警告。

我們看下面這個例子:

子組件直接對 prop 值做雙向綁定,會發(fā)生什么?

父組件代碼:

<template>
  <child-component :value="fatherValue" />
</template>

<script>
import ChildComponent from './child.vue'

export default {
  name: 'father-component',
  components: {
    ChildComponent
  },
  data() {
    return {
      fatherValue: ''
    }
  }
}
</script>

子組件代碼:

<template>
  <div class="child-component">
    <input v-model="value" placeholder="edit me" />
    <p>{{ value }}</p>
  </div>
</template>

<script>
export default {
  name: 'child-component',
  props: {
    value: {
      type: String,
      default: ''
    }
  }
}
</script>

Vue中不通過v-model怎么實現(xiàn)雙向綁定

Vue中不通過v-model怎么實現(xiàn)雙向綁定

Vue中不通過v-model怎么實現(xiàn)雙向綁定

可以看到,childComponent中的 prop 值可以實現(xiàn)雙向綁定,但是 FatherComponent 中的 data 值并未發(fā)生改變,而且控制臺拋出了警告:

[Vue warn]: Avoid 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"

翻譯一下:避免直接改變 prop 值,因為每當(dāng)父組件重新渲染時,該值將被覆蓋。相反,使用基于 prop 值的 data 或 computed。

很顯然,直接改變子組件的 prop 值的這種行為被 vue 禁止了。

如何操作傳入子組件的 prop 值

但是很多時候,我們確實要操作傳入子組件的 prop 值,該怎么辦呢?

正如上面的警告所說,有兩種辦法:

  • 這個 prop 用來傳遞一個初始值,定義一個本地的 data property 并將這個 prop 用作其初始值

props: {
  initialCounter: {
    type: Number,
    default: 0
  },
},
data() {
  return {
    counter: this.initialCounter
  }
}
  • 這個 prop 以一種原始的值傳入且需要進行轉(zhuǎn)換,用這個 prop 的值來定義一個計算屬性

props: {
  size: {
    type: String,
    default: ''
  }
},
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

這樣不管怎么操作數(shù)據(jù)都是操作的子組件數(shù)據(jù)了,不會影響到父組件數(shù)據(jù)。

所以,我們想用 prop 傳入的數(shù)據(jù)實現(xiàn)雙向綁定,可以這么寫:

父組件代碼不變

子組件里用 innerValue 來接收傳入的 value :

<template>
  <div class="child-component">
    <input v-model="innerValue" placeholder="edit me" />
    <p>{{ innerValue }}</p>
  </div>
</template>

<script>
export default {
  name: 'child-component',
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      innerValue: this.value
    }
  }
}
</script>

這里要注意一個問題

在 JavaScript 中對象和數(shù)組是通過引用傳入的,所以對于一個數(shù)組或?qū)ο箢愋偷?prop 來說,在子組件中改變變更這個對象或數(shù)組本身將會影響到父組件的狀態(tài)。

還是上面的例子,我們將傳入的值改為對象:

父組件代碼:

<template>
  <child-component :obj="fatherObj" />
</template>

<script>
import ChildComponent from './child.vue'

export default {
  name: 'father-component',
  components: {
    ChildComponent
  },
  data() {
    return {
      fatherObj: {
        name: 'lin'
      }
    }
  }
}
</script>

子組件代碼:

<template>
  <div class="child-component">
    <input v-model="innerObj.name" placeholder="edit me" />
    <p>{{ innerObj.name }}</p>
  </div>
</template>

<script>
export default {
  name: 'child-component',
  props: {
    obj: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      innerObj: this.obj
    }
  }
}
</script>

Vue中不通過v-model怎么實現(xiàn)雙向綁定

Vue中不通過v-model怎么實現(xiàn)雙向綁定

這里的 this.obj 是引用類型,賦值給了 innerObj,所以 innerObj 實際上還是指向了父組件的數(shù)據(jù),對 innerObj.name 的修改依然會影響到父組件

所以,處理這種引用類型數(shù)據(jù)的時候,需要深拷貝一下

import { clone } from 'xe-utils'
export default {
  name: 'child-component',
  props: {
    obj: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      innerObj: clone(this.obj, true)
    }
  }
}

Vue中不通過v-model怎么實現(xiàn)雙向綁定

如上圖所示,這樣子組件和父組件之間的數(shù)據(jù)就不會互相影響了。

讀到這里,這篇“Vue中不通過v-model怎么實現(xiàn)雙向綁定”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI