在项目中开始使用vue2来构建项目了,跟 vue1 很大的一处不同在于2
取消了props
的双向绑定,改成只能从父级传到子级的单向数据流,初衷当然是好的,为了避免双向绑定在项目中容易造成的数据混乱。

Vue学习笔记-3 前言

解决方案一

Vue 2.x相比较Vue
1.x而言,升级变化除了实现了Virtual-Dom以外,给使用者最大不适就是移除的组件的props的双向绑定功能。
以往在Vue1.x中利用props的twoWay和.sync绑定修饰符就可以实现props的双向绑定功能,但是在Vue2中彻底废弃了此功能,如果需要双向绑定需要自己来实现。

然后开始参考网上和github上的方案等等,发现很多解决方案是这样的

Vue2的组件props通信方式

  1. 用data对象中创建一个props属性的副本
  2. watch props属性 赋予data副本 来同步组件外对props的修改
  3. watch data副本,emit一个函数 通知到组件外

在Vue2中组件的props的数据流动改为了只能单向流动,即只能由组件外(调用组件方)通过组件的DOM属性attribute传递props给组件内,组件内只能被动接收组件外传递过来的数据,并且在组件内,不能修改由外层传来的props数据。

这里以最常见的 modal为例子:modal挺合适双向绑定的,外部可以控制组件的
显示或者隐藏,组件内部的关闭可以控制 visible属性隐藏,同时visible
属性同步传输到外部

图片 1

///modal.vue 组件
<template>
 <div class="modal" v-show="visible">
  <div class="close" @click="cancel">X</div>
 </div>
</template>

<script>
export default {
 name:'modal',
 props: {
  value: {
  type: Boolean,
  default:false
  }
 },

 data () {
 return {
  visible:false
 }
 },
 watch:{
  value(val) {
  console.log(val);
  this.visible = val;
  },
  visible(val) {
  this.$emit("visible-change",val);
  }
 },
 methods:{
 cancel(){
  this.visible = false;
 }
 },
 mounted() {
 if (this.value) {
  this.visible = true;
 }
 }
}
</script>


///调用modal组件
<modal :value="isShow" @visible-change="modalVisibleChange"></modal>

export default {
 name: 'app',
 data () {
 return {
  isShow:true,
 }
 },
 methods:{
  modalVisibleChange(val){
  this.isShow = val;
  }
 }
}

关于这一点的修改官方给的解释:

这样就解决了 组件props 双向绑定的问题。
但是这样有一个不是太美观的现象就是 在父级调用
modal组件的时候,还需要写一个 modalVisibleChange 的methods.
总是显得这部分代码是多余的。
特别是写一个让别人用的公共组件,这样调用太麻烦了。能不能不写method来实现props的双向绑定呢,答案是可以的。

prop
是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。

优美解决方案

虽然废弃了props的双向绑定对于整个项目整体而言是有利且正确的,但是在某些时候我们确实需要从组件内部修改props的需求

那就是利用 v-model, 在组件内部放置一个 隐藏的input
控件来保存v-model的值,进行双向绑定

案例

改成如下代码:

假设我要做一个iOS风格的开关按钮,需求就只有两个:

<template>
 <div class="modal" v-show="visible">
  <div class="close" @click="cancel">X</div>
  <input type="text" :value="value" style='display:none;'>
 </div>
</template>

<script>
export default {
 props: {
  value: {
  type: Boolean,
  default:false
  }
 },

 data () {
 return {
  visible:false
 }
 },
 watch:{
  value(val) {
  console.log(val);
  this.visible = val;
  },
  visible(val) {
  this.$emit('input', val);
  }
 },
 methods:{
 cancel(){
  this.visible = false;
 }
 },
 mounted() {
 if (this.value) {
  this.visible = true;
 }
 }
}
</script>


///调用modal组件

 <modal v-model="isShow"></modal>

export default {
 name: 'app',
 data () {
 return {
  isShow:false
 }
 }
}
</script>
  • 点击按钮实现 开/关 状态切换
  • 不点击按钮,也可以通过外部修改数据切换开关状态,比如级联联动开关。

