React、Vue3、Vue2 组件之间传值方式总结!!

文章目录

主要内容

本文总结了React、Vue3、Vue2组件之间传值的各种方式

React的传值方式

react的传值方式可以有六种:

  1. props:
    父传子:父组件以props的方式传参
    子传父:父组件以props的方式传递方法,让子组件调用
  2. context:上下文通信类似于vue的project/inject
  3. ref:通信获取组件实例,想要获取函数式组件的ref实例,需要使用forwardRef、或者forwardRef配合useImperativeHandle才能获取
    子组件只使用forwardRef:那么父组件可以直接获取子组件ref绑定的dom元素
    子组件forwardRef配合useImperativeHandle使用:那么父组件只能获取useImperativeHandle返回的自定义句柄,无法访问ref绑定的dom元素
  4. chilren:类似于vue的插槽,当props和children同时存在的时候,children插槽为准
  5. eventEmitter:借助外部插件,通过一个空的实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信
  6. redux(或者mobx等):状态管理通信

应用场景:

  1. 父子组件通信:
  • props
  • context
  • ref
  • children
  1. 兄弟组件通信:
  • EventEmitter
  • Redux
  1. 跨层级组件通信:
  • context
  • EventEmitter
  • Redux (或者mobx等)

1、props 通信

(1)父传子

【父组件】传入collapsed属性
在这里插入图片描述
【子组件】接收collapsed属性
在这里插入图片描述

(2)子传父

【父组件】传入一个函数给子组件,等待子组件触发此函数就执行
在这里插入图片描述
【子组件】接收父组件传入的函数,点击了按钮时触发父组件传入的函数

在react中子组件向父组件传递消息是通过回调函数的方式,也就是父组件把方法以props的形式传递给子组件来调用。
这一块和vue还是有很大差别的
在这里插入图片描述

2、context 上下文通信

类似于 vue 的 provide/inject

(1)子孙组件通信

【Home.tsx】提供 上下文
在这里插入图片描述
【Son.tsx】子组件可以接收也可以不接收,这里是啥也不做
在这里插入图片描述
【GrandSon.tsx】孙组件接收
接收方式一:使用 Consumer 接收爷爷的值
在这里插入图片描述
接收方式二:使用 useContext 接收爷爷的值
在这里插入图片描述

3、ref 通信

通过ref可以获取到子组件实例,然后使用组件上的属性或方法,这个和vue是类似的
注意:如果想要获取函数式组件的ref,需要使用forwardRef、或者forwardRef配合useImperativeHandle才能使用

子组件只使用forwardRef:那么父组件可以直接获取子组件ref绑定的dom元素
子组件forwardRef配合useImperativeHandle使用:那么父组件可以获取useImperativeHandle返回的自定义句柄

(1) 父组件通过useRef() 获取子组件的ref实例,子组件通过forwardRef()暴露实例

子组件
在这里插入图片描述
父组件
在这里插入图片描述
结果
在这里插入图片描述

(2) 父组件通过useRef() 获取子组件的ref实例,子组件通过forwardRef()结合useImperativeHandle()向父组件公开自定义引用句柄

useImperativeHandle:向父组件公开自定义引用句柄

子组件
在这里插入图片描述

父组件 (父组件通过ref只能访问到useImperativeHandle公开的自定义引用句柄)

在这里插入图片描述
结果
在这里插入图片描述

4、children 通信

在react中,写在组件中的内容都是children,类似vue里面的插槽slot。
子组件通过this.props.children获取插槽内容
注意:当props和插槽同时存在的时候,插槽为准。

插槽的使用

【home.tsx】父组件,给子组件传递插槽
在这里插入图片描述
【Son.tsx】子组件,接收插槽内容,通过props.children获取父组件传递过来的插槽内容
在这里插入图片描述

当props和插槽同时存在的时候,插槽为准。

父组件,传入插槽内容
在这里插入图片描述
子组件,接收插槽内容
在这里插入图片描述
结果
在这里插入图片描述

