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对URL字符串进行编码/解码分析
Oct 25 Javascript
读jQuery之七 判断点击了鼠标哪个键的代码
Jun 21 Javascript
JS写的贪吃蛇游戏(个人练习)
Jul 08 Javascript
JavaScript判断访问的来源是手机还是电脑,用的哪种浏览器
Dec 12 Javascript
js/jquery解析json和数组格式的方法详解
Jan 09 Javascript
js中利用cookie实现记住密码功能
Aug 20 Javascript
javascript垃圾收集机制的原理分析
Dec 08 Javascript
详解MVC如何使用开源分页插件(shenniu.pager.js)
Dec 16 Javascript
jQuery排序插件tableSorter使用方法
Feb 10 Javascript
React Native 自定义下拉刷新上拉加载的列表的示例
Mar 01 Javascript
使用vue2实现带地区编号和名称的省市县三级联动效果
Nov 05 Javascript
Vue设置长时间未操作登录自动到期返回登录页
Jan 22 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 中英文语言转换类代码
2011/08/11 PHP
ajax php传递和接收变量实现思路及代码
2012/12/19 PHP
PHP 登录记住密码实现思路
2013/05/07 PHP
javascript 单选框,多选框美化代码
2008/08/01 Javascript
JQuery 网站换肤功能实现代码
2009/11/02 Javascript
javascript 防止刷新,后退,关闭
2010/08/07 Javascript
node.js中的fs.renameSync方法使用说明
2014/12/16 Javascript
AngularJS自定义插件实现网站用户引导功能示例
2016/11/07 Javascript
jQuery用FormData实现文件上传的方法
2016/11/21 Javascript
Vue.js实现表格动态增加删除的方法(附源码下载)
2017/01/20 Javascript
HTML5+jQuery实现搜索智能匹配功能
2017/03/24 jQuery
Vue组件化通讯的实例代码
2017/06/23 Javascript
详解react-webpack2-热模块替换[HMR]
2017/08/03 Javascript
iframe与主框架跨域相互访问实现方法
2017/09/14 Javascript
react 父子组件之间通讯props
2018/09/08 Javascript
小程序云开发实战小结
2018/10/25 Javascript
使用Sonarqube扫描Javascript代码的示例
2018/12/26 Javascript
Bootstrap4 gulp 配置详解
2019/01/06 Javascript
js 下拉菜单点击旁边收起实现(踩坑记)
2019/09/29 Javascript
javascript中的with语句学习笔记及用法
2020/02/17 Javascript
微信小程序scroll-view的滚动条设置实现
2020/03/02 Javascript
[04:29]2016国际邀请赛中国区预选赛Ehome战队教练采访
2016/06/27 DOTA
python3.0 字典key排序
2008/12/24 Python
Python实现类的创建与使用方法示例
2017/07/25 Python
Python cookbook(数据结构与算法)实现优先级队列的方法示例
2018/02/18 Python
Python实现购物车程序
2018/04/16 Python
Windows下PyCharm安装图文教程
2018/08/27 Python
python列表使用实现名字管理系统
2019/01/30 Python
python3读取图片并灰度化图片的四种方法(OpenCV、PIL.Image、TensorFlow方法)总结
2019/07/04 Python
屏蔽Django admin界面添加按钮的操作
2020/03/11 Python
python 删除excel表格重复行,数据预处理操作
2020/07/06 Python
Monnier Freres中文官网:法国领先的奢侈品配饰在线零售商
2017/11/01 全球购物
Made in Design德国:设计师家具、灯具和装饰
2019/10/31 全球购物
海蓝之谜英国官网:La Mer英国
2020/01/15 全球购物
文明宿舍获奖感言
2014/02/07 职场文书
事业单位绩效考核实施方案
2014/03/27 职场文书