目录
不使用v-model,如何实现双向绑定?
与本题相关联的知识延伸
总结
首页 web前端 Vue.js 聊聊Vue中如果不通过v-model实现双向绑定?

聊聊Vue中如果不通过v-model实现双向绑定?

Jan 29, 2022 am 09:00 AM
v-model vue 双向绑定

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>
登录后复制

1.gif

从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>
登录后复制

2.png

3.png

4.png

可以看到,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&#39;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>
登录后复制

5.png

6.png

这里的 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)
    }
  }
}
登录后复制

7.png

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

总结

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

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

是,但只是语法糖

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

是,数据向下,事件向上

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

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

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

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

以上是聊聊Vue中如果不通过v-model实现双向绑定?的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

vue怎么给按钮添加函数 vue怎么给按钮添加函数 Apr 08, 2025 am 08:51 AM

可以通过以下步骤为 Vue 按钮添加函数:将 HTML 模板中的按钮绑定到一个方法。在 Vue 实例中定义该方法并编写函数逻辑。

vue中怎么用bootstrap vue中怎么用bootstrap Apr 07, 2025 pm 11:33 PM

在 Vue.js 中使用 Bootstrap 分为五个步骤:安装 Bootstrap。在 main.js 中导入 Bootstrap。直接在模板中使用 Bootstrap 组件。可选:自定义样式。可选:使用插件。

vue.js怎么引用js文件 vue.js怎么引用js文件 Apr 07, 2025 pm 11:27 PM

在 Vue.js 中引用 JS 文件的方法有三种:直接使用 &lt;script&gt; 标签指定路径;利用 mounted() 生命周期钩子动态导入;通过 Vuex 状态管理库进行导入。

vue中的watch怎么用 vue中的watch怎么用 Apr 07, 2025 pm 11:36 PM

Vue.js 中的 watch 选项允许开发者监听特定数据的变化。当数据发生变化时,watch 会触发一个回调函数,用于执行更新视图或其他任务。其配置选项包括 immediate,用于指定是否立即执行回调,以及 deep,用于指定是否递归监听对象或数组的更改。

vue多页面开发是啥意思 vue多页面开发是啥意思 Apr 07, 2025 pm 11:57 PM

Vue 多页面开发是一种使用 Vue.js 框架构建应用程序的方法,其中应用程序被划分为独立的页面:代码维护性:将应用程序拆分为多个页面可以使代码更易于管理和维护。模块化:每个页面都可以作为独立的模块,便于重用和替换。路由简单:页面之间的导航可以通过简单的路由配置来管理。SEO 优化:每个页面都有自己的 URL,这有助于搜索引擎优化。

vue返回上一页的方法 vue返回上一页的方法 Apr 07, 2025 pm 11:30 PM

Vue.js 返回上一页有四种方法:$router.go(-1)$router.back()使用 &lt;router-link to=&quot;/&quot;&gt; 组件window.history.back(),方法选择取决于场景。

怎样查询vue的版本 怎样查询vue的版本 Apr 07, 2025 pm 11:24 PM

可以通过以下方法查询 Vue 版本:使用 Vue Devtools 在浏览器的控制台中查看“Vue”选项卡。使用 npm 运行“npm list -g vue”命令。在 package.json 文件的“dependencies”对象中查找 Vue 项。对于 Vue CLI 项目,运行“vue --version”命令。检查 HTML 文件中引用 Vue 文件的 &lt;script&gt; 标签中的版本信息。

vue怎么用函数截流 vue怎么用函数截流 Apr 08, 2025 am 06:51 AM

Vue 中的函数截流是一种技术,用于限制函数在指定时间段内被调用的次数,防止性能问题。实现方法为:导入 lodash 库:import { debounce } from 'lodash';使用 debounce 函数创建截流函数:const debouncedFunction = debounce(() =&gt; { / 逻辑 / }, 500);调用截流函数,控制函数在 500 毫秒内最多被调用一次。

See all articles