5、EventEmitter

react并不支持自定义事件,所以没有vue的$on $off $emit $once等方法。所以需要借助外部插件。
EventEmitter 就是一种,类似mitt。
这种方法通过一个空的实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。

安装

npm install events

使用

注意:on一定要先于emit之前,要不然浏览器的事件注册队列没有相应的触发器。当你emit抛出方法时,页面没有该方法的事件监听,所以导致你无法获取。

(1)先创建工具函数:eventEmiiter.ts 【src/utils/eventEmiiter.ts】

在这里插入图片描述

(2)注册事件

在这里插入图片描述

(3)发布事件

在这里插入图片描述

6、redux 状态管理通信

redux是一个 js 的状态管理库,用于管理应用的全局状态。
可以帮助开发者 管理和同步 应用中的数据状态,以实现组件间的数据共享和通信。
redux 遵循了一种单向数据流的架构模式,将整个应用的状态数据存储在一个全局的状态树store中,通过action和reducer来管理状态的变化。
redux遵循的三个原则:单一数据来源、状态只读、使用和纯函数进行修改。

redux的核心组成有
(1)store:状态容器,包含了应用的所有状态,并提供了一些方法来访问和修改状态,通过一个单一的store,管理整个应用的状态。
(2)action:是一个普通的 js 对象,每个action都有一个type字段,表示将要执行的动作,并可以携带一些额外的数据。
(3)reducer:状态变化的处理者,是一个纯函数,它接收当前的 state 和 action,返回一个新的state。

redux本身是同步的,可以使用中间件处理异步操作
redux-thunk可以让action变成函数形式存在,在函数中可以做一个写异步操作,然后等接口拿到数据以后再发生dispatch去更新最新的数据。

中间件:扩展redux的功能。
中间件是一个函数,可以捕获、拦截、处理Action,也可以在处理完Action后派发新的Action。
常见的中间件包括redux-thunk(处理异步Action)和 redux-logger(记录状态变化)

安装

npm i redux -D

封装store

【src/store/redux/reducers/settingReducer.ts】
在这里插入图片描述
【src/store/redux/reducers/testReducer.ts】
在这里插入图片描述

【src/store/redux/reducers/index.ts】合并reducer
在这里插入图片描述

【src/store/redux/index.ts】创建store
在这里插入图片描述

使用store

有三种方式,下面进行一一举例

使用store的第一种方式

页面一,使用并改变count的值、改变contentColor的值
在这里插入图片描述
页面二,只使用count的值和contentColor的值
在这里插入图片描述

使用store的第二种方式 使用Provider实现redux和react项目的结合

安装
npm i react-redux @types/react-redux -D

全局提供store:【src/main.tsx】通过Provider进行redux和react的项目关联
在这里插入图片描述

在页面一里使用connect(高阶组件)把redux数据映射到组件上,在组件中可以通过dispatch派发来改变redux数据
在这里插入图片描述
页面二,展示
在这里插入图片描述

使用store的第三种方式 使用useSelector, useDispatch (推荐使用!!)

安装
npm i react-redux @types/react-redux -D

全局提供store:【src/main.tsx】通过Provider进行redux和react的项目关联
在这里插入图片描述
在页面一里使用:使用useSelector获取某个store的所有state,使用 useDispatch 派发来改变redux数据
在这里插入图片描述
页面二,展示
在这里插入图片描述

效果展示:

上面例子中的三种使用store的方式达到的效果是一致的
页面一:初始化效果图
在这里插入图片描述
页面一,改变count的值为4,改变contentColor的值为 yellow ,跳转到页面2,显示count、contentColor最新值
在这里插入图片描述
页面二,显示count、contentColor最新值
在这里插入图片描述

action处理异步

action必须是一个简单的对象,不能是异步的。如果需要处理异步action,我们需要借助redux中间件来处理
处理异步action的中间件有:
1、redux-thunk 支持dispatch(函数)
2、redux-promise 支持dispatch(Promise)、dispatch({type:“”,payload:Promise})
3、redux-saga 支持异步和同步(推荐使用)

