Vue中实现父子组件双向数据流的三种方案分享

 更新时间:2023年08月04日 10:46:23   作者:FEF前端团队  
通常情况下,父子组件的通信都是单向的,或父组件使用props向子组件传递数据,或子组件使用emit函数向父组件传递数据,本文将尝试讲解Vue中常用的几种双向数据流的使用,需要的朋友可以参考下

1. 背景

通常情况下,父子组件的通信都是单向的,或父组件使用props向子组件传递数据,或子组件使用emit函数向父组件传递数据。

但在有些场景下,免不了需要父子组件之间进行双向数据流,从而让我们的业务代码更加简洁。很常见的场景之一:父组件引入了一个子组件,子组件是个dialog弹窗,在父组件可以点击某个按钮显示dialog,但是dialog组件的关闭操作是在组件里面的。这个时候使用双向数据流管理dialog组件的显隐状态,不仅让代码显得优雅,还能少写不少业务。

那我们能不能直接在子组件修改props来实现上述功能呢?当然是不行的,因为在Vueprops属性是只读的。官方文档给出的解释如下:

所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。本文将尝试讲解Vue中常用的几种双向数据流的使用。

2. 双向数据流

2.1. 什么是双向数据流

简而言之,双向数据流就是model的更新会触发view的更新,view的更新会触发model的更新,它们的作用是相互的。

tips: 这里只讨论父子组件传值时的双向数据流,对框架数据的双向数据流不做展开。

2.2. Vue提供的解决方案

2.2.1. 方案一:v-model

父组件代码如下:

<template>
  <div class="container">
    <a-button type="primary" @click="handleClick">改变子组件的状态</a-button>
    <p>父组件状态:{{ message }}</p>
    <!-- 子组件 -->
    <child-view v-model="message"></child-view>
		<!-- 也可以使用多个v-model,子组件里面用props正常接收就可以了 -->
		<!-- <child-view v-model:message="message" v-model:msg="msg"></child-view> -->
  </div>
</template>
<script>
import ChildView from '@/components/ChildView.vue'
export default {
  name: 'HomeView',
  components: {
    ChildView
  },
  data () {
    return {
      message: ''
    }
  },
  methods: {
    handleClick () {
      this.message = '我是用v-model修改的状态'
    }
  }
}
</script>

子组件代码如下:

<template>
  <div>
    <a-button type="primary" @click="handleClick">改变父组件的状态</a-button>
    <p>子组件状态:{{ value }}</p>
  </div>
</template>
<script>
export default {
  props: {
    // 这里框架默认属性名就是value
    value: {
      type: String,
      default: ''
    },
    // 接收多个props
    message: {
      type: String,
      default: ''
    },
    msg: {
      type: String,
      default: ''
    }
  },
  methods: {
    handleClick () {
      // 这里框架默认事件名就是input
      // 发送的数据会被父级v-model="message"接收到,再被value=message传回来
      this.$emit('input', '我是在子组件里面修改父组件v-model的值')
    }
  }
}
</script>

自定义v-modelprops属性:

Vue 允许一个自定义组件在使用 v-model 时定制 prop 和 event。默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event,但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。使用 model 选项可以回避这些情况产生的冲突。

<template>
  <div>
    <a-button type="primary" @click="handleClick">改变父组件的状态</a-button>
    <p>子组件状态:{{ msg }}</p>
  </div>
</template>
<script>
export default {
  // 自定义prop名称和事件
  model: {
    prop: 'msg',
    event: 'update'
  },
  props: {
    msg: {
      type: String,
      default: ''
    }
  },
  methods: {
    handleClick () {
      this.$emit('update', '我是在子组件里面修改父组件v-model的值')
    }
  }
}
</script>

浏览器运行效果:

2.2.2. 方案二:sync修饰符

父组件代码如下:

<template>
  <div class="container">
    <a-button type="primary" @click="handleClick">改变子组件的状态</a-button>
    <p>父组件状态:{{ message }}</p>
    <child-view :msg.sync="message"></child-view>
  </div>
</template>
<script>
import ChildView from '@/components/ChildView.vue'
export default {
  name: 'HomeView',
  components: {
    ChildView
  },
  data () {
    return {
      message: ''
    }
  },
  methods: {
    handleClick () {
      this.message = '十里平湖霜满天'
    }
  }
}
</script>

