详解vue父子组件状态同步的最佳方式


Posted in Javascript onSeptember 10, 2020

哈喽!大家好!我是木瓜太香,一位老牌儿前端工程师,平时我们在使用 vue 开发的时候,可能会遇到需要父组件与子组件某个状态需要同步的情况,通常这个是因为我们封装组件的时候有一个相同的状态外面要用,里面也要用,今天我们就来看看怎么优雅的解决这个问题吧!
一般来说我们实现这个功能,只需要父组件通过 props 传递给子组件就好了,但是理想很丰满,现实很骨感,如果我们直接在子组件更改传进来的 props ,不出意外浏览器会给你一坨大红色的报错,因为在 vue 中我们的数据流动是自上而下的,而子组件直接更改父组件传来的 props 则是自下而上的数据流动,这是 vue 不允许的。

所以通常我们的解决办法是,父组件通过 props 传入状态给子组件,子组件通过 props 来初始化另外一个内部的状态,子组件每次更改状态之后都通知父组件,然后由父组件来更改自己的状态,其实就是 props on emit 的应用,接下来我们来上代码。

父组件 Father.vue

<template>
  <div class="father">
    <h1>父组件维护的状态:{{food}}</h1>
    <son :food="food" @update:food="f => food = f"></son>
  </div>
</template>

子组件 Son.vue

<template>
  <div class="son">
    <h2>子组件中维护的状态:{{innerFood}}</h2>
    <button @click="innerFood = '100斤牛肉'">点击更改子组件状态</button>
  </div>
</template>
<script>
  export default {
    data () {
     return {
       innerFood: this.food
     } 
    },
    props: {
      food: String
    },
    watch: {
      innerFood (nv) {
        this.$emit("update:food",nv)
      }
    }
  }
</script>

可以看到我们上述的写法,其实是维护了父子组件中的不同的两个状态,我们做的工作只是将这两个状态同步了,这种写法没有任何问题,其实对于子组件的部分我们也可以通过 computed 来实现,下面我们来看一看另一种子组件内维护同步状态的方法:

子组件 Son.vue 的另一种写法

<template>
  <div class="son">
    <h2>子组件中维护的状态:{{innerFood}}</h2>
    <button @click="innerFood = '100斤牛肉'">点击更改子组件状态</button>
  </div>
</template>
<script>
  export default {
    props: {
      food: String
    },
    computed: {
      innerFood: {
        get () {
          return this.food
        },
        set (nv) {
          this.$emit("update:food",nv)
        }
      }
    }
  }
</script>

好了,两种写法我们都已经演示完毕,现在我们来优化一下父组件中的写法。

父组件中可以看到我们之前在上面绑定了一个 update:food 事件,并且使用箭头函数做了一个赋值,其实这里我们可以稍微优化一下,不要箭头函数直接赋值,因为我们触发的是自定义事件,而我们触发的时候给的第一个参数就是新值,我们可以直接通过 $event 拿到这个值,所以可以写成如下形式:

优化后的父组件

<template>
  <div class="father">
    <h1>父组件维护的状态:{{food}}</h1>
    <son :food="food" @update:food="food = $event"></son>
  </div>
</template>

到这里你以为就结束了?其实我们还可以更近一步,只要满足我们以上的事件命名方式,我们实际上可以使用 sync 修饰符代替事件的绑定,也就是我们不用写事件绑定了,但是子组件内部的事件触发依然不能少,最终优化的结果如下:

<template>
  <div class="father">
    <h1>父组件维护的状态:{{food}}</h1>
    <son :food.sync="food"></son>
  </div>
</template>

到此我们就真的完成了父子组件的同步,当然在子组件中维护一个状态不一定是必须的,如果我们只用父组件传给我们的 props 做展示,而子组件没有对这个 props 直接更改的行为,那么我们就不用在子组件创建另外一个状态,我们子组件想改他的时候只需要在合适的时机提交合适的事件即可,但是有一种情况我们不得不在子组件中创建另一个状态,就是我们父组件传入的状态在子组件中用于 v-model 这种双向数据绑定的功能时,由于 v-model 会自动更改值所以直接填入从父组件接受的 props 就不合适了。

