首頁  >  文章  >  web前端  >  聊聊Vue中如果不透過v-model實現雙向綁定?

聊聊Vue中如果不透過v-model實現雙向綁定?

青灯夜游
青灯夜游轉載
2022-01-29 09:00:303354瀏覽

Vue中如果不透過v-model實現雙向綁定?以下這篇文章跟大家介紹一下不使用v-model,實現雙向綁定的方法,希望對大家有幫助!

聊聊Vue中如果不透過v-model實現雙向綁定?

不使用v-model,如何實現雙向綁定?

有人說,這種小白問題,也好意思問?

你別說,我初學vue的時候,可是被這些問題折磨得死去活來的,硬著頭皮照著官網文檔demo寫,會用之後,日常開發也寫出過很多跟v-model相關的bug,後來下定決心仔細研究一下之後,才發現這裡面的門道還有點多,且聽我細細講來。 【相關推薦:vue.js影片教學

先來看解答:

<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: &#39;test-v-model&#39;,
  data() {
    return {
      msg: &#39;&#39;,
      msg1: &#39;&#39;
    }
  },
  methods: {
    handleInput(e) {
      this.msg1 = e.target.value
    }
  }
}
</script>

#不使用v- model,就需要透過value 屬性綁定值和input 事件改變綁定值來實現雙向綁定。

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

事實上,v-model 的本質就是語法糖,它負責監聽用戶的輸入事件以更新數據,並對一些極端場景進行一些特殊處理。 -- 官方文件

v-model 在內部為不同的輸入元素使用不同的property 並拋出不同的事件:

  • text 和textarea 元素使用 value property 和 input 事件;
  • checkbox 和radio 使用 checked property 和 change 事件;
  • select 欄位將 value 作為prop 並將 change 作為事件。

與本題相關聯的知識延伸

  • 雙向綁定
  • 單向資料綁定
  • vue 元件之間互動的單向資料流

問:什麼是雙向綁定?

雙向綁定就是當資料變更之後,視圖同步更新,當視圖變更之後,資料也會更新。

問:什麼是單向資料綁定?

#單向資料綁定就是當資料變更之後,視圖同步更新,當視圖變更之後,資料不會更新。

在vue中是透過指令v-model 來實現雙向綁定,透過v-bind 來實作單向資料綁定

#看完下面這段程式碼和這段程式碼運行的gif演示,你就能明白他們的差別了。

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

    <p>单向数据绑定</p>
    <input v-bind:value="msg1" placeholder="edit me" />
    <p>{{ msg1 }}</p>
  </div>
</template>

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

聊聊Vue中如果不透過v-model實現雙向綁定?

從gif圖中可以看出,使用v-model,當資料變更之後,視圖同步更新,當視圖變更之後,資料也會更新,這就是雙向綁定。

使用 v-bind,當資料變更之後,視圖同步更新,當視圖變更之後,資料不會更新,這就是單向資料綁定。

問:什麼是 vue 單向資料流?

子元件不能改變父元件傳遞給它的 prop 屬性,建議的做法是它拋出事件,通知父元件自行改變綁定的值。
總結起來就是資料向下,事件向上。

vue 文件在介紹 Prop 時就提出了單向資料流的概念,點擊此處 查看 vue 文件對單向資料流的說明。

所有的prop 都使得其父子prop 之間形成了一個單向下行綁定:父級prop 的更新會向下流動到子元件中,但反過來則不行。這樣會防止從子元件意外變更父級元件的狀態,從而導致你的應用的資料流向難以理解。

額外的,每次父級元件發生變更時,子元件中所有的 prop 都會刷新為最新的值。這表示你應該在一個子元件內部改變 prop。如果你這樣做了,Vue 會在瀏覽器的控制台中發出警告。

我們看下面這個範例:

子元件直接對 prop 值做雙向綁定,會發生什麼事?

父元件程式碼:

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

<script>
import ChildComponent from &#39;./child.vue&#39;

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

子元件程式碼:

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

<script>
export default {
  name: &#39;child-component&#39;,
  props: {
    value: {
      type: String,
      default: &#39;&#39;
    }
  }
}
</script>

聊聊Vue中如果不透過v-model實現雙向綁定?

聊聊Vue中如果不透過v-model實現雙向綁定?

聊聊Vue中如果不透過v-model實現雙向綁定?

可以看到,childComponent中的 prop 值可以实现双向绑定,但是 FatherComponent 中的 data 值并未发生改变,而且控制台抛出了警告:

[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 值,因为每当父组件重新渲染时,该值将被覆盖。相反,使用基于 prop 值的 data 或 computed。

很显然,直接改变子组件的 prop 值的这种行为被 vue 禁止了。

如何操作传入子组件的 prop 值

但是很多时候,我们确实要操作传入子组件的 prop 值,该怎么办呢?

正如上面的警告所说,有两种办法:

  • 这个 prop 用来传递一个初始值,定义一个本地的 data property 并将这个 prop 用作其初始值
props: {
  initialCounter: {
    type: Number,
    default: 0
  },
},
data() {
  return {
    counter: this.initialCounter
  }
}
  • 这个 prop 以一种原始的值传入且需要进行转换,用这个 prop 的值来定义一个计算属性
props: {
  size: {
    type: String,
    default: &#39;&#39;
  }
},
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

这样不管怎么操作数据都是操作的子组件数据了,不会影响到父组件数据。

所以,我们想用 prop 传入的数据实现双向绑定,可以这么写:

父组件代码不变

子组件里用 innerValue 来接收传入的 value :

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

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

这里要注意一个问题

在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。

还是上面的例子,我们将传入的值改为对象:

父组件代码:

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

<script>
import ChildComponent from &#39;./child.vue&#39;

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

子组件代码:

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

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

聊聊Vue中如果不透過v-model實現雙向綁定?

聊聊Vue中如果不透過v-model實現雙向綁定?

这里的 this.obj 是引用类型,赋值给了 innerObj,所以 innerObj 实际上还是指向了父组件的数据,对 innerObj.name 的修改依然会影响到父组件

所以,处理这种引用类型数据的时候,需要深拷贝一下

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

聊聊Vue中如果不透過v-model實現雙向綁定?

如上图所示,这样子组件和父组件之间的数据就不会互相影响了。

总结

至此,终于把双向绑定和单向数据流讲清楚了,真的没想到,平时开发时都懂的概念,想讲清楚居然花了这么多篇幅,确实不容易,不过,这也是对自己的一种锻炼吧。

问:v-model是双向绑定吗?

是,但只是语法糖

问:v-model是单向数据流吗?

是,数据向下,事件向上

本题还有一些其他问法,比如:

  • vue 的双向绑定和单向数据流有什么区别?
  • 为什么说 vue 的双向绑定和单向数据流不冲突?

看完本篇文章,相信不管怎么问,你都能对这两个概念理解透彻了。

更多编程相关知识,请访问:编程入门!!

以上是聊聊Vue中如果不透過v-model實現雙向綁定?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除