vue2组件之间双向数据绑定问题

文质彬彬
• 阅读 28500

最近在使用element-ui的dialog组件二次封装成独立组件使用时,子组件需要将关闭dialog状态返回给父组件,简单的说就是要实现父子组件之间的数据双向绑定问题。

大致代码如下:

1,父组件

<template>
  <button @click="openDialog">打开弹窗</button>
  <dialogCompenent :show="result" :result="result" @dialogData="closeDialog"></dialogCompenent>
</template>
<script type="text/babel">
import dialogCompenent from '/dialogCompenent'
export default {
  data () {
    return {
      result: false
    }
  },
  components: {
    dialogCompenent
  },
  methods: {
    openDialog () {
      this.result = true
    },
    closeDialog (data) {
      this.result = data
    }
  }
}
</script>

2,子组件 childCompenent

<template>
<el-dialog
  title="弹框组件"
  :visible.sync="result"
  @open="doOpen"
  @close="doClose"
  :show="result"
  size="tiny">
  <div class="content-wrapper">
    具体业务代码...
  </div>
</el-dialog>
  </div>
</template>
<script type="text/babel">
  import videoApi from '../../api/videoApi/videoApi'
  export default {
    name: 'dialogCompenent',
    props: {
      result: Boolean
    },
    methods: {
      doOpen () {
        ...
      },
      doClose () {
        this.$emit('dialogData', false)
        ...
      }
    }
  }
</script>

程序在浏览器上虽然能够正常运行,但是在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的值,同时修改的值也不会同步到组件外层,即调用组件方不知道组件内部当前的状态是什么

这是什么原因造成的呢?

在vue1.x版本中利用props的twoWay和.sync绑定修饰符就可以实现props的双向数据绑定。

在vue2.0中移除了组件的props的双向数据绑定功能,如果需要双向绑定需要自己来实现。
在vue2.0中组件的props的数据流动改为了只能单向流动,即只能由(父组件)通过组件的v-bind:attributes传递给(子组件),子组件只能被动接收父组件传递过来的数据,并在子组件内不能修改由父组件传递过来的props数据。

官方文档解释:

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

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

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

子组件修改:

<template>
    <el-dialog
      title="弹框组件"
      :visible.sync="openStatus"
      @open="doOpen"
      @close="doClose"
      :show="openStatus"
      size="tiny">
      <div class="content-wrapper">
        具体业务代码...
      </div>
    </el-dialog>
  </div>
</template>
<script type="text/babel">
  import videoApi from '../../api/videoApi/videoApi'
  export default {
    name: 'dialogCompenent',
    props: {
      result: Boolean
    },
    /*创建一个openStatus变量缓存result数据
    *在子组件需要调用result的地方调用data对象openStatus
    */
    data () {
      return {
        openStatus: this.result
      }
    },
    //新增result的watch,监听变更同步到openStatus
    //监听父组件对props属性result的修改,并同步到组件内的data属性
    watch: {
      result (val) {
        this.openStatus = val
      }
    },
    methods: {
      doOpen () {
        ...
      },
      doClose () {
        this.$emit('dialogData', false)//子组件对openStatus修改后向父组件发送事件通知
        ...
      }
    }
  }
</script>

父组件修改:

<template>
  <button @click="openDialog">打开弹窗</button>
  <dialogCompenent :show="result" :result="result" @dialogData="closeDialog"></dialogCompenent>
</template>
<script type="text/babel">
import dialogCompenent from '/dialogCompenent'
export default {
  data () {
    return {
      result: false
    }
  },
  components: {
    dialogCompenent
  },
  methods: {
    openDialog () {
      this.result = true
    },
    closeDialog (data) {
      this.result = data//子组件触发父组件事件,进行数据变更,同步result数据
    }
  }
}
</script>

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