到此这篇关于详解vue父子组件状态同步的最佳方式的文章就介绍到这了,更多相关vue父子组件状态同步 内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
jQuery 解析xml文件
Aug 09 Javascript
手写的一个兼容各种浏览器的javascript getStyle函数(获取元素的样式)
Jun 06 Javascript
使用js Math.random()函数生成n到m间的随机数字
Oct 09 Javascript
jQuery实现按键盘方向键翻页特效
Mar 18 Javascript
原生js实现倒计时功能(多种格式调用)
Jan 12 Javascript
MUI 解决动态列表页图片懒加载再次加载不成功的bug问题
Apr 13 Javascript
webpack学习--webpack经典7分钟入门教程
Jun 28 Javascript
详解vue2.0 资源文件assets和static的区别
Nov 27 Javascript
微信小程序 导入图标实现过程详解
Oct 11 Javascript
手把手带你入门微信小程序新框架Kbone的使用
Feb 25 Javascript
vue 组件间的通信之子组件向父组件传值的方式
Jul 29 Javascript
Vue中computed及watch区别实例解析
Aug 01 Javascript
vue使用echarts实现水平柱形图实例
Sep 09 #Javascript
在vue中实现清除echarts上次保留的数据(亲测有效)
Sep 09 #Javascript
vue 项目引入echarts 添加点击事件操作
Sep 09 #Javascript
Vue this.$router.push(参数)实现页面跳转操作
Sep 09 #Javascript
Vue页面跳转传递参数及接收方式
Sep 09 #Javascript
微信小程序实现身份证取景框拍摄
Sep 09 #Javascript
vue实现点击按钮“查看详情”弹窗展示详情列表操作
Sep 09 #Javascript
You might like
收音机史话 - 1960年代前后的DIY
2021/03/02 无线电
php 动态添加记录
2009/03/10 PHP
php数组冒泡排序算法实例
2016/05/06 PHP
thinkPHP5框架导出Excel文件简单操作示例
2018/08/03 PHP
PHP验证类的封装与使用方法详解
2019/01/10 PHP
js在指定位置增加节点函数insertBefore()用法实例
2015/01/12 Javascript
Js为表单动态添加节点内容的方法
2015/02/10 Javascript
jquery悬浮提示框完整实例
2016/01/13 Javascript
简单模拟node.js中require的加载机制
2016/10/27 Javascript
深入理解node.js之path模块
2017/05/03 Javascript
vue生成token并保存到本地存储中
2018/07/17 Javascript
如何用JavaScript实现功能齐全的单链表详解
2019/02/11 Javascript
Webpack4 使用Babel处理ES6语法的方法示例
2019/03/07 Javascript
javascript原型链学习记录之继承实现方式分析
2019/05/01 Javascript
nodejs提示:cross-device link not permitted, rename错误的解决方法
2019/06/10 NodeJs
三分钟教你用Node做一个微信哄女友(基友)神器(面向小白)
2019/06/21 Javascript
解决vue项目F5刷新mounted里的函数不执行问题
2019/11/05 Javascript
python读写文件操作示例程序
2013/12/02 Python
Python语言的变量认识及操作方法
2018/02/11 Python
python实现图片筛选程序
2018/10/24 Python
Python中垃圾回收和del语句详解
2018/11/15 Python
一篇文章彻底搞懂Python中可迭代(Iterable)、迭代器(Iterator)与生成器(Generator)的概念
2019/05/13 Python
Python多进程方式抓取基金网站内容的方法分析
2019/06/03 Python
django 简单实现登录验证给你
2019/11/06 Python
使用 Supervisor 监控 Python3 进程方式
2019/12/05 Python
django框架使用views.py的函数对表进行增删改查内容操作详解【models.py中表的创建、views.py中函数的使用,基于对象的跨表查询】
2019/12/12 Python
selenium+超级鹰实现模拟登录12306
2021/01/24 Python
ASP.NET Core中的配置详解
2021/02/05 Python
HTML5之SVG 2D入门10—滤镜的定义及使用
2013/01/30 HTML / CSS
NFL Game Pass欧洲:在线观看NFL比赛直播和点播,以高清质量播放
2018/08/30 全球购物
地球鞋加拿大官网:Earth Shoes Canada
2020/11/17 全球购物
国际政治学专业推荐信
2014/09/26 职场文书
党的群众路线教育实践活动领导班子整改方案
2014/10/25 职场文书
2014年度工作总结报告
2014/12/15 职场文书
2015年护士工作总结范文
2015/03/31 职场文书
公司要求试用期员工提交“述职报告”,该怎么写?
2019/07/17 职场文书