(1)redux-thunk 支持dispatch(函数)

【1】安装中间件

npm i redux-thunk -D

【2】修改【src/store/redux/index.ts】文件,创建store时添加中间件
在这里插入图片描述
【3】使用:添加中间件后,dispatch支持函数
在这里插入图片描述
【4】如果dispatch是一个函数,为了能够重复使用,可以封装一个公共函数
在这里插入图片描述
使用
在这里插入图片描述

(2)redux-promise,支持dispatch(Promise)、dispatch({type:“”,payload:Promise})

【1】安装中间件

npm i redux-promise -D

【2】修改【src/store/redux/index.ts】文件,创建store时添加中间件
在这里插入图片描述
【3】使用:添加中间件后,dispatch可以接收Promise对象作为参数。

thunk-promise的dispatch两种使用方法:
1、是直接传入Promise对象。
2、是将Promise对象放入Action的payload字段中。

1、dispatch函数,直接传入promise对象

封装一个Promise对象
在这里插入图片描述
使用
在这里插入图片描述

2、将Promise对象放入Action的payload字段中

封装一个Promise对象
在这里插入图片描述
使用
在这里插入图片描述

(3)redux-saga 支持异步和同步(推荐使用)

【1】安装中间件

npm i redux-saga -D

【2】创建【src/store/redux/reducers/asyncAction.ts】文件,专门写异步操作的方法
在这里插入图片描述
【3】创建【src/store/redux/reducers/sagas.ts】文件,集中写saga
在这里插入图片描述
【4】修改【src/store/redux/index.ts】文件,创建store时添加中间件
在这里插入图片描述
【5】使用 saga执行reducer ,可以选择调用异步,也可以选择调用同步
在这里插入图片描述

持久化store

安装

npm i redux-persist --D

设置持久化

(1)修改【src/store/index.ts】文件,改为持久化,持久化至sessionStorage
紫色框原来创建store的方式,没有持久化的方式。红色框是新增的代码
在这里插入图片描述
(2)修改【src/main.tsx】文件,添加持久化
注释掉的那行是修改前的代码,红色框是新增的代码
在这里插入图片描述
(3)浏览器持久化效果
在这里插入图片描述

Vue3的传值方式

在这里插入图片描述

1、props/emits 通信

(1)父传子

【parent.vue】
在这里插入图片描述
【son.vue】
在这里插入图片描述

(2)子传父

【son.vue】
在这里插入图片描述
【parent.vue】在这里插入图片描述

(3)v-model双向绑定更新

父组件传入的v-model:show 和 子组件emits(“update:show”, newShow.value) 配合使用,使得子组件改变值时,父组件能及时更新
子组件的props.show可以在初始化时收到父组件传过来的值,但父组件改变值时,子组件无法知道,所以子组件需要设置一个watch监听,可以让父组件改变时,子组件能及时更新。

【parent.vue】
在这里插入图片描述
【son.vue】
在这里插入图片描述
效果:点击父组件的按钮或子组件的按钮都能同步更新值
在这里插入图片描述

2、$attrs / $listeners 通信

(1)$attrs 父传下层

$attrs里面包含着上层组件传递的所有数据(除style和class)
当组件(子组件)声明了prop时候,attrs里面包含上层组件传递的所有数据除去prop里面的数据剩下的数据

【parent.vue】
在这里插入图片描述
【son.vue】
在这里插入图片描述
效果
在这里插入图片描述

(2)v-bind=“$attrs” 和 inheriAttrs:false的使用

默认inheriAttrs:true自动继承$attrs剩下的属性到当前组件(子组件)根节点

例如上面的案例,剩下age属性,就默认继承显示在子组件的根节点上
在这里插入图片描述
【son.vue】设置v-bind=“$attrs” 和 inheriAttrs:false
在这里插入图片描述
效果
在这里插入图片描述

(3)$listeners 子传父,父调用子组件的事件

