浅谈Vue组件通信

本文介绍了Vue.js中组件间通信的几种常见方法,包括v-bind(props)、自定义事件$emit、插槽以及状态管理库Vuex。重点讲解了如何通过父组件向子组件传递数据、子组件向父组件反馈信息,以及如何利用Vuex进行组件间的共享状态管理。
摘要由CSDN通过智能技术生成

为什么要通信(必要性)

  1. 父子组件:

    1. 父对子:父组件可能是主页组件,子组件可能是帖子组件,发帖子需要父组件提供的用户信息(如名字,头像等),即此刻父组件传递其用户信息给到子组件中。

    2. 子对父:如果在子组件中点赞评论,需要及时反馈到父组件中,完成主页更新,即此刻需要子组件传递其相关信息给到父组件中。

  2. 兄弟组件:比如产品列表组件和购物车列表组件,产品列表组件可以将用户选择的产品信息传递给购物车组件,以便购物车组件能够在界面上显示所选产品和计算总价。基于现实情况,两个组件之间有信息需要传递,故这是一个例子!

  3. 祖孙组件:一个新闻阅读应用中,顶层组件是新闻列表,包含了子组件新闻卡片;而新闻卡片又包含孙组件,如评论区域。用户在评论区域进行评论时,可以通过祖孙组件之间的通信将评论内容传递给顶层组件,由顶层组件进行数据的处理和提交。又比如毕设的选题,开题报告,初稿,这些也都是需要一步一步传递信息下来的。各个组件之间有相关性。

方法有哪些

1. v-bind+props(父传子)

看以下例子,记一个,组件中的数据共有三种形式:data、props、computed

父组件

<template>
  <div id="app">
    <!-- <img alt="Vue logo" src="./assets/logo.png"> -->
    <!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
    <!-- <testHs></testHs> -->
    
    <!-- 把变量a,数组b,对象c 都传给子组件childZj -->
    <!-- 通过属性绑定指定,将这三个绑定到子组件上(当然v-bind也可以缩写) -->
    <!-- 第一个a是子组件中定义的a,第二个a是父组件中的a,故第一个可以改为你想要的 -->
    <childZj v-bind:a="a" v-bind:b="b" v-bind:c="c"></childZj> 

  </div>
</template>

<script>
import childZj from './components/childZj.vue'

export default {
  name: 'App',
  components: {
    childZj,
  },
  data(){
    return {
      a:'字符串!',
      b:['1','2','3'],
      c:{
        d:'1'
      }
    }
  }
}
</script>

子组件

<template>
  <div>
    <p>{{ a }}</p>
    <ul>
        <li v-for="(bb ,index) in b" :key="index">{{ bb }}</li>
    </ul>
    <p>{{ c }}</p>
  </div>
</template>

<script>
export default {
    name:'childZj',
    props:{
        a:{
            type:String,
            required:true
        },
        b:{
            type:Array,
            required:true
        },
        c:{
            type:Object,
            required:true
        }
    }

}
</script>

<style>

</style>

2. $emit+v-on (自定义事件,子传父)

子组件通过事件向父组件传值,父组件在子组件标签上通过v-on接受对应的事件,通过事件拿到值

子组件

<template>
  <div>
    <button @click="childToP">我是子组件的button,点击可通过事件方式向父组件传值</button>
  </div>
</template>

<script>
export default {
    name:'childZj2',
    methods:{
        childToP(){
            console.log('子组件开始向父组件传值');
            this.$emit("a",'我是子传给父的字符串,变量名为a')
            this.$emit("b",['1','2','3'])
            this.$emit("c",{d:'对象!'})
        }
    }

}
</script>

<style>

</style>

父组件

