当前位置:首页 » 《随便一记》 » 正文

【Vue】Vue2组件传参总结来了(建议收藏)

21 人参与  2023年04月05日 16:57  分类 : 《随便一记》  评论

点击全文阅读


Vue2组件传参总结来了(建议收藏)


前言

对于Vue来说组件的数据通信非常重要,面试中也是频繁出现,为了更加深入了解组件的数据通信,本文专门总结了一下组件之间通信的场景和通信方式如何实现。

组件通信大致有以下场景:

父子组件通信隔代组件通信兄弟组件通信跨路由组件通信

接下来本文将介绍以下通信方式

一、props/emit传参

使用介绍

props/emit 传参是最基础的组件通信方式,父组件通过props 可以向子组件进行通信,子组件通过emit 向父组件进行通信。

使用场景

父子组件通信

使用方法

1.父组件向子组件传参

通过在子组件中定义 props 参数,父组件传入子组件中定义的参数属性来实现通信。

//父组件<template>    < msg :word="word"></ msg>  </template>  <script>  import Msg from './Msg.vue'  export default {    components: {    msg    },    data() {      return {        word: '该做核酸了'      }    }  }  </script>//子组件 <template>    <div>      <span>{{word}}</span>    </div>  </template>  <script>  export default {    props: {     word: {        type: String,        default: 'test'      }    }  }  </script>
2.自组件向父组件传参

Vue 通过 on/emit 的方式来实现子组件向父组件传参,在子组件中使用 $emit 绑定一个自定义事件,当执行语句时,就会将参数传递给父组件;父组件通过$on 来监听子组件自定义的事件获取子组件传递的参数。

//父组件<template>    <msg :num="num" @add='add'></ msg>  </template>  <script>  import Msg from './Msg.vue'  export default {    components: {    msg    },    data() {      return {        num:10      }    },    methods:{    add(res){    this.num = res    }    }  }  </script>//子组件 <template>    <div>      <button ></button>    </div>  </template>  <script>  export default {    props: {     num: {        type: Number,        default: 100      }    },    methods:{    add(){    this.$emit('add',this.num + 1)    }    }  }  </script>

使用总结

最常见的父子组件通信方式
props支持参数验证
emit 只会触发父组件的监听事件
不适合多层次组件参数传递,需要逐层传递参数

二、$parent/ $children传参

使用介绍

通过 $patent / $children 可以拿到父子组件的实例 ,从而调用实例里的数据方法,实现父子组件通信

使用方法

1.引用父组件

在这里插入图片描述

2.引用子组件 $children 和 $refs

在这里插入图片描述

三、事件bus

使用介绍

事件bus :eventBus ,相当于所有组件共用一个事件中心,这个事件中心用来管理事件,当我们需要的时候就向事件中心发送或者接收事件。通过共享一个vue实例,使用该实例的 $on 以及 $emit 实现数据传递。

跨层级访问数据

任意组件只要导入 bus (bus.js) 就可以随意,发送 与监听数据

使用场景(非父子关系)

隔代组件通信兄弟组件通信

使用方法

1.新建 bus.js

在 utils 文件夹里新建bus.js
在这里插入图片描述

//导入vueimport Vue from "vue";// 导出vue 创建的空实例var bus = new Vue();export default bus;
2.发送数据

在要发送数据的组件中导入bus.js ,并使用bus.$emit

在这里插入图片描述