在这里插入图片描述
【son.vue】
在这里插入图片描述

【parent.vue】
在这里插入图片描述
效果
在这里插入图片描述
在这里插入图片描述

3、provide/inject 通信:父传下层

【parent.vue】
在这里插入图片描述

【son.vue】
在这里插入图片描述

效果
点击父组件的按钮更改值,子组件也能及时更新
在这里插入图片描述

4、ref/defineExpose 子传父,父调用子组件的暴露的事件、属性

defineExpose是vue3新增的一个api
放在 < scipt setup >下使用的,目的是把属性和方法暴露出去
可以用于父子组件通信,子组件把属性暴露出去, 父组件用ref获取子组件DOM,子组件暴露的方法或属性可以用dom获取。

【son.vue】
在这里插入图片描述

【parent.vue】
在这里插入图片描述

效果
在这里插入图片描述

5、插槽

(1)默认插槽

无默认内容

【son.vue】
在这里插入图片描述

【parent.vue】
在这里插入图片描述

【parent.vue】还可以这样写

//写法1
<Son> 666 </Son>

//写法2
<Son>
    <template v-slot:default> 666 </template>
</Son>

//写法3
<Son>
    <template #default> 666 </template>
</Son>

效果
在这里插入图片描述

有默认内容

【son.vue】
在这里插入图片描述

【parent.vue】父组件使用子组件什么也不传
在这里插入图片描述

效果
在这里插入图片描述

【parent.vue】父组件传入了默认插槽的内容,就会替换子组件内部的默认内容
在这里插入图片描述

效果
在这里插入图片描述

(2)具名插槽

具名插槽-不传值

【son.vue】设置了一个名为content的插槽
在这里插入图片描述【parent.vue】
在这里插入图片描述

效果
在这里插入图片描述

具名插槽-传值

【son.vue】设置了一个名为content的插槽,并传了一个值msg
在这里插入图片描述
【parent.vue】
在这里插入图片描述
【parent.vue】还可以这样写

//解构写法1:
<Son>
    <template #content="{ msg }"> 
        接收值:{{ msg }} 
    </template>
</Son>


//解构写法2:
<Son>
    <template v-slot:content="{ msg }"> 
        接收值:{{ msg }} 
    </template>
</Son>

//不解构写法1:
<Son>
    <template #content="contentProps"> 
        接收值:{{ contentProps.msg }} 
    </template>
</Son>


//不解构写法2:
 <Son>
    <template v-slot:content="contentProps"> 
        接收值:{{ contentProps.msg }} 
    </template>
</Son>

效果
在这里插入图片描述

(3)动态插槽

【son.vue】
在这里插入图片描述

【parent.vue】
在这里插入图片描述
效果
在这里插入图片描述

6、EventEmitter

安装 mitt

npm install mitt --save

Mitt是一个微型的 EventEmitter 库,在Vue3中,官方推荐使用它替代已经移除的EventBus,所以在Vue3使用前我们需要先安装Mitt依赖
1.emit(name,data) : 触发事件,两个参数:name:触发的方法名,data:需要传递的参数
2.on(name,callback) : 绑定事件,两个参数:name:绑定的方法名,callback:触发后执行的回调函数
3.off(name) : 解绑事件,一个参数:name:需要解绑的方法名
注:以上的name应该保持一致(同一个)
注:on一定要先于emit之前,要不然浏览器的事件注册队列没有相应的触发器。当你emit抛出方法时,页面没有该方法的事件监听,所以导致你无法获取。

使用 mitt

方式一:挂载全局

【main.ts】挂载在全局
在这里插入图片描述
【son.vue】注册事件,并接收值
注意:on一定要先于emit之前,要不然浏览器的事件注册队列没有相应的触发器。当你emit抛出方法时,页面没有该方法的事件监听,所以导致你无法获取。
在这里插入图片描述
【parent.vue】发布事件、卸载事件
在这里插入图片描述
效果
在这里插入图片描述