这样调用组件的代码是不是很简洁,其他人员要调用的话,会很轻松,只要设置
isShow 就可以控制 modal 组件的显示或者隐藏,同时 如果是modal
组件内部关闭按钮关闭的,状态也会传到 isShow。

图片 2

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

代码大致是类似这样的:

您可能感兴趣的文章:

  • Vuejs
    组件——props数据传递的实例代码
  • Vuejs第九篇之组件作用域及props数据传递实例详解
  • vue组件中使用props传递数据的实例详解
  • Vue组件选项props实例详解
  • vue里面v-bind和Props
    利用props绑定动态数据的方法
<div id="app">
 <!--开关组件-->
 <switchbtn :result="result"></switchbtn>
 <!--外部控制-->
 <input type="button" value="change" @click="change">
</div>


//开关组件代码
Vue.component("switchbtn",{
 template:"<div @click='change'>{{result?'开':'关'}}</div>",
 props:["result"],
 methods:{
 change(){
 this.result=!this.result;
 }
 }
});

//调用组件
new Vue({
 el: "#app",
 data:{
 result:true//开关状态数据
 },
 methods:{
 change(){
 this.result=!this.result;
 }
 }
});

但是在vue2.0中上面的代码在点击开关时会报错:

[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: “result” (found in component
)

组件内不能修改props的值,同时修改的值也不会同步到组件外层,即调用组件方不知道组件内部当前的状态是什么

在Vue2.0中,实现组件属性的双向绑定方式

1.
在组件内的data对象中创建一个props属性的副本

因为result不可写,所以需要在data中创建一个副本myResult变量,初始值为props属性result的值,同时在组件内所有需要调用props的地方调用这个data对象myResult

Vue.component("switchbtn", {
 template: "<div @click='change'>{{myResult?'开':'关'}}</div>",
 props: ["result"],
 data: function () {
 return {
 myResult: this.result//data中新增字段
 };
 },
 ......
});

2.
创建针对props属性的watch来同步组件外对props的修改

此时在组件外(父组件)修改了组件的props,会同步到组件内对应的props上,但是不会同步到你刚刚在data对象中创建的那个副本上,所以需要再创建一个针对props属性result的watch(监听),当props修改后对应data中的副本myResult也要同步数据。

Vue.component("switchbtn", {
 template: "<div @click='change'>{{myResult?'开':'关'}}</div>",
 props: ["result"],
 data: function () {
 return {
 myResult: this.result
 };
 },
 watch: {
 result(val) {
 this.myResult = val;//新增result的watch,监听变更并同步到myResult上
 }
 },
 ......

3.
创建针对props副本的watch,通知到组件外

此时在组件内修改了props的副本myResult,组件外不知道组件内的props状态,所以需要再创建一个针对props副本myResult,即对应data属性的watch。
在组件内向外层(父组件)发送通知,通知组件内属性变更,然后由外层(父组件)自己来变更他的数据

最终全部代码:

<div id="app">
 <switchbtn :result="result" @on-result-change="onResultChange"></switchbtn>
 <input type="button" value="change" @click="change">
</div>



Vue.component("switchbtn", {
 template: "<div @click='change'>{{myResult?'开':'关'}}</div>",
 props: ["result"],
 data: function () {
 return {
 myResult: this.result//①创建props属性result的副本--myResult
 };
 },
 watch: {
 result(val) {
 this.myResult = val;//②监听外部对props属性result的变更,并同步到组件内的data属性myResult中
 },
 myResult(val){
 //xxcanghai 小小沧海 博客园
 this.$emit("on-result-change",val);//③组件内对myResult变更后向外部发送事件通知
 }
 },
 methods: {
 change() {
 this.myResult = !this.myResult;
 }
 }
});

new Vue({
 el: "#app",
 data: {
 result: true
 },
 methods: {
 change() {
 this.result = !this.result;
 },
 onResultChange(val){
 this.result=val;//④外层调用组件方注册变更方法,将组件内的数据变更,同步到组件外的数据状态中
 }
 }
});

至此,实现了组件内数据与组件外的数据的双向绑定,组件内外数据的同步。最后归结为一句话就是:组件内部自己变了告诉外部,外部决定要不要变。

图片 3

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图