<template>
  <div id="app">
    
    <!-- 子传父 -->
    <!-- v-on:a="aa" v-on:b="bb" v-on:c="cc" -->
    <!-- 子组件通过事件,以$emit发生事件的方式向父组件发数据 -->
    <!-- 在父组件这边的操作是 1 对应子组件标签里面也是通过绑定事件的方式拿到,即v-on -->
    <!-- v-on:key="value" key是子组件的自定义名字,父组件这里要和子组件保持一致-->
    <!-- value(e),则value是函数名,里面的e是子传父的值 -->
    <childZj2 @a="aa" v-on:b="bb" v-on:c="cc"></childZj2>
    <div>从子组件拿到的字符串:{{ a_data }}</div>
    <div>从子组件拿到的数组:{{ b_data }}</div>
    <div>从子组件拿到的对象:{{ c_data }}</div>

  </div>
</template>

<script>
import childZj2 from './components/childZj2.vue'

export default {
  name: 'App',
  components: {
    // childZj1,
    childZj2
  },
  data(){
    return {
      a_data:'',
      b_data:[],
      c_data:{}
    }
  },
  methods:{
    // 上面已经写了事件,在这里写好对应的即可。
    aa(e){
      console.log('从子组件拿到的字符串为:'+e);
      this.a_data=e
    },
    bb(e){
      console.log('从子组件拿到的数组为:'+e);
      this.b_data=e
    },
    cc(e){
      console.log('从子组件拿到的对象为:'+e);
      this.c_data=e
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

图示

3. 插槽(父传子->模板内容,记,模板是子提供,父提供内容)

相对于props是父->子,父传递的是值,私以为,插槽的存在是子可以给到父模板,然后内容父自定义,更为灵活了

可分为

  1. 默认插槽

  2. 具名插槽(在父组件中使用 <BaseLayout> 时,我们需要一种方式将多个插槽内容传入到各自目标插槽的出口。此时就需要用到具名插槽了,顾名思义,用name去定义),动态插槽名,

  3. 作用域插槽(同时使用父组件域内和子组件域内的数据。要做到这一点,我们需要一种方法来让子组件在渲染时将一部分数据提供给插槽!可以像对组件传递 props 那样,向一个插槽的出口上传递 attributes),具名作用域插槽

具体见文档

4. Vuex(万能)

多个组件共用一些数据的时候,可以用Vuex来实现

1. 状态管理库,集中管理项目中组件共用的数据
2. 有四个部分(形式:对象)
  1. state:存储数据

  2. mutations:修改state的数据(同步,唯一)

  3. actions:处理业务逻辑,处理异步问题

  4. getter:理解为计算属性,简化数据

3. 为什么不在mutations里面处理业务和异步问题?为什么不在actions里面修改数据?

如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。

(能用 devtools 追踪状态变化。

事实上在 vuex 里面 actions 只是一个架构性的概念,并不是必须的,说到底只是一个函数,你在里面想干嘛都可以,只要最后触发 mutation 就行。异步竞态怎么处理那是用户自己的事情。vuex 真正限制你的只有 mutation 必须是同步的这一点(在 redux 里面就好像 reducer 必须同步返回下一个状态一样)。

同步的意义在于这样每一个 mutation 执行完成后都可以对应到一个新的状态(和 reducer 一样),这样 devtools 就可以打个 snapshot 存下来,然后就可以随便 time-travel 了。

如果你开着 devtool 调用一个异步的 action,你可以清楚地看到它所调用的 mutation 是何时被记录下来的,并且可以立刻查看它们对应的状态。其实我有个点子一直没时间做,那就是把记录下来的 mutations 做成类似 rx-marble 那样的时间线图,对于理解应用的异步状态变化很有帮助。)(源自作者知乎https://www.zhihu.com/question/48759748~)

做了代码隔离,不非受控的代码集中到 action,mutation只做纯函数的状态改变

4. 注意可以实现模板化开发
5. 最后通过一张图了解流程

5. 全局事件总线(万能)

书写方式:Vue.prototype.$bus=this;(待补充完整)

6. pubsub.js(万能)

发布与订阅,在React用得比较多(待补充完整)

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值