方式二:提供统一的方法

新建文件【src/utils/eventBus.ts】

import mitt from "mitt";
const eventBus = mitt();
export default eventBus;

【son.vue】注册事件,并接收值
注意:on一定要先于emit之前,要不然浏览器的事件注册队列没有相应的触发器。当你emit抛出方法时,页面没有该方法的事件监听,所以导致你无法获取。

import eventBus from "@/utils/eventBus";
eventBus.on("message", (value: string) => {
    console.log("接收值:", value);
});

【parent.vue】发布事件、卸载事件

import eventBus from "@/utils/eventBus";
onMounted(() => {
    eventBus.emit("message", "我是根组件"); //发布事件
});
onUnmounted(() => {
    eventBus.off("message"); //卸载事件
});

效果
在这里插入图片描述

7、pinia

(1)安装

npm install pinia -S

持久化插件:
npm install pinia-plugin-persistedstate --save

(2)定义Store

新建目录
在这里插入图片描述
【src/store/globalStore.ts】-----------Pinia的Option Store方式定义 Store

import { useWindowSize } from "@vueuse/core";
import { defineStore } from "pinia";
export const useGlobalStore = defineStore("globalStore", {
    state: () => {
        return {
            windowWidth: useWindowSize().width, // 窗口实时宽度
            windowHeight: useWindowSize().height, // 窗口实时高度
            projectName: "fuyu",
        };
    },
    getters: {
        getWindowWidth: (state) => {
            return state.windowWidth;
        },
        getWindowHeight: (state) => {
            return state.windowHeight;
        },
        getProjectName: (state) => {
            return state.projectName;
        },
    },
    actions: {
        setProjectName(projectName: string) {
            this.projectName = projectName;
        },
    },

    //如果安装了npm install pinia-plugin-persistedstate --save持久化插件就可根据需要配置
    // persist:true,//全部持久化
    persist: {
        //部分持久化
        key: "globalStore", //缓存key
        storage: window.sessionStorage, //缓存方式
        // 部分持久化状态的点符号路径数组,默认持久化所有数据
        paths: ["projectName"], //持久化字段
    },
});

【src/store/index.ts】

import { createPinia } from "pinia";
import { App } from "vue";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; //持久化插件

const pinia = createPinia();

pinia.use(piniaPluginPersistedstate); //使用插件持久化存储状态

export function setupStore(app: App<Element>) {
    app.use(pinia);
}

export default pinia;

(3)注册store

在这里插入图片描述

(4)使用store

在这里插入图片描述

(5)store持久化(使用插件)

安装持久化插件

npm install pinia-plugin-persistedstate --save

【src/store/index.ts】
在这里插入图片描述
【src/store/globalStore.ts】
在这里插入图片描述

(6)store持久化(不使用插件,手动设置持久化)

示例一

在这里插入图片描述
在这里插入图片描述

示例二

在这里插入图片描述
在这里插入图片描述

(7)pinia 知识点

修改state的值的方式有
import { useGlobalStore } from "@/store/globalStore";
const globalStore = useGlobalStore();

//方法一,使用$patch代理
globalStore.$patch((state) => {
    state.projectName = "测试";
});

//方法二
globalStore.projectName = "测试";

//方法三
globalStore.$state.projectName = "测试";

//方法四
globalStore.$state = {
    projectName: "测试",
};

//方法五:在actions内定义一个修改state中属性的方法,然后于组件内部调用该方法即可
globalStore.setProjectName("测试");
store解构
保留响应式解构 使用 storeToRefs

在这里插入图片描述

失去响应式的解构

在这里插入图片描述

$reset()

重置state内所有属性(即恢复到store中设置的最初值)

import { useGlobalStore } from "@/store/globalStore";
const globalStore = useGlobalStore();
globalStore.$reset();
$subscribe()

返回一个函数,函数默认有两个形参;
检测store对象中任何一个属性的变动,变动转化成对象存储在形参args里,state顾名思义就是存储变化后的state

