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 相关文章推荐
js仿百度有啊通栏展示效果实现代码
May 28 Javascript
js中单引号与双引号冲突问题解决方法
Oct 04 Javascript
jquery使用append(content)方法注意事项分享
Jan 06 Javascript
Jquery响应回车键直接提交表单操作代码
Jul 25 Javascript
jQuery实现的多级下拉菜单效果代码
Aug 24 Javascript
jquery实现上传文件大小类型的验证例子(推荐)
Jun 25 Javascript
AngularJs基本特性解析(一)
Jul 21 Javascript
JS实现多级菜单中当前菜单不随页面跳转样式而发生变化
May 30 Javascript
浅谈Vue.js 中的 v-on 事件指令的使用
Nov 25 Javascript
Vue 组件修改根实例的数据的方法
Apr 02 Javascript
JavaScript函数式编程(Functional Programming)箭头函数(Arrow functions)用法分析
May 22 Javascript
layui清空,重置表单数据的实例
Sep 12 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
php公用函数列表[正则]
2007/02/22 PHP
在IIS7.0下面配置PHP 5.3.2运行环境的方法
2010/04/13 PHP
PHP array_multisort()函数的使用札记
2011/07/03 PHP
简单的cookie计数器实现源码
2013/06/07 PHP
php把数据表导出为Excel表的最简单、最快的方法(不用插件)
2014/05/10 PHP
PHP实现财务审核通过后返现金额到客户的功能
2019/07/04 PHP
Thinkphp5.0框架使用模型Model的获取器、修改器、软删除数据操作示例
2019/10/11 PHP
jquery 双色表格实现代码
2009/12/08 Javascript
js动态设置鼠标事件示例代码
2013/10/30 Javascript
iframe实用操作锦集
2014/04/22 Javascript
jquery滚动加载数据的方法
2015/03/09 Javascript
Juery解决tablesorter中文排序和字符范围的方法
2015/05/06 Javascript
javascript中 try catch用法
2015/08/16 Javascript
Express的路由详解
2015/12/10 Javascript
canvas绘制多边形
2017/02/24 Javascript
JS传播事件、取消事件默认行为、阻止事件传播详解
2017/08/14 Javascript
JScript实现表格的简单操作
2017/08/15 Javascript
JavaScript实现简单音乐播放器
2020/04/17 Javascript
详解微信小程序scroll-view横向滚动的实践踩坑及隐藏其滚动条的实现
2019/03/14 Javascript
如何检查一个对象是否为空
2019/04/11 Javascript
解决mui框架中switch开关通过js控制开或者关状态时小圆点不动的问题
2019/09/03 Javascript
node.js通过Sequelize 连接MySQL的方法
2020/12/28 Javascript
Ubuntu 14.04+Django 1.7.1+Nginx+uwsgi部署教程
2014/11/18 Python
django+xadmin+djcelery实现后台管理定时任务
2018/08/14 Python
Pytorch之保存读取模型实例
2019/12/30 Python
Python实现实时数据采集新型冠状病毒数据实例
2020/02/04 Python
Python 生成VOC格式的标签实例
2020/03/10 Python
Html5 webview元素定位工具的实现
2020/08/07 HTML / CSS
美国最大的船只买卖在线市场:Boat Trader
2018/08/04 全球购物
写出程序把一个链表中的接点顺序倒排
2014/04/28 面试题
技能竞赛活动方案
2014/02/21 职场文书
大学生个人学习总结
2015/02/15 职场文书
成品仓管员岗位职责
2015/04/01 职场文书
孔繁森观后感
2015/06/10 职场文书
公司管理建议书
2015/09/14 职场文书
提档介绍信范文
2015/10/22 职场文书