<template>  <div id="app">  </div></template><script>import bus from "@/utils/bus";export default {  //App.vue 作为数据的提供方  provide: {    a: "明天要放假了", // 只要子孙元素都可以接收  },  name: "app",  components: { TabsCom },  data() {    return {      msg: "来自app",    };  },  //在mounted 里面发送  mounted() {    setTimeout(() => {      this.changeIt();    }, 5000);  },  //在任意组件中都可以发送和接收  methods: {    changeIt() {      this.msg = "下楼做核酸了 ";      bus.$emit("msgchange", this.msg);    },  },};</script>
3.接收数据

在有接收数据的组件中导入 bus.js ,并使用bus.$on(注意this)

在这里插入图片描述

<template>  <div class="nav" :style="{ backgroundColor: bg_color, color: text_color }">    <div class="left" @click="$emit('left-click', $event)">      <slot name="icon_left"></slot> {{ left_text }}    </div>    <div class="title">      <slot name="title"></slot>      {{ title }}    </div>    <div class="right" @click="$emit('right-click', $event)">      <slot name="icon_right"></slot> {{ right_text }}    </div>  </div></template><script>import bus from "@/utils/bus";export default {  //接收的地方要监听数据,$event 就是app页面发送的数据  created() {    bus.$on("msgchange", ($event) => {      console.log("msgchange");      this.myMsg = $event;    });  },  data() {    return {      myColor: "#f30",      myMsg: "",    };  },  props: {    text_color: {      type: String,      default: "#000",    },    bg_color: {      type: String,      default: "#fff",    },    title: {      type: String,      default: "",    },    left_text: {      type: String,      default: "返回",    },    right_text: {      type: String,      default: "",    },  },};</script>
  // 组件销毁时需要解绑监听  beforeDestroy () {    bus.$off('myMsg')  }

使用总结

常用于多层嵌套组件场景下兄弟组件或任意两个组件之间通讯。$on 事件 是不会自动清除销毁的,需要手动销毁,可以在beforeDestroy中解绑监听,避免重复触发。适合简单场景下使用,太过复杂的场景建议使用 vuex

四、provide/inject传参

使用介绍

常用于多层嵌套组件封装,当后代组件需要用到顶层组件的数据方法时可以使用这个。provide 提供数据,所有子孙都可以通过 inject注入数据,inject 接收父辈组件提供的数据。provideinject 依赖注入 ,跨层级访问(只读)

使用场景

隔代组件通信

使用方法

在这里插入图片描述

使用总结

跨层级组件之间通信传递的属性是非响应的如果需要传递响应属性,采用函数的方式传入对象复杂组件不建议使用此方式传参,任意层级都能访问导致数据追踪比较困难

五、Vuex全局数据共享

使用介绍

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态, 并以相应的规则保证状态以一种可预测的方式发生变化。

简单来说,Vuex 在大型,特大型,vue项目中做数据统一管理的;在vuex中存储的数据,每个组件都可以引用到,vuex中的数据发生变化,引用该数据的组件会自动更新。

Vuex包含以下几个部分:全局唯一的状态管理仓库(state),同步操作(mutations)、异步操作(actions)、缓存依赖(getters),模块(modules)

具体使用方法访问官网查看 ==> Vuex官网

什么数据可以存储在Vuex里面

如果一个数据,需要在多个vuex的store中如:用户数据,购物车数据

为什么要把登录转换到Vuex中

登录后成功的数可以全局共享为了重复利用,登录功能可能不止在登录页面 首页点击弹框登录购物车 跳转前,弹框登录登录位置会有很多 如果写在Vuex 只需要在登录地方,$store.dispatch('login',data) 方法就可以

使用场景

隔代组件通信兄弟组件通信跨路由组件通信

使用方法

1.state
存放状态$store.state.xxx访问
在这里插入图片描述
//定义vuex的数据地方state:{cartNum:10​}//在组件访问数据​$store.state.cartNum
2.mutations
定义修改数据的方法,改变状态的唯一方法$store.commit(‘xxx’,data)
在这里插入图片描述
mutations: {    //修改state数据必须在mutations中的方法    //方法名建议大写     SET_CART_NUM(state, data) {          //修改cartNum的值           state.cartNum = data;                }        },        //在组件中访问mutations的方法$store.commit('SET_CART_NUM',100)
3.actions
定义异步延迟方法$store.dispatch(‘xxx’,data)
在这里插入图片描述
    actions: {       //定义异步,网络延迟等方法      //只能调用mutations,不能直接修改state         getCartNum(context,data){              //可以执行网络请求,等待延迟             setTimeout(()=>{        //等待4秒后执行mutations 的SET_CART_NUM方法                              context.commit('SET_CART_NUM',data)                        },4000)                }        },//在组件中调用$store.dispatch('getCartNum',33)
4.getters
从现有state 数据计算出新的数据$store.getters.xxx
在这里插入图片描述
  getters: {                //从现有数据计算新的数据,每个商品佣金是0.5元                //fee 佣金会随着cartNum变化而变化                fee:function(state){                        return state.cartNum*0.5                }        },//在组件中调用$store.getters.fee

小案例

module 把vuex的数据分成多个子模块(添加子组件)

1.user.js
import { Login, Reg } from "@/api/user";import $router from "@/router/index";//导入vueimport Vue from "vue";//导入插件import Notify from "@/plugin/Notify";//使用插件Vue.use(Notify);export default {    state: {        //用户信息        userInfo: {            name: "",            score: 0,        },        //token 标识        token: "",    },    mutations: {        //负责修改用户信息        SET_USERINFO(state, data) {            //更新state 的userInfo            state.userInfo = data;            //本地存储用户信息            localStorage.setItem("user", JSON.stringify(data));        },        //修改token        SET_TOKEN(state, data) {            state.token = data;            //token 本来就是字符串,不需要            localStorage.setItem("token", data);        },    },    actions: {        //页面退出        logout(context) {            context.commit("SET_USERINFO", {});            context.commit("SET_TOKEN", "");        },        //负责登录  (登录是异步的需要放在actions中)        login(context, data) {            Login(data)                .then((res) => {                    //200 代表成功其他代表失败                    if (res.data.code === 200) {                        Notify.success(res.data.msg || "登录成功");                        //登录成功弹出设置用户信息与设置token                        context.commit("SET_USERINFO", res.data.user);                        context.commit("SET_TOKEN", res.data.token);                        //跳转到redirect 对应页面                        //获取当前留言信息                        var $route = $router.history.current;                        //获取查询参数                        var redirect = $route.query.redirect || "/";                        //实现跳转                        $router.replace(redirect);                    } else {                        //登录不成功清空用户信息                        Notify.danger(res.data.msg || "登录失败");                        context.commit("SET_USERINFO", {});                        context.commit("SET_TOKEN", "");                    }                })                //失败显示网络失败                .catch((err) => {                    console.log(err);                    Notify.danger("网络失败");                });        },};
2.使用
<template>  <div>    <h1>我的</h1>    <p v-if="$store.state.user.userInfo.name">      <label>        <input type="file" name="file" ref="myfile" @change="fileChange()" />        <img :src="user.avatar" width="100" class="avatar" />      </label>      {{ $store.state.user.userInfo.name }},积分:{{        $store.state.user.userInfo.score      }}      <a href="" @click.prevent="$store.dispatch('logout')">退出</a>    </p>    <p v-else>      <router-link to="/login?redirect=/user">登录</router-link> <br />      <router-link to="/reg">注册</router-link>    </p>  </div></template>

使用总结

任意组件之间通信,多组件之间通信跨路由组件之间通信刷新浏览器,vuex数据会丢失,可以采用vuex-persistedstate插件解决此问题适合场景复杂的大型项目,简单的业务场景不建议使用

往期传送门

【Vue】Vue2生命周期详解


【Vue】axios的二次封装和使用(附详细代码)


【Vue】vue组件和vue插件的创建和使用(底部栏组件、Toast 和 Notify通知插件)


【Vue】 vue2路由搭建和搭建vue2脚手架(入门级)



点击全文阅读


本文链接:http://zhangshiyu.com/post/58504.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1