import { useGlobalStore } from "@/store/globalStore";
const globalStore = useGlobalStore();

globalStore.setProjectName("付裕");

globalStore.$subscribe((args, state) => {
    console.log(args);
    console.log(state);
});

Vue2的传值方式

在这里插入图片描述

1、props/emits 通信

(1)父传子

【parent.vue】
在这里插入图片描述
【son.vue】
在这里插入图片描述

(2)子传父

【son.vue】
在这里插入图片描述
【parent.vue】
在这里插入图片描述

(3)父子组件双向绑定更新

方式一:v-mode + value + input 的方式

父组件传入的v-model 和 子组件this.$emit(“input”, this.show);配合使用,使得子组件改变值时,父组件能及时更新,props的value,专指父组件v-model传入进来的值
子组件的props中的value可以在初始化时收到父组件传过来的值,但父组件改变值时,子组件无法知道,所以子组件需要设置一个watch监听,可以让父组件改变时,子组件能及时更新。

【parent.vue】
在这里插入图片描述
【son.vue】
在这里插入图片描述
效果:点击父组件的按钮或子组件的按钮都能同步更新值
在这里插入图片描述

方式二:变量.sync + update: 变量 的方式

父组件传入的.sync 和 子组件this.$emit(“update:show”, this.newShow);;配合使用,使得子组件改变值时,父组件能及时更新
子组件的props中的show可以在初始化时收到父组件传过来的值,但父组件改变值时,子组件无法知道,所以子组件需要设置一个watch监听,可以让父组件改变时,子组件能及时更新。

【parent.vue】
在这里插入图片描述
【son.vue】
在这里插入图片描述
效果:点击父组件的按钮或子组件的按钮都能同步更新值
在这里插入图片描述

2、$attrs / $listeners 通信

(1)$attrs 父传下层

$attrs里面包含着上层组件传递的所有数据(除style和class)
当组件(子组件)声明了prop时候,attrs里面包含上层组件传递的所有数据除去prop里面的数据剩下的数据

【parent.vue】
在这里插入图片描述
【son.vue】
在这里插入图片描述
效果
在这里插入图片描述

(2)v-bind=“$attrs” 和 inheriAttrs:false的使用

默认inheriAttrs:true,自动继承$attrs剩下的属性到当前组件(子组件)根节点
例如上面的案例,剩下age属性,就默认继承显示在子组件的根节点上
在这里插入图片描述

【son.vue】
在这里插入图片描述
效果
在这里插入图片描述

(3)$listeners 子传父,父调用子组件的事件

在这里插入图片描述
【son.vue】
在这里插入图片描述
【parent.vue】
在这里插入图片描述
效果
在这里插入图片描述
在这里插入图片描述

3、provide/inject 通信:父传下层

provide:Object | () => Object
inject:Array | { [key: string]: string | Symbol | Object }

provide:提供依赖``是一个对象,或者是一个返回对象的函数。里面包含要给子孙后代的属性和属性值。
inject: 注入依赖一个字符串数组,或者是一个对象。属性值可以是一个对象,包含from和default默认值。

  • 祖先组件不需要知道哪些后代组件需要使用它提供的属性
  • 后代组件不需要知道被注入的属性来自哪里

注意:provide 是一个对象时,是非响应式,provide是返回对象的函数就是可响应式的。

非响应式 示例

【parent.vue】
在这里插入图片描述
【son.vue】
在这里插入图片描述
效果
在这里插入图片描述
当父组件修改this.msg的值,子组件接收的注入值并不会被改变,仍是原来的值,这里就不贴代码了。

响应式 示例

(1)provide传递的参数用一个方法返回

个人理解:函数的引用地址相同,所以是可响应的

【parent.vue】
在这里插入图片描述
【son.vue】
在这里插入图片描述
效果
在这里插入图片描述
点击父组件的按钮改变值,子组件接收的注入值也会被改变
在这里插入图片描述

(2)provide传递的参数定义成一个对象

