09.超全vue组件通信

107 阅读3分钟

组件传值在我们vue的使用过程中一个很重要的功能,我们日常工作中需要使用各种形式的传值满足的我们的业务需求,传值的方法有很多,需要我们选择合适的.

1.props

props 是父传子中最常见的一种方式, 父组件用v-bind绑定数据

  <hr />
  <Children :count="count" />

子组件用props接受,可以是一个数据,也可以是一个对象详细描述传递参数

  props: {
    // count: Number 简写 或者下面对象形式
    count: {
      type: Number,
      default: 0,
      require: true
    }
  },
  // props: ["count"],

image.png

注意vue是单向数据流,不能直接在子组件修改数据,需要用一个遍历接收,更改变量.

2.emit

子向父传值 子组件emit传递事件,2个参数 1个是事件名 一个是参数,如果有多个参数可以使用对象属性的形式

<template>这是子组件: <button @click="update">修改count的值为2</button></template>
<script setup>
import { defineEmits } from "vue";
const emit = defineEmits(["update"]);
const update = () => {
  emit("update", 2);
};
</script>

父组件用v-on接受 绑定一个事件并执行

<template>
  这是父组件: count:{{ count }}
  <hr />
  <Children @update="update" />
</template>

<script>
import Children from "./Son";
import { ref } from "vue";

export default {
  name: "Father",
  components: {
    Children
  },
  setup() {
    const count = ref(1);
    const update = (num) => {
      count.value = num;
    };
    return { count, update };
  }
};
</script>

3.attrs $listeners

attrs和pros和props使用差不多 只是他不用声明可以直接使用,vue3在子组件中使用useAttrs引入

<template>
  {{ attrs }}
</template>
<script setup>
import { useAttrs } from "vue";
const attrs = useAttrs();
</script>

父组件使用v-bind传值

<template>
  这是父组件: count:{{ count }}
  <hr />
  <Children :count="count"/>
</template>
<script setup>
import Children from "./Son";
import { ref } from "vue";
const count = ref(1);
</script>

image.png

$listeners差不多就不详细写了 反向传值emit

4.ref传值

ref在父组件可以直接调用子组件暴露出来的变量或者方法

<template>
  这是父组件: count:{{ count }} <button @click="getCount">获取子组件count</button>
  <button @click="setCount">改变子组件count</button>
  <hr />
  <Children ref="refChildren" />
</template>

<script setup>
import Children from "./Son";
import { ref } from "vue";
const count = ref(1);
const refChildren = ref();
const getCount = () => {
  console.log("子组件count:", refChildren.value.count2);
};
const setCount = () => {
  refChildren.value.getCount(5);
};
</script>

子组件需要通过defineExpose暴露出去

<template>这是子组件:{{ count2 }}</template>
<script setup>
import { ref, defineExpose } from "vue";
const count2 = ref(2);
const getCount = (num) => {
  count2.value = num;
};
defineExpose({
  count2,
  getCount
});
</script>

5.eventbus

事件总线 这个在vue3中已经被官方废除了,实现原理就是一个发布订阅模式.这里就用vue2来实现了. main.里面初始化

import Vue from 'vue';
Vue.prototype.$eventBus = new Vue();

在子组件2 触发事件 发布事件

<template>
  <div class="xx-container">
    这是子组件2:count:{{ count
    }}<button @click="changeCount">修改子组件1的count</button>
  </div>
</template>
<script>
export default {
  props: {},
  data() {
    return {
      count: 2
    };
  },
  methods: {
    changeCount() {
      this.$eventBus.$emit('changeChildren1Count', 5);
    }
  }
};
</script>

在 子组件1中 监听事件

<template>
  <div class="xx-container">这是子组件1:count:{{ count }}</div>
</template>
<script>
export default {
  data() {
    return {
      count: 1
    };
  },
  mounted() {
    this.$eventBus.$on('changeChildren1Count', (num) => {
      this.count = num;
    });
  }
};
</script>
<style lang="less" scoped></style>

6.provide,inject

子孙通信,当我们组件有多层嵌套且有多处使用,更改的时候可以使用provide,inject来通讯 父组件用provide来传递数据和方法

<template>
  这是父组件: count:{{ count }}
  <hr />
  <Children />
</template>

<script setup>
import Children from "./Son";
import { ref, provide } from "vue";
const count = ref(1);
const changeCount = () => {
  count.value = 5;
};
provide("getCount", count);
provide("changeCount", changeCount);
</script>

