vue3出来很久了,也非常成熟了,平时项目只管用也没多想,直至今天想写一编关于vue3传参,然后我总结一下竟然总结出来11种方式那么多,11种我分别列了出来,由于vue3有两种setup写法,下面我将用最简洁的代码例子针对主流的
子组件代码: const props = defineProps({})接收后直接在标签使用
{{ props.name }}
二、子传父
思路:子组件用 const emits = defineEmits([‘触发的方法’]) 注册某个在父组件的事件,然后通过emits(‘触发的事件’, 参数) 触发父组件事件并且带上参数。
子组件代码: 注册 addEvent 事件后, 用 emits(‘addEvent’, name.value) 触发父组件的 addEvent事件
父组件代码: 触发addEvent事件后,在对应的方法里面直接能拿到传过来的参数
三、兄弟组件传参(mitt)
以前vue2是用EventBus事件总线跨组件实现兄弟组件通信的。但vue3中没有,所以vue3目前主流使用mitt.js插件来进行替代实现兄弟通信。
1、npm包引入
npm install --save mitt
2、在main.js文件进行全局挂载, $bus是自定义属性名
import mitt from "mitt"
const app = createApp(App)
app.config.globalProperties.$bus = new mitt()
3、传参出去的兄弟组件代码
4、接收参数的兄弟组件代码
四、$attrs
注意: 以前在在vue2里面中除了
$attrs
,还有$listeners
; 但vue3
直接把$listeners
合并到$attrs
里面了。
简要说明:
$attrs
主要作用是接收没在props
里面定义,但父组件又传了过来的属性。看下面代码例子就好懂多了
父组件代码: 传两个属性过去,一个在子组件props中,一个不在
子组件代码: $attrs
接收到props以外的内容,所以用useAttrs()
打印出来没有name只有data
{{ props.name }} // '天天鸭'
五、refs传参
简单说明:父组件通过在子组件上定义 ref=’ref名称’,然后const ref名称 = ref(null),就能通过ref名称操控子组件的属性和方法(子组件用defineExpose对外暴露才能被操控),具体看下面例子。
父组件代码:
子组件代码: 用defineExpose
对外暴露才能被操控
六、v-model
简单讲解: v-model其实语法糖,如下两行代码作用是一样, 上面是下面的简写。
父组件代码: 直接使用v-model传参
子组件代码: 通过 defineEmits
获取到然后用emit(“update:修改的属性”, 修改的内容)进行修改父组件的内容,,注意:update:
是固定写法。
v-model扩展:defineModel()
:
defineModel()
宏的简单说明:父子组件的数据双向绑定,不用emit和props的繁重代码版本要求:必须要
3.4+
示例场景:父组件引入一个子组件弹窗,点击就
父传子(props)
弹出子组件弹窗,子组件里面有个按钮点击就子传父(emit)
关闭
父组件代码: 用v-model在子组件身上绑定showDevice属性,该属性用于通知子组件是否打开弹窗。
子组件代码: 如下的handleClickCancel
方法,通过defineModel
宏声明一个model,点击按钮能直接通知父组件修改属性。
上面例子通过defineModel
宏,直接不需要props和emit就实现了父子通信效果,非常简洁好用。
七、provide/inject
简单讲解:provide和inject叫依赖注入,是vue官方提供的API,它们可以实现多层组件传递数据,无论层级有多深,都可以通过这API实现。
假设这是太老爷组件: provide(‘名称’, 传递的参数)向后代组件提供数据, 只要是后代都能接收
最深层的孙组件: 无论层级多深,用 inject(接收什么参数) 进行接收即可
{{ name }}
八、路由传参
简单讲解: 路由跳转事上参数也是传参的一种,而且传参方式还不止一种呢,下面细说。
1、query传参
// 传递方
const query = { id: 9527, name: '天天鸭' }
router.push({ path: '/user', query })
// 接收方
import { useRoute} from 'vue-router'
const route = useRoute()
console.log(route.query)
2、params传参
注意:4.1.4 (2022-08-22) 删除了param这种方式
// 发送方
router.push({
name: 'test',
params: {
name: '天天鸭'
}
})
// 接收方
import { useRoute} from 'vue-router'
const route = useRoute()
console.log(route.params) // { name: '天天鸭' }
3、state传参
// 发送方
const state= { name: '天天鸭' }
router.push({ path: '/user', state })
// 接收方直接使用
console.log(history?.state?.name)
九、vuex传参
全局共享状态:
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex);
export default new Vuex.Store({
state:{ // 用来定义一些变量
userName: "",
count: 1,
},
getters: { // 类似于计算属性
doneTodos (state) {
return state.count*2
}
},
mutations:{ // 是用来触发事件, 修改userName
saveName(state,userName){
state.userName = userName;
},
},
actions: { // 用于提交mutations,可以包含任意异步操作,, 在里面可以请求接口操作
increment (context) {
context.commit('saveName')
}
}
})
十、pinia
全局共享状态:
import {defineStore} from 'pinia'
const useUser = defineStore("user",{
state:() => ({ // 用来定义一些变量
mycount: 1,
}),
getters: { // 类似于计算属性
double: (state) => state.mycount * 2,
},
actions: { // 里面是一些方法,在里面可以请求接口操作
increment() {
this.mycount++
},
async registerUser(login, password) { // 异步操作
await api.post({ login, password })
}
}
})
export default useUser
十一、浏览器缓存
localStorage 和sessionStorage: 这算是用的不多,但也是必用的一种通信方式了,下面看看区别:
sessionStorage
(临时存储):为每一个数据源维持一个存储区域,在浏览器打开期间存在,包括页面重新加载
localStorage
(长期存储):与 sessionStorage 一样,但是浏览器关闭后,数据依然会一直存在
下面直接上使用的语法。
// 存储数据
localStorage.setItem('key', 'value');
sessionStorage.setItem('key', 'value');
// 获取数据
const valueFromLocalStorage = localStorage.getItem('key');
const valueFromSessionStorage = sessionStorage.getItem('key');
// 删除数据
localStorage.removeItem('key');
sessionStorage.removeItem('key');
// 清空所有数据
localStorage.clear();
sessionStorage.clear();