个人理解:原理是data()返回obj的引用地址,provide注入又提供了这个obj的引用地址,所以子组件注入时是可响应的,引用地址相同。

【parent.vue】
在这里插入图片描述
【son.vue】
在这里插入图片描述

效果
在这里插入图片描述
点击父组件的按钮改变值,子组件接收的注入值也会被改变
在这里插入图片描述

4、ref

ref:如果在普通的 dom 元素上使用,引用指向的就是 dom实例;如果用在子组件上,引用就指向组件实例
注意:ref要等组件挂载之后才能使用

挂载顺序:父beforeCreate > 父created > 父beforeMount > 子beforeCreate > 子created > 子beforeMount > 子mounted > 父mounted

【parent.vue】
在这里插入图片描述
效果
在这里插入图片描述

5、$parent 和 $children

在这里插入图片描述

$parent 示例

【parent.vue】
在这里插入图片描述
打印结果
在这里插入图片描述

$children 示例

【son.vue】
在这里插入图片描述
打印结果
在这里插入图片描述

6、插槽

(1)默认插槽

无默认内容

【son.vue】
在这里插入图片描述
【parent.vue】
在这里插入图片描述
【parent.vue】还可以这样写

//写法1
<Son> 666 </Son>

//写法2
<Son>
    <template v-slot:default> 666 </template>
</Son>

//写法3
<Son>
    <template #default> 666 </template>
</Son>

效果
在这里插入图片描述

有默认内容

【son.vue】
在这里插入图片描述
【parent.vue】父组件使用子组件什么也不传
在这里插入图片描述
效果
在这里插入图片描述
【parent.vue】父组件传入了默认插槽的内容,就会替换子组件内部的默认内容
在这里插入图片描述
效果
在这里插入图片描述

(2)具名插槽

具名插槽-不传值

【son.vue】设置了一个名为content的插槽
在这里插入图片描述
【parent.vue】
在这里插入图片描述
效果
在这里插入图片描述

具名插槽-传值

【son.vue】设置了一个名为content的插槽,并传了一个值msg
在这里插入图片描述
【parent.vue】
在这里插入图片描述
【parent.vue】还可以这样写

//解构写法1:
<Son>
    <template #content="{ msg }"> 
        接收值:{{ msg }} 
    </template>
</Son>


//解构写法2:
<Son>
    <template v-slot:content="{ msg }"> 
        接收值:{{ msg }} 
    </template>
</Son>

//不解构写法1:
<Son>
    <template #content="contentProps"> 
        接收值:{{ contentProps.msg }} 
    </template>
</Son>


//不解构写法2:
 <Son>
    <template v-slot:content="contentProps"> 
        接收值:{{ contentProps.msg }} 
    </template>
</Son>

效果
在这里插入图片描述

(3)动态插槽名

【son.vue】
在这里插入图片描述
【parent.vue】
在这里插入图片描述
效果
在这里插入图片描述

7、(bus):$emit / $on

在这里插入图片描述
在这里插入图片描述

注意:
on一定要先于emit之前,要不然浏览器的事件注册队列没有相应的触发器。当你emit抛出方法时,页面没有该方法的事件监听,所以导致你无法获取。
复习一下组件挂载顺序:父beforeCreate > 父created > 父beforeMount > 子beforeCreate > 子created > 子beforeMount > 子mounted > 父mounted
使用方式有两种。

方式一:挂载全局

【main.ts】挂载在全局
在这里插入图片描述
【son.vue】注册事件,并接收值
在这里插入图片描述
【parent.vue】发布事件、注销事件
在这里插入图片描述
效果
在这里插入图片描述

方式二:提供统一的方法

新建文件【src/utils/bus.js】
在这里插入图片描述
【son.vue】注册事件,并接收值
在这里插入图片描述
【parent.vue】发布事件、卸载事件
在这里插入图片描述
效果
在这里插入图片描述

8、Vuex

vuex就是专门为vue.js应用程序开发的状态管理模式,可以帮助我们管理共享状态,也就是管理全局变量。
Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。

