Vue2.0实现组件数据的双向绑定问题


Posted in Javascript onMarch 06, 2018

通过上一节的学习,我们了解到了在Vue的组件中数据传递: prop 向下传递,事件向上传递 。意思是父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。但Vue中, props 是单向数据绑定,虽然在Vue 1.0版本中,通过 .sync 能实现双向数据绑定。但 .sync 在几个版本中被移除,尽管在2.3版本重新引入 .sync 修饰符,可这次引入只是作为一个编译时的语法糖存在。如果直接使用 .sync 修饰符来做双向数据绑定,会报警告信息。那么我们如何在组件中实现双向数据绑定呢?这一节我们就来学习这方面的相关知识。

实现组件双向数据绑定

在上一节中最后的示例使用的是Vue 1.0版本中的 .sync 实现数据双向绑定。那我们先来看看抛弃 .sync 修饰符来实现组件双向数据绑定的工作: 通过Vue提供的机制,绕开直接修改 prop 来实现组件双向数据绑定 。

其思路大致是这样:

  • 在数据渲染时使用 prop 渲染数据
  • 将 prop 绑定到子组件自身的数据上,修改数据时修改自身数据来替代 prop
  • watch 子组件自身数据的改变,触发事件通知父组件更改绑定到 prop 的数据

这样做的好处是: 父组件数据改变时,不会修改存储 prop 的子组件数据,只是以子组件数据为媒介,完成对 prop 的双向修改 。

继续拿上一节的示例来举例,只不过接下来的示例,并没有使用 .sync 来实现双向数据绑定的效果。

修改的代码如下:

<div id="app">
 <div class="parent">
  <h3>父组件Parent数据</h3>
  <ul>
   <li>
    <label>姓名:</label>
    <span>{{ name }}</span>
    <input type="text" v-model="name" />
   </li>
   <li>
    <label>年龄:</label>
    <span>{{ age }}</span>
    <input type="number" v-model="age" />
   </li>
  </ul>
 </div>
 <child :my-name="name" :my-age="age" @update:my-name="val => name = val" @update:my-age="val => age = val"></child>
</div>
<template id="child">
 <div class="child">
  <h3>子组件child数据</h3>
  <ul>
   <li>
    <label>姓名</label>
    <span>{{ myName }}</span>
    <input type="text" v-model="childMyName" />
   </li>
   <li>
    <label>年龄</label>
    <span>{{ myAge }}</span>
    <input type="number" v-model="childMyAge" />
   </li>
  </ul>
 </div>
</template>

在上面的这个示例中,我们并没有使用 .sync 修饰符,但在调用子组件的时候使用了 @update :

<child :my-name="name" :my-age="age" @update:my-name="val => name = val" @update:my-age="val => age = val"></child>

子组件中渲染到HTML模板的数据是用的 prop 数据,但监听 input 是使用的子组件自身定义的数据作为 v-model 。这样一来就不会直接修改 prop 。简单来说, 一切 prop 的改变从本质上来说都由父组件完成 。JavaScript的代码如下:

let parent = new Vue({
 el: '#app',
 data () {
  return {
   name: 'w3cplus',
   age: 7
  }
 },
 components: {
  'child': {
   template: '#child',
   props: ['myName', 'myAge'],
   data () {
    return {
     childMyName: this.myName,
     childMyAge: this.myAge
    }
   },
   watch: {
    childMyName: function (val) {
     this.$emit('update:my-name', val)
    },
    childMyAge: function (val) {
     this.$emit('update:my-age', val)
    }
   }
  }
 }
})

最终效果如下:

上面的示例效果,不管是修改父组件的数据还是子组件的数据,都会相互影响:

Vue2.0实现组件数据的双向绑定问题 

因为子组件中 props 的 myName 和 myAge 不可写,所以在 data 中创建一个副本 childMyName 和 childMyAge 。初始值为 props 属性 myName 和 myAge 的值,同时在组件内所有需要调用 props 的地方调用 data 中的 childMyName 和 childMyAge 。

components: {
 'child': {
  template: '#child',
  props: ['myName', 'myAge'],
  data () {
   return {
    childMyName: this.myName,
    childMyAge: this.myAge
   }
  },
  ...
 }
}

接下来在子组件中通过 watch 来对 props 属性的 myName 和 myAge 进行监听。当 props 修改后对应 data 中的副本 childMyName 和 childMyAge 也要同步数据。

...
watch: {
 childMyName: function (val) {
  this.$emit('update:my-name', val)
 },
 childMyAge: function (val) {
  this.$emit('update:my-age', val)
 }
}
...

接下来要做的事情就是当组件内的 props 属性发生变化时,需要向组件外(父组件)发送通知,通知组件内属性变更,然后由外层(父组件)自己来决定是否变更他的数据。

接下来我们按上面的方案来改造上一节示例中的switch按钮。

至此,实现了组件内部数据与组件外部的数据的双向绑定,组件内外数据的同步。简而言之: 组件内部自已变了告诉外部,外部决定要不要变更 。

Vue2.0实现组件数据的双向绑定问题 

什么样的 props 适合做双向绑定