子组件代码如下:

<template>
  <div>
    <a-button type="primary" @click="handleClick">改变父组件的状态</a-button>
    <p>子组件状态:{{ msg }}</p>
  </div>
</template>
<script>
export default {
  props: {
    msg: String
  },
  methods: {
    handleClick () {
      this.$emit('update:msg', '寸寸青丝愁华年')
    }
  }
}
</script>

浏览器运行效果:

2.2.3. 方案三:通过JS引用类型特性绕过props

父组件代码如下:

<template>
  <div class="container">
    <a-button type="primary" @click="handleClick">改变子组件的状态</a-button>
    <p>父组件状态:{{ config.message }}</p>
    <child-view :config="config"></child-view>
  </div>
</template>
<script>
import ChildView from '@/components/ChildView.vue'
export default {
  name: 'HomeView',
  components: {
    ChildView
  },
  data () {
    return {
      config: {
        message: ''
      }
    }
  },
  methods: {
    handleClick () {
      this.config.message = '我是用v-model修改的状态'
    }
  }
}
</script>

子组件代码如下:

通过JS引用类型特性绕过props

运行效果和v-model一样,这里就不贴图了。

3. 总结

Vue父子组件通信,都是单向的,在需要双向通信的时候,我们有三种方式达到目的:

  1. 使用v-model
  2. 使用sync修饰符
  3. 通过JS引用类型特性绕过props单向数据流

以上就是Vue中实现父子组件双向数据流的三种方案分享的详细内容,更多关于Vue实现父子组件双向数据流的资料请关注脚本之家其它相关文章!

相关文章

  • 详解vue项目中如何引入全局sass/less变量、function、mixin

    详解vue项目中如何引入全局sass/less变量、function、mixin

    这篇文章主要介绍了详解vue项目中如何引入全局sass/less变量、function、mixin,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • 使用vue-element-admin框架调用后端接口及跨域的问题

    使用vue-element-admin框架调用后端接口及跨域的问题

    这篇文章主要介绍了使用vue-element-admin框架调用后端接口及跨域的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • 详解Vue中watch的详细用法

    详解Vue中watch的详细用法

    在vue中,使用watch来响应数据的变化。watch的用法大致有三种。下面代码是watch的一种简单的用法,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友参考下吧
    2018-11-11
  • vue接入腾讯防水墙代码

    vue接入腾讯防水墙代码

    这篇文章主要介绍了vue接入腾讯防水墙代码,代码超级简单,非常不错,具有一定的参考借鉴价值 ,需要的朋友可以参考下
    2019-05-05
  • Vue中内置指令与自定义指令语法详解

    Vue中内置指令与自定义指令语法详解

    这篇文章主要为大家介绍了Vue中内置指令与自定义指令语法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • Vue3 SFC 和 TSX 方式自定义组件实现 v-model的详细过程

    Vue3 SFC 和 TSX 方式自定义组件实现 v-model的详细

    v-model 是 vue3 中的一个内置指令,很多表单元素都可以使用这个属性,如 input、checkbox 等,咱可以在自定义组件中实现 v-model,这篇文章主要介绍了Vue3 SFC 和 TSX 方式自定义组件实现 v-model,需要的朋友可以参考下
    2022-10-10
  • 使用vue3指令封装一个图片预览功能

    使用vue3指令封装一个图片预览功能

    这篇文章主要为大家详细介绍了如何使用 vue3 指令封装一个后台管理系统图片预览功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-01-01
  • 详解Vue2 无限级分类(添加,删除,修改)

    详解Vue2 无限级分类(添加,删除,修改)

    本篇文章主要介绍了详解Vue2 无限级分类(添加,删除,修改) ,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • vue-meta实现router动态设置meta标签的方法

    vue-meta实现router动态设置meta标签的方法

    这篇文章主要介绍了vue-meta实现router动态设置meta标签,实现思路非常简单内容包括mata标签的特点和mata标签共有两个属性,分别是http-equiv属性和name属性,本文通过实例代码给大家详细讲解需要的朋友可以参考下
    2022-11-11
  • Element-Plus之el-col与el-row快速布局

    Element-Plus之el-col与el-row快速布局

    el-col是el-row的子元素,下面这篇文章主要给大家介绍了关于Element-Plus之el-col与el-row快速布局的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-09-09

最新评论