vuex使用一个store对象管理应用状态,一个store包括:

  • state:状态管理的数据源
  • getter:将state过滤后输出
  • mutations:是vuex中改变state的唯一途径,并且只能同步操作
  • actions:一些对于state的异步操作可以放在action中,并通过在action提交mutations来变更状态。
    【使用Action,为了方便devtools打个快照存下来,方便管理维护。所以说这个只是规范,而不是逻辑的不允许,只是为了让这个工具能够追踪数据变化而已】
  • module:当store对象过于庞大时,可以根据具体的业务需求分为多个module,模块化vuex,可以让每一个模块拥有自己的state、mutations、actions、getters,使得结构非常清晰,方便管理。

(1)安装

安装vuex指定版本:npm install vuex@3 -S

(2)使用Vuex

【1】创建一个store【src/store/globalStore.js】

在这里插入图片描述

【2】全局注册store

【src/main.js】
在这里插入图片描述

【3】使用store
1、调用state状态

(1)在标签中调用 state

<h1>{{ $store.state.token }}</h1>

(2)在js中调用 state

console.log(this.$store.state.token);

(3)使用辅助函数mapState + computed属性
在这里插入图片描述

2、使用getter获取状态

(1)在标签中调用 getters

<h1>{{ $store.getters.getToken }}</h1>

(2)在js中调用 getters

console.log(this.$store.getters.getToken);

(3)使用辅助函数mapGetters + computed属性
在这里插入图片描述

3、调用Mutations 变更状态

(1)在标签中调用 mutations

<Button @click="$store.commit('setToken', '222')">点击我,改变Token</Button>

(2)在js中调用 mutations

this.$store.commit("setToken", "222");

(3)使用辅助函数mapMutations属性
在这里插入图片描述

4、调用Actions

(1)在标签中调用 actions

<Button @click="$store.dispatch('asyncSetToken', '222')">点击我,改变Token</Button>

(2)在js中调用 actions

this.$store.dispatch("asyncSetToken", "222");

(3)使用辅助函数mapActions属性
在这里插入图片描述

5、Modules 模块化vuex

当遇见大型项目时,数据量大,store就会显得很臃肿
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割

(1)新建目录

在这里插入图片描述
【src/store/globalStore.js】注意是导出一个对象,不是new Vuex.Store({})
在这里插入图片描述

【src/store/routerStore.js】注意是导出一个对象,不是new Vuex.Store({})
在这里插入图片描述
【src/store/index.js】创建 new Vuex.Store({})
在这里插入图片描述

(2)注册store

【src/main.js】
在这里插入图片描述

(3)使用store

没有命名空间时:
state是局部的,调用时需要加上模块名称
getters、mutations、actions是全局的,不需要加上模块名称
在这里插入图片描述

####### (4)设置命名空间
在这里插入图片描述

当设置为命名空间时,使用都需要加上模块名称,如下图所示
在这里插入图片描述

(5)模块动态注册

在这里插入图片描述

可以使用 store.unregisterModule(moduleName) 来动态卸载模块。注意,你不能使用此方法卸载静态模块(即创建 store 时声明的模块)。
可以通过 store.hasModule(moduleName) 方法检查该模块是否已经被注册到 store。
这里就不举例啦

(3)持久化Vuex-persistedstate

  • vuex优势: 相比sessionStorage,存储数据更安全,sessionStorage可以在控制台被看到。
  • vuex劣势: 在F5刷新页面后,vuex会重新更新state,所以,存储的数据会丢失。

vuex可以进行全局的状态管理,但刷新后刷新后数据会消失,这是我们不愿意看到的。怎么解决呢?
我们可以结合本地存储做到数据持久化,也可以通过插件vuex-persistedstate,插件的原理其实也是结合了存储方式,只是统一的配置就不需要手动每次都写存储方法
在这里插入图片描述

安装

npm i vuex-persistedstate -S

使用

在这里插入图片描述

  • 20
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值