一、父子组件间传值
- 父传子:父组件传值给子组件 需要子组件用props接收值)
父
<template>
<div class="app">
<children name="jiangjiang" age="24" sex="男"></children>
</div>
</template>
子
<template>
<div class="app">
<div>子组件接收到父组件的值:{{name}}{{age}}{{sex}}</div>
</div>
</template>
// 简单声明接收
props:['name','age','sex']
// 接收的同时对数据进行类型限制
props:{
name:String,
age:Number,
sex:String
}
// 接收的同时对数据进行类型限制 + 默认值的指定 + 必要性的限制
props:{
name:{
type:Stirng, // name 的类型是字符串
required:true, // name 是必要的
default:99
},
age:{
type:Number,
default:99 // 默认值
},
sex:{
type:Stirng,
required:true
}
}
- 子传父
父
<template>
<div class="app">
<child @btn="handelEmit" />
父组件接收子组件的值:{{message}}
</div>
</template>
methods: {
handelEmit (val) {
this.message = val //父组件接收子组件的值
}
},
子
<template>
<div class="app">
<button @click="btn">我是子组件的按钮 点击我将值传到现在的父组件中</button>
</div>
</template>
methods: {
btn () {
this.$emit('btn', '123')// 参数一:参数名称,参数二为需要传递的值
}
},
二、非父子组件传值(provide、inject)
Provide/Inject用于非父子组件之间共享数据:比如有一些深度嵌套的组件,子组件想要获取父组件的部分内容;在这种情况下,如果我们仍然将props沿着组件链逐级传递下去,就会非常的麻烦;对于这种情况下,我们可以使用 Provide 和 Inject :
父组件存在Provide来提供数据。
子组件存在Inject来获取数据。
父组件 provide 与 data() 同级
// 一般用写法二
provide:{
name:'jiangjiang',
age:24
}
provide(){
return{
name:'jiangjiang',
age:24
}
}
子组件 inject 与 data() 同级
inject:['name','age']
如果Provide拿到的数据,是从data拿到的数据,此时该如何写呢?
如果我们修改了this.name的内容,那么使用的子组件是不会响应的:这是因为当我们修改了name之后,之前在provide中引入的 this.name 本身并不是响应式的。(可用computed实现)
父组件
data(){
return{
name:'jiangjiang
//name: computed(() => this.name)
}
},
provide(){
return{
name:this.name
}
}
子组件
inject:['name']
三、兄弟组件传值(bus总线机制)
- 接收数据:A组件想接收数据,则在A组件中给$bus 绑定自定义事件,事件的回调留在A组件自身
mounted(){
this.$bus.$on('xxx',this.demo)
},
methods:{
demo(data){.....}
}
- 提供数据
this.$bus.$emit('xxx', 数据)
四、Vuex(状态管理工具)
专门在 Vue 中实现集中式(数据) 管理的一个 Vue 插件,对 Vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间的通信方式,且适用于任意组件间的通信。适用于多个组件需要共享数据时。更改状态的唯一方法就是在mutaions里修改state,actions不能直接修改state(辅助函数—mapState,mapGetters,mapActions,mapMutations)
- State --数据存贮
- Getter --state的计算属性
- Mutation --更改state中状态的逻辑 同步操作
- Action --提交mutation 异步操作
- Model --模块化
其中state和getters用来保存状态;mutations和actions用来改变状态;监听状态用的是Vue组件中的computed属性;module是用来组织整个应用的状态管理代码,使状态划分模块,更易于管理;辅助函数用来在监听状态时候简化代码,
关于store,需要先记住两点
- store 中存储的状态是响应式的,当组件从store中读取状态时,如果store中的状态发生了改变,那么相应的组件也会得到更新;
- 不能直接改变store中的状态。改变store中的状态的唯一途径是提交(commit)mutations。这样使
得我们可以方便地跟踪每一个状态的变化。
机制:
在项目中我们要修改state状态的时候,我们需要使用this.$store.dispatch来触发actions中定义的方法,在actions里面定义的方法通过commit来调用mutations定义的方法来改变state状态。
state 基本数据,存储变量
const store = new Vuex.Store({
state: {
name: 'jiangjiang',
age:24,
sex:'男'
},
});
使用时
方法一:子组件能通过 this.$store 访问
this.$store.state.name
方法二:从vuex中按需导入mapstate函数(注意:当前组件需要的全局数据,映射为当前组件computed属性)
import { mapState } from "vuex";
computed:{
// 借助 mapState 生成计算属性: name、age、sex(对象写法)
...mapState({name:'name',age:'age',sex:'sex'})
// 借助 mapState 生成计算属性: name、age、sex(数组写法)
...mapState(['name','age','sex'])
}
Mutation 更改 Vuex 的 store 中的状态的唯一方法是提交 Mutation(两个形参:state是当前VueX对象中的state,
payload是该方法在被调用时传递参数使用的)
mutations:{
//编辑
edit(state,payload){
//(1)直接调用
state.name = 'wayne'
//(2)传值调用
state.name = payload
//(3)传值对象调用
state.name = payload.name
},
}
//页面通过this.$store.commit调用
//(1)直接调用
this.$store.commit('edit')
//(2)传值调用
this.$store.commit('edit','wayne')
//(3)传值对象调用
this.$store.commit('edit',{name:'wayne',sex:'男'})
//还可以这么写
this.$store.commit({
type:'edit',
payload:{
name:'wayne',
sex:'男'
}
})
//使用mapMutations 辅助函数
import { mapMutations } from "vuex";
// 数组形式
methods:{
...mapMutations(
['edit']
)
}
// 对象形式
methods:{
...mapMutations(
{'edit':'edit'}
)
}
Getters加工state成员给外界类似于计算属性(两个默认参数:state 当前VueX对象中的状态对象,getters 当前getters对象)
getters:{
nameInfo(state){
return "姓名:"+state.name
},
fullInfo(state,getters){
return getters.nameInfo+'年龄:'+state.age
}
}
// 调用
this.$store.getters.fullInfo//姓名:jiangjiang 年龄:24
actions 专门放置异步操作,然后提交mutation去操作state(两个默认参数:context 上下文(相当于箭头函数中的this)对象,payload 挂载参数)
actions:{
Edit(context,payload){
//异步操作
setTimeout(()=>{
//提交mutations方法,修改state
context.commit('edit',payload)
},2000)
}
}
//在页面组件中调用:
this.$store.dispatch('Edit','wayne')
四、pinia
- 介绍
pinia是最新一代的轻量级状态管理插件,一个全新的用于 Vue 的状态管理库。下一个版本的 Vuex,也就是 Vuex 5.0。。按照尤雨溪的说法,vuex 将不再接受新的功能,建议将 Pinia 用于新的项目。
- 用法
main.js引入
// main.js
import { createApp } from 'vue'
import App from './App.vue'
// 导入构造函数
import { createPinia } from 'pinia'
// 实例化 Pinia
const pinia = createPinia()
// 创建Vue应用实例app
const app = createApp(App)
// 应用以插件形式挂载Pinia实例
app.use(pinia)
app.mount('#app')
src文件夹下新建store/index.js
// src/store/index.js
// Store 是使用 defineStore() 定义的
import { defineStore } from 'pinia'
// 第一个参数是应用程序中 store 的唯一 id,是必要的,Pinia 使用它来将 store 连接到 devtools。
export const useCounterStore = defineStore('counter', {
// 类似组件的 data ,用来存储全局状态,推荐使用 完整类型推断的箭头函数(为了在服务端渲染的时候避免交叉请求导致数据污染)
state: () => {
return {
count: 0,
name:'jiangjiang'
}
},
// state: () => ({ count: 0 })
// 类似于computed 用来封装计算属性 有缓存功能
getters: {
double: (state) => state.count * 2,
},
// 类似于methods 编辑业务逻辑
actions: {
increment() {
this.count++
},
},
})
使用
// 引入store
import { useCounterStore } from '@/stores/counter'
export default {
setup() {
const counter = useCounterStore()
counter.count++
// 如果我们批量更改数据建议使用$patch方法,因为Pinia 的官方网站,已经明确表示 $patch的方式是经过优化的,会加快修改速度,对程序的性能有很大的好处。所以如果你是多条数据同时更新状态数据,推荐使用 $patch方式更新。
counter.$patch({ count: counter.count + 1 })
// or using an action instead
counter.increment()
},
}
// 也可以使用类似于vuex的mapState等方式引入
import { useCounterStore } from '@/stores/counter'
export default {
computed: {
// other computed properties
// gives access to this.counterStore
...mapStores(useCounterStore),
// gives read access to this.count and this.double
...mapState(useCounterStore, ['count', 'double']),
},
methods: {
// gives access to this.increment()
...mapActions(useCounterStore, ['increment']),
},
}
修改state方法
1、counter.count++
2、counter.$dispatch({
name:'jiangjiang1',
count:1
}) // dispatch 传一个对象
3、counter.$dispatch((state)=>{
state.name='jiangjiang1'
state.count=1
})
4、counter.increment()
pinia 解构不具有响应式
import { storeToRefs } from 'pinia'
const { name,count } = storeToRefs(counter)
- Vuex 和 Pinia 的优缺点
Vuex的优点
● 支持调试功能,如时间旅行和编辑
● 适用于大型、高复杂度的Vue.js项目
Vuex的缺点
● 从 Vue 3 开始,getter 的结果不会像计算属性那样缓存
● Vuex 4有一些与类型安全相关的问题
Pinia的优点
● 完整的 TypeScript 支持:与在 Vuex 中添加 TypeScript 相比,添加 TypeScript 更容易
● 极其轻巧(体积约 1KB)
● store 的 action 被调度为常规的函数调用,而不是使用 dispatch 方法或 MapAction 辅助函数,这在 Vuex 中很常见
● 支持多个Store
● 支持 Vue devtools、SSR 和 webpack 代码拆分
Pinia的缺点
● 不支持时间旅行和编辑等调试功能、
- pinia和vuex的区别
● 它没有mutation,他只有state,getters,action【同步、异步】使用他来修改state数据
● 他默认也是存入内存中,如果需要使用本地存储,在配置上比vuex麻烦一点
● 语法上比vuex更容易理解和使用,灵活。
● pinia没有modules配置,没一个独立的仓库都是definStore生成出来的
● state是一个对象返回一个对象和组件的data是一样的语法