学习参考地址:【精选】Vue3父子组件间传参通信_vue3父子组件传参-CSDN博客
1、父传子
父组件直接通过属性绑定的方式给子组件绑定数据,子组件通过defineProps接收函数接收,例如:
父组件中:
子组件中接收props:
子组件中使用props,直接打点调用
2、子传父
子组件传值给父组件主要是子组件通过defineEmits
注册一个自定义事件,而后触发emit
去调用该自定义事件,并传递参数给父组件。
在父组件中调用子组件时,通过v-on
绑定一个函数,通过该函数获取传过来的值。
子组件:
// defineEmits不用引入 直接使用
const emit = defineEmits(["selectedListFn"]);
emit("selectedListFn", val);
父组件通过自定义函数接收:
3、子组件暴露属性给父组件defineExpose
子组件:
父组件:通过给子组件添加ref 从而调用子组件的方法和属性
4、依赖注入Provide/Inject
(针对多层嵌套的组件使用props传递会产生props逐级透传的问题)
父组件:
使用provide函数向下传递值,第一个参数是注入名,第二个参数是传递的值
子组件:
通过inject函数接收父组件传递的值
第一个参数是父组件通过provide传递数据的注入名,第二个参数是父组件
孙组件:
而后无论哪个子组件想要获取toChildValue
的值,只需使用inject
即可
当提供 / 注入响应式的数据时,如果想改变数据时,建议尽可能将任何对响应式状态的变更都保持在供给方组件中,即根组件Root.vue
。这样可以确保所提供状态的声明和变更操作都内聚在同一个组件内,使其更容易维护。
父组件:
子组件:
5、pinia 状态管理器
npm install pinia
npm i pinia
main.js中引入:
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).use(createPinia()).mount('#app')
src目录下创建store文件夹,用于存放store对应的js/ts文件,例如创建一个user.js文件
// @ts-check
import { defineStore } from 'pinia'
/**
* Simulate a login
*/
function apiLogin(a: string, p: string) {
if (a === 'ed' && p === 'ed') return Promise.resolve({ isAdmin: true })
if (p === 'ed') return Promise.resolve({ isAdmin: false })
return Promise.reject(new Error('invalid credentials'))
}
export const useUserStore = defineStore({
id: 'user',
state: () => ({
name: 'Eduardo',
isAdmin: true,
}),
getters:{
userName: (state) => `Get userName from getter ${state.name}`
},
actions: {
/**
* 退出logout
*/
logout() {
this.$patch({
name: '',
isAdmin: false,
})
/**
* 登录 login
*/
async login(user: string, password: string) {
const userData = await apiLogin(user, password)
this.$patch({
name: user,
...userData,
})
},
},
})
相比较于vuex,pinia去除了mutation,同步和异步操作都通过actions,并且没有了module的概念,defineStore会创建一个新的store。
组件中使用store
<script setup lang="ts">
import { useUserStore } from "./store/user"
const userStore = useUserStore()
//访问state
console.log(userStore.name)
//访问getter
console.log(userStore.userName)
</script>
然后就可以通过user来访问store中的state,并且还可以调用getter和action。
getter
Getter 完全等同于 Store 状态的计算值。 它们可以用 defineStore() 中的 getters 属性定义。 他们接收“状态”作为第一个参数以鼓励箭头函数的使用,可以直接在 store 实例上访问 getter。
我们也可以在定义常规函数时通过 this 访问到整个 store 的实例。
action
Actions 相当于组件中的 methods。 它们可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义业务逻辑,也可以直接在store实例上调用action。
在actions中也可以在定义常规函数时通过 this 访问到整个 store 的实例。
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
actions: {
increment() {
this.counter++
},
randomizeCounter() {
this.counter = Math.round(100 * Math.random())
},
},
})
2.5 修改state
1、直接修改
虽然可以通过pinia实例直接修改,但是出于代码结构来说,全局的状态管理还是不要直接在各个组件处随意修改状态,应放于 action 中统一方法修改(piain没有mutation)并不推荐!
store.count ++;
2、使用$patch
使用$patch改变数据 $patch 可以同时修改多个值。
store.$patch((state) => {
state.name= 'newName'
state.age ++
})
3、使用actions
推荐
actions:{
async login(user: string, password: string) {
//模拟异步登录
const userData = await apiLogin(user, password)
//更新state中数据
this.$patch({
name: user,
...userData,
})
}
}
2.6 storeToRefs
为了直接获取store中的属性,我们可能会利用解构来直接获取:
import { useUserStore } from "./store/user"
const { name }= useUserStore()
但是,值得注意的是,如果直接解构store实例来获取state中的值,那么获取的值就失去了响应式,正确的做法是使用storeToRefs:
import { storeToRefs } from 'pinia'
import { useUserStore } from "./store/user"
const { name }= storeToRefs(useUserStore())