vue的组件传值
前言
vue的组件传值分为三种方式:父传子、子传父、非父子组件传值
引用官网的一句话:父子组件的关系可以总结为 prop 向下传递,emit向上传递,兄弟之间用bus。
一、父子组件传值
子组件
<template>
<div class="child">
{{ message }}
</div>
</template>
<script>
export default {
name: "Child",
props: {
message: String,
},
};
//vue3这样使用
defineProps({
message: {
type: String,
default: ""
}
})
</script>
父组件
<template>
<div class="father">
<Child :message="text" />
<input v-model="data" />
<button @click="changeChild">点我改变子组件的值</button>
</div>
</template>
<script>
import Child from "./Child";
export default {
name: "Father",
components: { Child },
data() {
return {
data: "",
text: "我是父组件的值",
};
},
methods: {
changeChild() {
this.text = this.data;
},
},
};
</script>
效果图
改变后
详情可参考官网props
二、子组件通过emit来触发父组件的自定义事件
子组件
<template>
<div class="child">
<button @click="setTime">点击我获取父组件的方法</button>
</div>
</template>
<script>
export default {
name: "Child",
methods:{
setTime(){
this.$emit("getTime","可以传参");
}
},
};
//vue3这样使用
const emits = defineEmits(['getTime']);
emits('getTime', "可以传参")
</script>
父组件
<template>
<div class="father">
<Child @get-time="getTime" />
<input v-model="data" />
<p>{{ time }}</p>
</div>
</template>
<script>
import Child from "./Child";
import moment from "moment" //npm i moment -s 下载日期插件
export default {
name: "Father",
components: { Child },
data() {
return {
data: "",
time: "",
};
},
methods: {
getTime(data) {
this.time = moment().format('YYYY年MM月DD日, hh:mm:ss')
this.data = data;
},
},
};
</script>
效果图
改变后
详情可看官网自定义事件
在父组件向子组件传递数据时,若是该数据为对象或数组,并且该对象或数组在父组件内部被修改,则 Vue 不会检测到。这种情况下,我们需要在父组件中设置一个临时变量来保存修改后的对象或数组,并将其传递给子组件。
关于父子组件传值遇到的坑可以看vue修改父组件传值报错
三、vue3子组件通过defineExpose来暴露属性
//子组件
<template>
<div>我是子组件</div>
</template>
<script setup >
import { ref } from 'vue'
const num = ref(1)
const childFn = (item) => {
console.log(item) //这是传下去的值
}
defineExpose({
num,
childFn
})
</script>
//父组件
<template>
<div>我是父组件</div>
<ChildComponent ref="childeRef"></ChildComponent>
</template>
<script setup >
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const childeRef = ref()
onMounted(() => {
console.log( childeRef.value.num) //1
childeRef.value.childFn("这是传下去的值") // 调用子组件函数
})
</script>
四、vue2兄弟之间通过bus
父组件引入两兄弟
<template>
<div class="father">
<Child />
<ChildTwo />
</div>
</template>
<script>
import Child from "./Child";
import ChildTwo from "./ChildTwo";
export default {
name: "Father",
components: { Child, ChildTwo },
};
创建一个bus文件夹下面新建一个bus.js文件
bus.js代码
import Vue from 'vue'
var bus = new Vue();
export default bus;
兄弟组件一号
<template>
<div class="child">
<h1>我是1号兄弟组件</h1>
<button @click="changeTwo">点击我改变2号的值</button>
</div>
</template>
<script>
import Bus from "@/bus/bus"
export default {
name: "Child",
methods:{
changeTwo(){
Bus.$emit("changeName","可以选填的值")
}
},
};
</script>
兄弟组件二号
<template>
<div class="child-two">
<h1>我是2号兄弟组件</h1>
<p>{{ name }}</p>
</div>
</template>
<script>
import Bus from "@/bus/bus";
export default {
name: "ChildTwo",
data() {
return {
name: "uzi",
};
},
mounted() {
Bus.$on("changeName", (data) => { this.name = data });
},
};
</script>
注:用bus传值,父组件引入子组件,子组件需要传值的用Bus.
e
m
i
t
(
)
,接收方用
B
u
s
.
emit(),接收方用 Bus.
emit(),接收方用Bus.on()。
最后看效果图
改变后
五、其它方式传值传值
1.父孙传值
$attrs(向下)
官网是这么解释的
意思就是孙子组件的传值问题可以选择不使用props传值而通过$attrs传递
部分代码
//父组件
<template>
<div class="father">
<compOne :message="message"/>
</div>
</template>
<script>
import compOne from "@/views/Component/compOne";
export default {
name: "father",
components: {
compOne,
},
data() {
return {
message: "父组件传过去的值",
};
},
inheritAttrs: false,
methods: { },
};
</script>
//子组件
<template>
<div class="comp-one">
<compOneChild v-bind="$attrs"/>
</div>
</template>
<script>
import compOneChild from "./compOneChild.vue";
export default {
name: "compOne",
components: { compOneChild },
inheritAttrs: false,
created() {
console.log("我是子组件", this.$attrs);
},
methods: {},
};
</script>
//孙子组件
<template>
<div class="comp-one-child"> </div>
</template>
<script>
export default {
name: "compOneChild",
created() {
console.log("我是孙组件", this.$attrs);
},
inheritAttrs: false,
};
</script>
打印结果
$listeners(向上)
官网是这么解释的
$listeners可以将孙组件的事件和参数传递给父组件
//父组件
<template>
<div class="father">
<compOne
v-on="$listeners"
@compOneChild="compOneChild"/>
</div>
</template>
<script>
import compOne from "@/views/Component/compOne";
export default {
name: "father",
components: {
compOne,
},
data() {
return { };
},
inheritAttrs: false,
methods: {
compOneChild(val) {
console.log("我是父组件", val);
},
},
};
</script>
//子组件
<template>
<div class="comp-one">
<compOneChild v-on="$listeners"/>
</div>
</template>
<script>
import compOneChild from "./compOneChild.vue";
export default {
name: "compOne",
inheritAttrs: false,
methods: {},
};
</script>
//孙子组件
<template>
<div class="comp-one-child">
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="姓名">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.pass"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "compOneChild",
data() {
return {
form: {
name: "",
pass: "",
},
};
},
inheritAttrs: false,
methods: {
onSubmit() {
this.$listeners.compOneChild(this.form);
//this.$emit("compOneChild", this.form); //也可以用这种向上方式传值
},
},
};
</script>
打印结果
2.provide/inject
官网概念:
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。
官网链接provide / inject
用法举例
//祖先组件(刚登陆首页的组件)
data() {
return {
userName: "李潇潇",
};
},
provide() {
return {
newName: () => this.userName,
};
},
//子孙组件(随便跳转详情的组件)
inject: ["newName"],
mounted() {
console.log(this.newName());
console.log(this.userName());
},
methods: {
userName() {
return this.newName();
},
}
最后看跳转子孙的打印值
3.slots
将父组件的内容传递到子组件中
//父组件
<template>
<my-component>
<p>这是向子组件传的值</p>
</my-component>
</template>
//子组件
<template>
<div>
<slot></slot>
</div>
</template>
当然也可以使用作用域插槽将子组件内部的数据传递到父组件
//子组件
<template>
<div>
<slot :data="data" :text="text"></slot>
</div>
</template>
<script setup>
const data = ref('这是向父组件传递的值')
const text = ref('111')
}
</script>
//父组件
<template>
<my-component v-slot="slotProps">
<p>{{ slotProps.data }} {{ slotProps.text}}</p>
</my-component>
</template>
具体可以看vue 插槽
4.parent/children
官网是这么介绍的
所以尽量少用,了解一下就行了。
六、vue2使用VUEX传值
在使用VUEX时先弄懂几个概率。
VUEX是用来干嘛的?
答:vuex是一个状态管理工具存储应用所有组件的状态。
构成:
- state:vuex的基本数据,用来存储变量。
- mutations:提交更改数据,同步更新状态。
- actions:提交mutations,可异步操作。
- getters:是store的计算属性。
- modules:模块,每个模块里面有四个属性。
用官网上的一张图来展示vuex工作的流程
了解更多VUEX知识 可看官网What is Vuex?
实现的功能:有两个组件A和B,有一个公共的名字(默认为UZI),想要使组件A改变名字,组件B名字也改变为一样的,组件B改变反之A也改变。
这是文件目录,为了方便后期管理将store下面新建文件夹与文件,每个文件管理一个或几个状态,这里name.js管理name
store下面的index.js代码
import Vue from 'vue'
import Vuex from 'vuex'
import name from './name/name'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
name,
}
})
name.js代码
const state = { //基本数据,变量
userName: "UZI" //默认值
}
const actions = { //提交mutations
changeNameOne({ commit }, name) {
return commit("changeNameOne", name)
},
changeNameTwo({commit }, name) {
return commit("changeNameOne", name)
}
}
const getters ={ //计算属性
userName(state){
return state.userName
}
}
const mutations = { //同步的数据
changeNameOne(state, obj) {
state.userName = obj
},
changeNameTwo(state, obj) {
state.userName = obj
},
}
export default {
state,
actions,
getters,
mutations
}
NameOne组件
<template>
<div>
<P class="title">组件A</P>
<P class="titleName">名字:{{ userName }}</P>
<div>
<input v-model="name" placeholder="请输入名字" />
<button @click="changeNameOne(name)">修改名字</button>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
export default {
name: "NameOne",
data() {
return {
name: "JackLove",
};
},
methods: {
...mapActions(
["changeNameOne"] //提交这个方法===this.$store.dispatch('changeNameTwo')
),
},
computed: {
...mapGetters(
["userName"] //计算属性===this.$store.getters.userName
),
},
};
</script>
mapActions和mapGetters是vuex的语法糖
NameTwo组件
<template>
<div>
<P class="title">组件B</P>
<P class="titleName">名字:{{ userName }}</P>
<div>
<input v-model="name" placeholder="请输入名字" />
<button @click="changeNameTwo(name)">修改名字</button>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
export default {
name:"NameTwo",
data() {
return {
name: "ClearLove",
};
},
methods: {
...mapActions(
["changeNameTwo"] //提交这个方法===this.$store.dispatch('changeNameTwo')
),
},
computed: {
...mapGetters(
["userName"] //计算属性===this.$store.getters.userName
),
},
}
</script>
最后看效果图,当修改A组件的名字的时候
当修改B组件的名字的时候
PS:最后再加了个组件C,看效果图
PS:还可以这样传参
this.$store.commit(‘name/changeNameOne’,res) (res是需要传的参数)
这样接收参数
this.$store.getters[“workStore/getToken”]
这种有没有方便
七、vue2通过$refs获取实例
八、vue3通过Pinia来传值
与 Vuex 相比,少了mutations这个状态,Pinia 提供了一个更简单的 API,具有更少的规范,提供了 Composition-API 风格的 API,最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持。
- 定义一个 Store
import { defineStore } from 'pinia'
const useStore = defineStore("mainStore", {
state: () => ({
obj: {name:"天命人"},
num:0
}),
getters: {
},
actions: {
}
})
export default useBoardStore
- 使用Store
<script setup>
import useStore from '@/stores/index.js'
console.log(useStore.num); //0
console.log(useStore.obj); //{name:"天命人"}
<script />
- Store赋值
<script setup>
import useStore from '@/stores/index.js'
useStore().num = 1
useStore.obj.describe = "悟空"
console.log(useStore.num); //1
console.log(useStore.obj); //{name:"天命人",describe:"悟空"}
<script />
- Getters
Getter 完全等同于 Store 状态的 计算值。
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2,
},
})
- Actions
Actions 相当于组件中的 methods
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
actions: {
increment() {
this.counter++
},
randomizeCounter() {
this.counter = Math.round(100 * Math.random())
},
},
})
九、Storage传值
新建两个文件分别为setStorage.vue和getStorage.vue,一个用来储存一个用来获取数据。由于sessionStorage、localStorage使用的方法一样这里用sessionStorage来做的示范。
先看页面
setStorage.vue组件
<template>
<div>
<input v-model="data" />
<button @click="setData()">点击我分发数据</button>
</div>
</template>
<script>
export default {
name:"setStorage",
data(){
return{
data:""
}
},
methods:{
setData(){
sessionStorage.setItem('myData',this.data) //用来储存data数据,myData自定义的名字
}
},
}
</script>
getStorage.vue组件
<template>
<div>
<label>{{data}}</label>
<button @click="getData()">点击我获取数据</button>
</div>
</template>
<script>
export default {
name:"getStorage",
data(){
return{
data:""
}
},
methods:{
getData(){
let item= sessionStorage.getItem('myData') //获取到myData储存的数据
this.data=item //赋值
}
},
}
</script>
效果图
首先要发送数据,然后才能获取得到,在网页中打开查看Application也可以查看到储存的数据
每天学习一点进步一点~~