事实上,在Vue中,双向绑定的 props 是不利于组件间的数据状态管理,尤其是较为复杂的业务当中,因此在实际项目中应该尽量少用双向绑定,过于复杂的数据处理,建议使用 Vuex 。但很多时候又避免不了使用双向绑定。那么什么场景之下使用 props 来做双向绑定呢?

如果在你的项目中,同时满足下面的条件时,我们就可以考虑使用 props 来做双向绑定:

  • 组件内部需要修改 props
  • 组件需要可以由外部在运行时动态控制,而非单纯的初始化
  • 组件父部需要读取组件内的状态来进行处理

虽然上面的示例展示了我们怎么在Vue 2.0中实现 props 的双向绑定,但如果项目中有更多这样的双向绑定,那么就会让你做一些重复的事情,而且代码也很冗余,事情也会变得复杂。为了改变这样的现象,可以借助Vue的 mixin 来自动化处理 props 的双向绑定的需求。不过在这节中,我们不会学习这方面的知识,后面我们在学习 mixin 时,可地再回过头来实现这样的功能。

在Vue中除了上述介绍的组件通讯之外,还有其他一些方法,在下一节中,咱们将会继续学习这方面的知识。

总结

以上所述是小编给大家介绍的Vue2.0实现组件数据的双向绑定问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
优化网页之快速的呈现我们的网页
Jun 29 Javascript
Prototype Function对象 学习
Jul 12 Javascript
JavaScript 页面编码与浏览器类型判断代码
Jun 03 Javascript
js实现页面转发功能示例代码
Aug 05 Javascript
js判断主流浏览器类型和版本号的简单实现代码
May 26 Javascript
JavaScript实现Fly Bird小游戏
Dec 15 Javascript
bootstrap提示标签、提示框实现代码
Dec 28 Javascript
基于JavaScript实现验证码功能
Apr 01 Javascript
js学习总结之dom2级事件基础知识详解
Jul 27 Javascript
vue页面加载时的进度条功能(实例代码)
Jan 13 Javascript
JavaScript实现滑动门效果
Jan 18 Javascript
uni-app实现获取验证码倒计时功能
Nov 01 Javascript
轻松搞定jQuery+JSONP跨域请求的解决方案
Mar 06 #jQuery
Vue2.0 http请求以及loading展示实例
Mar 06 #Javascript
浅析Vue中method与computed的区别
Mar 06 #Javascript
浅谈Koa2框架利用CORS完成跨域ajax请求
Mar 06 #Javascript
JavaScript基础心法 深浅拷贝(浅拷贝和深拷贝)
Mar 05 #Javascript
JavaScript基础心法 数据类型
Mar 05 #Javascript
js获取html页面代码中图片地址的实现代码
Mar 05 #Javascript
You might like
mysql+php分页类(已测)
2008/03/31 PHP
超小PHP小马小结(方便查找后门的朋友)
2012/05/05 PHP
PHP CLI模式下的多进程应用分析
2013/06/03 PHP
Youku 视频绝对地址获取的方法详解
2013/06/26 PHP
php数组去重复数据示例
2014/02/25 PHP
thinkPHP框架自动填充原理与用法分析
2018/04/03 PHP
PHP如何通过带尾指针的链表实现'队列'
2020/10/22 PHP
在UpdatePanel内jquery easyui效果失效的解决方法
2010/04/11 Javascript
jQuery 表单验证扩展(三)
2010/10/20 Javascript
jquery实现带单选按钮的表格行选中时高亮显示
2013/08/01 Javascript
JS实现的Select三级下拉菜单代码
2015/08/20 Javascript
jquery实现列表上下移动功能
2016/02/25 Javascript
jQuery中数据缓存$.data的用法及源码完全解析
2016/04/29 Javascript
动态加载js、css的简单实现代码
2016/05/26 Javascript
bootstrap laydate日期组件使用详解
2017/01/04 Javascript
JavaScript中利用for循环遍历数组
2017/01/15 Javascript
react-redux中connect()方法详细解析
2017/05/27 Javascript
在小程序中使用Echart图表的示例代码
2018/08/02 Javascript
javascript实现贪吃蛇小练习
2020/07/05 Javascript
vue 解决IOS10低版本白屏的问题
2020/11/17 Javascript
Python中列表和元组的使用方法和区别详解
2020/12/30 Python
Python中正则表达式详解
2017/05/17 Python
详解用python计算阶乘的几种方法
2019/08/14 Python
python中用logging实现日志滚动和过期日志删除功能
2019/08/20 Python
利用pyecharts读取csv并进行数据统计可视化的实现
2020/04/17 Python
python如何停止递归
2020/09/09 Python
如何用Python 加密文件
2020/09/10 Python
HTML5 与 XHTML2
2008/10/17 HTML / CSS
巴基斯坦电子产品购物网站:Home Shopping
2017/09/14 全球购物
意大利顶级奢侈品电商:LUISAVIAROMA(支持中文)
2020/05/26 全球购物
水务局局长岗位职责
2013/11/28 职场文书
资产经营总监岗位职责
2013/12/04 职场文书
日本语毕业生自荐信
2014/02/01 职场文书
初中生自我鉴定
2014/02/04 职场文书
大学新闻系应届生求职信
2014/06/02 职场文书
家具公司总经理岗位职责
2014/07/08 职场文书