子孙组件用inject来接受数据和触发方法

<template>
  这是父组件: count:{{ count }}
  <hr />
  <Children />
</template>

<script setup>
import Children from "./Son";
import { ref, provide } from "vue";
const count = ref(1);
const changeCount = () => {
  count.value = 5;
};
provide("getCount", count);
provide("changeCount", changeCount);
</script>

image.png

7.parent,parent,children

vue2中可以直接通过this.parent和this.children访问父组件/子组件中的数据和方法 这个在vue3中废弃了 所以在这里用vue2实现 父组件

<template>
  <div class="xx-container">
    这是父组件:count:{{ count }}
    <hr />
    <Children1 />
  </div>
</template>
<script>
import Children1 from './son1.vue';
export default {
  components: {
    Children1
  },
  data() {
    return {
      count: 1
    };
  },
  methods: {
    change() {
      this.count = 4;
    }
  }
};
</script>

子组件this.$parent / this.children[0]

<template>
  <div class="xx-container">
    这是子组件 <button @click="change1">修改父组件count为4</button
    ><button @click="change2">修改父组件count为5</button>
    <hr />
    <Grandson />
  </div>
</template>
<script>
import Grandson from './grandson.vue';
export default {
  components: { Grandson },
  data() {
    return {
      count: 2
    };
  },
  methods: {
    change1() {
      this.$parent.change();
    },
    change2() {
      this.$children[0].change();
    }
  }
};
</script>

孙组件

<template>
  <div class="xx-container">这是孙组件:count:{{ count }}</div>
</template>
<script>
export default {
  data() {
    return {
      count: 3
    };
  },
  methods: {
    change() {
      this.count = 5;
    }
  }
};
</script>

image.png

8.全局vuex/pinia

全局的状态管理 store仓库里有5个模块 state,getter,mutation,action,module. 可以再组件内访问state的数据,或者调用mutation的同步方法,action的异步方法.具体的可以去看上一篇文字,这里就不做详细介绍了. juejin.cn/post/712986…

9.本地数据缓存sessionStorage,localStorage,indexDB

这里和vue没有直接关联,不属于vue特有的,谁都可以用.vue也可以用他来传递数据,但是要注意组件的加载顺序,如果还未存入获取不了 A组件:

<template>
  这是父组件: count:{{ count }}
  <hr />
  <Children />
</template>

<script setup>
import Children from "./Son";
import { ref } from "vue";
const count = ref(1);
sessionStorage.setItem("count", count.value);
</script>

B组件

<template>
  这是父组件: count:{{ count }}
  <hr />
  <Children />
</template>

<script setup>
import Children from "./Son";
import { ref } from "vue";
const count = ref(1);
sessionStorage.setItem("count", count.value);
</script>

vue可以使用vueuse库中的useLocalStorage,可以将LocalStorage中的数据封装成响应式的 vueuse.org/core/useloc…

10.路由传值

路由传值也是vue中通信方式中重要的一种,在页面跳转中传递重要的信息,有parmas和query2中形式,

query

query 传递一个对象,拼接在路由后面.参数可见.刷新页面不会消失 类似于get请求

params

params 传递一个对象,参数不可见,刷新页面就消失了,类似于post请求

具体的用法会在明天或者后天更新.这里就不做详细介绍了

11全局变量

vue2

在main.js中设置

Vue.prototype.$count = 1;

在组件中使用

<template>
  <div class="xx-container">这是父组件:count:{{ count }}</div>
</template>
<script>
export default {
  data() {
    return {
      count: this.$count
    };
  }
};
</script>

vue3

在vue3 mian.js中挂载到app.congif上

const app = createApp(App);
app.config.count = 1;

在组件中获取

<template>这是父组件: count:{{ count }}</template>
<script setup>
import { getCurrentInstance } from "vue";
const {
  appContext: {
    config: { count }
  }
} = getCurrentInstance();
</script>

image.png

12在js中导出一个响应式数据和方法

在一个js文件中定义一个响应式数据

import { ref } from "vue";
export const count = ref(1);

在组件中引入数据

<template>这是父组件: count:{{ count }}</template>
<script setup>
import { count } from "./data";
</script>

这里改变数据的方法同理,还可以传入一个回调自己diy

image.png

以上12中通信方式是我目前在开发过程中使用/知道的方法,如果还有没列举道德欢迎大家补充.