浅谈Vue不同场景下组件间的数据“交流”
 
Vue的官方文档可以说是很详细了。在我看来,它和react等其他框架文档一样,讲述的方式的更多的是“方法论”,而不是“场景论”,这也就导致了:我们在阅读完文档许多遍后,写起代码还是不免感到有许多困惑,因为我们不知道其中一些知识点的运用场景。这就是我写这篇文章的目的,探讨不同场景下组件间的数据“交流”的Vue实现
 

父子组件间的数据交流

父子组件间的数据交流可分为两种:
1.父组件传递数据给子组件
2.子组件传递数据给父组件

父组件传递数据给子组件——props

这是组件数据沟通中最常见的场景:你让父组件掌握了数据源,然后传递给子组件,供子组件使用
 

许多人会说,这很简单!用props嘛! 对,正因如此,它不是我要讲的主要内容,不过我们还是用代码简单过一遍:
父组件
<template>
  <div id="father">
    {{ '我是父组件' }}
    <son :text = "text"></son>
  </div>
</template>
 
<script>
import son from './son.vue'
export default {
  data: function () {
    return {
      text: '从父组件传来的数据'
    }
  },
  components: {
    son: son
  }
}
</script>
 
<style scoped>
</style>
子组件:
<template>
  <div>
    {{ '我是子组件,我接收了' + text }}
  </div>
</template>
 
<script>
export default {
  props: {
    text: { type: String, default: '' }
  }
}
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
demo:
 

在这个demo里面,我们把“从父组件传来的数据”这一个字符串通过props传递给了子组件
 
如果我们希望在子组件中改变父组件的数据的话,可以在父组件中定义一个能改变父组件数据的函数,然后通过props将该函数传递给子组件,并在子组件在适当时机调用该函数——从而起到在子组件中改变父组件数据的效果

子组件传递数据给父组件

子组件传递数据给父组件   方式一:回调传参

父组件:
<template>
  <div id="father">
    {{ '我是父组件,名称是' + componentName }}
    <son  :changeComponentName = "changeComponentName"></son>
  </div>
</template>
 
<script>
import son from './son.vue'
export default {
  data: function () {
    return {
      componentName: '组件A'
    }
  },
 
  methods: {
    changeComponentName: function (newComponentName) {
      this.componentName = newComponentName
    }
  },
 
  components: {
    son: son
  }
}
</script>
 
<style scoped>
  #father div{
    padding: 10px;
    margin: 10px;
    border: 1px solid gray;
  }
</style>
子组件:
<template>
  <div>
    <p>我是子组件:一个button</p>
    <button @click="() => changeComponentName(newComponentName)">
      把父组件的名称修改为:彭湖湾的组件
    </button>
  </div>
</template>
 
<script>
export default {
  data: function () {
    return {
      newComponentName: '彭湖湾的组件'
    }
  },
  props: {
    changeComponentName: {
      type: Function,
      default: () => { }
    }
  }
}
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

demo:

点击前:

点击后:

图解:

点击子组件(按钮)的时候,将父组件的名称从“A”修改为“彭湖湾的组件”
 
我们从父组件向子组件传递了一个函数(changeComponentName)。并在子组件调用这个函数的时候,以参数的形式传递了一个子组件内部的数据(newComponentName)给这个函数,这样,在父组件中定义的函数(changeComponentName)就可以取得子组件传来的参数了
 
【PS】 命名太长不好意思
 

子组件传递数据给父组件   方式二:自定义事件

父组件:
<template>
  <div id="father">
    <div>
      {{ '我是父组件,我的名称是:' + fatherComponentName }}
      <son  v-on:changeComponentName = "changeComponentName"></son>
    </div>
  </div>
</template>
 
<script>
import son from './son.vue'
export default {
  data: function () {
    return {
      fatherComponentName: 'A组件'
    }
  },
 
  methods: {
    changeComponentName: function (componentName) {
      this.fatherComponentName = componentName
    }
  },
 
  components: {
    son: son
  }
}
</script>
 
<style scoped>
  #father div{
    padding: 10px;
    margin: 10px;
    border:1px solid grey;
  }
</style>
子组件:
<template>
  <div>
    <p>我是子组件:一个按钮</p>
    <button @click="clickCallback">
      修改父组件的名称为:彭湖湾的组件
    </button>
  </div>
</template>
 
<script>
export default {
  data: function () {
    return {
      fatherComponentName: '彭湖湾的组件'
    }
  },
  methods: {
    clickCallback: function () {
      this.$emit('changeComponentName', this.fatherComponentName)
    }
  }
}
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