结语
那么为什么vue1.0还有的数据双向绑定在vue2.0版本中反而抛弃了呢,通过上述案例我们也可以发现双向绑定的props代码多,不利于组件间的数据状态管理,尤其是在复杂的业务中更是如此,所以尽量不使用这种方式的双向绑定,过于复杂的数据处理使用vuex来进行数据管理。(https://vuex.vuejs.org/zh-cn/...

点赞
收藏
评论区
推荐文章
Alex799 Alex799
4年前
vue最新面试题
最近在面试,总结几个重点的面试题:一、vue父子组件之间的传值:简单来说,子组件通过props方法接受父组件传来的值,子组件通过$emit方法来向父组件发送数据。(具体案例可以看我之前写的博客)。二、vue生命周期函数:beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeDestr
Chase620 Chase620
4年前
vue的8种通信方式
1.props/emit1.父组件向子组件传值下面通过一个例子说明父组件如何向子组件传递数据:在子组件article.vue中如何获取父组件section.vue中的数据articles:\'红楼梦','西游记','三国演义'\//section父组件<template<divclass"section"
Easter79 Easter79
4年前
Vue 组件实现数据双向绑定(el
一、组件vmodel值通过props传入,必须定义为value!(https://oscimg.oschina.net/oscnet/66e6fa03cb5d23a24fd7d45e5e782b125ec.png)二、将传入的value在data中重新定义赋值,以便子组件改变值(子组件中不能直接修改props
Souleigh ✨ Souleigh ✨
5年前
React 组件间通信的10种方法
组件间通信方式总结父组件子组件:1.Props2.InstanceMethods子组件父组件:1.CallbackFunctions2.EventBubbling兄弟组件之间:1.ParentComponent不太相关的组件之间:1.Context2.Portals3.Global
LinMeng LinMeng
5年前
element-ui Dialog组件的close-on-click-modal属性
element组件库的Dialog对话框默认可以通过点击modal关闭Dialog,即点击空白处弹框可关闭。单功能设置如下:<eldialog:closeonclickmodal"false"</eldialog全局修改默认配置,点击空白处不能关闭弹窗://在组件注册.js文件中Dialog.props.cl
Dax Dax
4年前
Vue父子组件
几种常见的通信方式:1、prop属性父组件通过绑定属性的方式,给子组件传值,同时子组件通过设置props来接收letChildVue.extend(template:'content',props:content:type:String,default:()r
Chase620 Chase620
4年前
关于:父组件中的子组件中的子组件(孙级)添加数据后怎么样去调用父组件中的方法呢?
1、需求引入image.png这是父组件下的子组件的子组件,一个绑定子设备的弹出窗modal,那么我们怎么样在这个组件中选中子设备后点击确定时去触发父组件的父组件的table列表数据刷新呢?image.pngimage.pngimage.png组件的层级关系.png上述的图示便是部分代码的展示,一般的组件传值有父组件传子组件(
Stella981 Stella981
4年前
Flutter子组件调用父组件方法修改父组件参数
子组件调用父级组件方法的主要实现是父组件给子组件传入一个方法,然后在子组件中调用父级方法来修改父级的参数。看一下效果图!(https://img2018.cnblogs.com/blog/1038765/201907/103876520190702152130487420290106.gif)父级组件实现在父级组件中写一个
Stella981 Stella981
4年前
ReactJS 关键知识点汇总
1.React组件之间事件调用(父组件调用子组件)(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fblog.csdn.net%2Fchenyongtu110%2Farticle%2Fdetails%2F49613967)2.ReactJS学习笔记(三)父子组
Stella981 Stella981
4年前
Lightning Web Components html_templates(三)
LightningWebComponents强大之处在于模版系统,使用了虚拟dom进行智能高效的组件渲染。使用简单语法以声明方式将组件的模板绑定到组件的JavaScript类中的数据数据绑定我们可以使用{property}绑定组件模版属性到一个组件js类中的属性一个简单的例子组件class
昔不亏 昔不亏
1年前