Vue中如果不通过v-model实现双向绑定?下面本篇文章给大家介绍一下不使用v-model,实现双向绑定的方法,希望对大家有所帮助!

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

不使用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: 'test-v-model',
  data() {
    return {
      msg: '',
      msg1: ''
    }
  },
  methods: {
    handleInput(e) {
      this.msg1 = e.target.value
    }
  }
}
</script>
登录后复制

不使用 v-model,就需要通过 value 属性绑定值和 input 事件改变绑定值来实现双向绑定。

换句话说,v-model只是一种简写形式而已

与本题相关联的知识延伸

  • 双向绑定
  • 单向数据绑定
  • 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: 'test-v-model',
  data() {
    return {
      msg: '',
      msg1: ''
    }
  }
}
</script>
登录后复制

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

从gif图中可以看出,使用 v-model,当数据变化之后,视图同步更新,当视图变化之后,数据也会更新,这就是双向绑定。

使用 v-bind,当数据变化之后,视图同步更新,当视图变化之后,数据不会更新,这就是单向数据绑定。

问:什么是 vue 单向数据流?

vue 文档在介绍 Prop 时就提出了单向数据流的概念,点击此处 查看 vue 文档对单向数据流的说明。

我们看下面这个例子:

子组件直接对 prop 值做双向绑定,会发生什么?

父组件代码:

<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实现双向绑定?-LMLPHP

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

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

可以看到,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: ''
  }
},
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: 'child-component',
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      innerValue: this.value
    }
  }
}
</script>
登录后复制

这里要注意一个问题

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

父组件代码:

<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实现双向绑定?-LMLPHP

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

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

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

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实现双向绑定?-LMLPHP

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

总结

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

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

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

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

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

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

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

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

08-23 04:30