demo:

点击前:

点击后:

 
 图解:

通过$emit(event, [...参数]),所有的参数将被传递给监听器回调,也就是我们在父组件中定义的changeComponentName方法,从而实现从子组件中给父组件传参

兄弟组件间的数据交流(有共同父组件的兄弟组件)

父组件:
<template>
  <div id="father">
    <div>
      {{ '我是父组件:father' }}
      <eldest-son :text = "text"></eldest-son>
      <youngest-son :changeText="changeText"></youngest-son>
    </div>
  </div> 
</template>
 
<script>
import eldestSon from './eldestSon.vue'
import youngestSon from './youngestSon.vue'
 
export default {
  data: function () {
    return {
      text: '我是一行文本'
    }
  },
 
  methods: {
    changeText: function () {
      this.text = '我是经过改动的一行文本'
    }
  },
 
  components: {
    eldestSon: eldestSon,
    youngestSon: youngestSon
  }
}
</script>
 
<style>
    #father div{
      border: 1px solid grey;
      padding: 10px;
      margin: 10px;
    }
</style>
兄弟组件1:
<template>
  <div>
    <p>我是兄弟组件:eldestSon</p>
    <p>我有一个可变数据text:{{ text }}</p>
  </div>
</template>
 
<script>
export default {
  props: {
    text: {
      type: String,
      default: ''
    }
  }
}
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
兄弟组件2:
<template>
  <div>
    <p>我是兄弟组件:youngestSon</p>
    <button @click="changeText">更改eldestSon兄弟组件中的文本</button>
  </div>
</template>
 
<script>
export default {
  props: {
    changeText: {
      type: Function,
      default: () => {}
    }
  }
}
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

点击前:

点击后:

图解:

如果两个兄弟组件间存在这种数据关系的话,我们可以尝试寻找其共同的父组件,使数据和相关方法“提升”到父组件内部,并向下传给两个子组件
 
这样,其中一个子组件取得了数据,另外一个子组件取得了改变数据的方法,便可以实现上述的数据沟通
 
【注意】这种场景存在局限性,它要求两个组件有共同父组件。对于这种场景之外的处理方法,请看下文
 

全局组件间的数据交流——Vuex

 
我上述的许多场景里面,都运用到了props或者函数传参的方式去处理组件间的数据沟通。然而在稍大型的应用里面,它们都不约而同地给我们带来了很大的麻烦
例如:
1.通过props从父组件向子组件传递数据
对于直接的父子关系的组件,数据流显得很简洁明确,但在大型应用里面,我们上下嵌套许多个组件的时候,这就会导致我们的代码非常地繁琐,并难以维护
 
2.对于没有共同的父组件的兄弟组件,函数传参的数据传递方式也无能为力了,Vue文档里介绍到,你可以通过以$emit和$on函数为基础的“事件总线”沟通数据,但它无法应对更加大型的应用
 
这个时候Vuex就成为了实现全局组件间数据交流的最佳方案了
Vuex拥有一个包含全部顶层状态的单一数据源(state)
1.所有的组件都可以使用这个单一数据源里面的数据
2.所有的组件都可以通过派发 动作(actions)修改这个单一数据源里的数据
 

原本要“走很多弯路”才能实现沟通的数据流,一下子就找到了最短的捷径
 

实现View层的数据和model层的解耦

 
在1,2小节中处理的数据(Vue)和第三小节中处理的数据(Vuex),在很多时候是两种不同类型的数据,前者是属于View层,仅负责单纯的UI展示,而model层的大多是从后端取得后注入的数据。
 
一点建议:
1.Vue部分的代码负责构建View层
2.Vuex部分的代码负责构建model层
(上述的Vue指的是Vuex之外的框架体系)
以上述两点为基础,决定某部分的代码到底要写进Vue里面还是写进Vuex里面,并尽量将两者分开,从而实现View层和model层的解耦,提高前端代码的可维护性和扩展性
 

【Vue】浅谈Vue不同场景下组件间的数据交流的更多相关文章

  1. 浅谈Vue不同场景下组件间的数据交流

    浅谈Vue不同场景下组件间的数据“交流”   Vue的官方文档可以说是很详细了.在我看来,它和react等其他框架文档一样,讲述的方式的更多的是“方法论”,而不是“场景论”,这也就导致了:我们在阅读完 ...

  2. 浅谈Vue下的components模板

    浅谈Vue下的components模板在我们越来越深入Vue时,我们会发现我们对HTML代码的工程量会越来越少,今天我们来谈谈Vue下的 components模板的 初步使用方法与 应用 我们先来简单 ...

  3. 浅谈Vue.js

    作为一名Vue.js的忠实用户,我想有必要写点文章来歌颂这一门美好的语言了,我给它的总体评价是“简单却不失优雅,小巧而不乏大匠”,下面将围绕这句话给大家介绍Vue.js,希望能够激发你对Vue.js的 ...

  4. Vue浅谈

    谈Vue 最近在学习Vue相关的知识点并且也做一些练手,就在学习过程中出现的各种坑爹的地方做一个总结!之后再遇到也不会抓瞎. 1.Vue工程的安装 (1)首先先安装node.js这是Vue的运行基础. ...

  5. 浅谈Vue响应式(数组变异方法)

    很多初使用Vue的同学会发现,在改变数组的值的时候,值确实是改变了,但是视图却无动于衷,果然是因为数组太高冷了吗? 查看官方文档才发现,不是女神太高冷,而是你没用对方法. 看来想让女神自己动,关键得用 ...

  6. 浅谈Vue模板的那些事儿

    接触过vue的童鞋都知道,组件的模板一般都是在template选项内定义的,如 Vue.component('child-component', { template: '<h3>我是闰土 ...

  7. 浅谈Vue中计算属性(computed)和方法(methods)的差别

    浅谈Vue中计算属性(computed)和方法(methods)的差别 源码地址 methods方法和computed计算属性,两种方式的最终结果确实是完全相同 计算属性是基于它们的响应式依赖进行缓存 ...

  8. 浅谈在ES5环境下实现const

    最近看到一个面试题--用ES5实现const.作为JS初学者的笔者知道在ES6中有const命令,可以用来声明常量,一旦声明,常量的值就不可改变.例如: 1234567891011 const Pi ...

  9. 040——VUE中组件之组件间的数据参props的使用实例操作

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. Mac osx 启用和关闭root用户

    设置->群组和用户->点击小

  2. 特级教师总结的教育之33条(ZZ)

    一位班主任发给家长的一则短信:“无论成绩好坏,请想想:每个孩子都是种子,只不过每个人的花期不同.有的花,一开始就灿烂绽放:有的花,需要漫长的等待.不要看着别人怒放了,自己的那棵还没有动静就着急,相信是 ...

  3. 2019.01.24 bzoj3125: CITY(轮廓线dp)

    传送门 题意简述:给一个n∗mn*mn∗m的网格图,有的格子不能走,有的格子只能竖着走,有的格子只能横着走,问用一条回路覆盖所有能走的格子的方案数. 思路: 就是简单的轮廓线dpdpdp加了一点限制而 ...

  4. 2018.12.22 bzoj3277: 串(后缀自动机+启发式合并)

    传送门 跟这道题是一模一样的. 于是本蒟蒻又写了一遍10min1A庆祝 代码: #include<bits/stdc++.h> #define ri register int using ...

  5. AttributeError: type object 'testClass' has no attribute 'testMothod'

    点击"Unittest for test_post_API.testClass"按钮,点击”Edit configuration...“,弹出对话框Run/Debug config ...

  6. maven下的经常使用的几个元素以及依赖范围的一些知识

    maven的pom.xml配置文件里面的project根节点下的dependencies可以包含一个或者多个dependency元素,以声明一个或者多个依赖,每个依赖都可以包含的元素: groupId ...

  7. SHELL脚本之awk妙用

    对于一个sougou文本文件,解压后大概4G,要求在其基础上切出第一列时间年月日时分秒增加在列中,作为hive的一个索引.先将文件head一下展示格式: [root@Master date]# hea ...

  8. 天使投资、A轮、B轮、C轮

    一般是这样划分的. A轮融资:公司产品有了成熟模样,开始正常运作一段时间并有完整详细的商业及盈利模式,在行业内拥有一定地位和口碑.公司可能依旧处于亏损状态.资金来源一般是专业的风险投资机构(VC).投 ...

  9. ArcGIS的地理坐标系与大地坐标系

    一直以来,总有很多朋友针对地理坐标系.大地坐标系这两个概念吃不透.近日,在网上看到一篇文章介绍它们,非常喜欢.所以在此转发一下,希望能够对制图的朋友们有所帮助. 地理坐标:为球面坐标. 参考平面地是  ...

  10. 阿里云对象存储oss上传文件夹

    最近公司做工程项目,实现文件夹云存储上传. 网上找了一天,发现网上很多代码都存在相似问题,最后终于找到了一个满足我需求的项目. 工程如下: 这里对项目的大文件传输功能做出分析,怎么实现文件夹上传的,如 ...