一、vue官网提供的父传子、子传父方法(常规操作)方法一:
1、父传子
1.1父子间相关操作(父组件传值给子组件)
//树形组件封装DeptTree
<template> <DeptTree @node-click="handleDeptNodeClick" :value="value" /> </template>
<script setup lang="ts" name="Warehouse">
const value = ref('父传子')
</script>
1.2子组件相关操作(子组件接收父组件传过来的值)
<template>
<div class="head-container">
<el-input v-model="deptName" class="mb-20px" clearable placeholder="请输入仓库名称">
<template #prefix>
<Icon icon="ep:search" />
</template>
</el-input>
</div>
<div class="head-container">
<el-tree
ref="treeRef"
:data="deptList"
:expand-on-click-node="false"
:filter-node-method="filterNode"
:props="defaultProps"
default-expand-all
highlight-current
node-key="id"
@node-click="handleNodeClick"
/>
</div>
</template>
<script lang="ts" setup>
const props = defineProps({
// 默认选中的部门id
value: {
type: string,
default: ''
}
})
watch(value,(val)=>{
console.log('接受父组件传给子组件的值value',val)
})
</script>
2、子传父
2.1子组件传值给父组件相关操作(子组件主要是传递方法跟值)
<template>
<div class="head-container">
<el-input v-model="deptName" class="mb-20px" clearable placeholder="请输入仓库名称">
<template #prefix>
<Icon icon="ep:search" />
</template>
</el-input>
</div>
<div class="head-container">
<el-tree
ref="treeRef"
:data="deptList"
:expand-on-click-node="false"
:filter-node-method="filterNode"
:props="defaultProps"
default-expand-all
highlight-current
node-key="id"
@node-click="handleNodeClick"
/>
</div>
</template>
<script lang="ts" setup>
import { ElTree } from 'element-plus'
// import * as DeptApi from '@/api/system/dept'
import * as WarehouseApi from '@/api/mall/cloudWarehouse/warehouse'
// import { defaultProps } from '@/utils/tree'
defineOptions({ name: 'SystemUserDeptTree' })
interface Tree {
sellerId: number
sellerName: string
warehouses?: Tree[]
}
const defaultProps = {
children: 'warehouses',
label: `sellerName`
}
const deptName = ref('')
const deptList = ref<Tree[]>([]) // 树形结构
const treeRef = ref<InstanceType<typeof ElTree>>()
watch(deptName, (val) => {
treeRef.value!.filter(val)
})
/** 获得部门树 */
const getTree = async () => {
const res = await WarehouseApi.getWarehouseList()
deptList.value = res
// deptList.value = []
// deptList.value.push(...handleTree(res))
}
/** 基于名字过滤 */
const filterNode = (name: string, data: Tree) => {
console.log('name', name, 'data', data)
if (!name) return true
return data.sellerName.includes(name)
}
/** 处理部门被点击 */
const handleNodeClick = async (row: { [key: string]: any }) => {
//子组件传递的方法跟值
emits('node-click', row)
}
const emits = defineEmits(['node-click'])
/** 初始化 */
onMounted(async () => {
await getTree()
})
2.2父组件接受到子组件传的值及触发方法
<template> <DeptTree @node-click="handleDeptNodeClick" /> </template>
<script setup lang="ts" name="Warehouse">
/** 处理部门被点击 *///父组件获取子组件传递的方法跟值
const handleDeptNodeClick = async (row) => {
queryParams.sellerId = row.sellerId
await getList()
}
</script>
二、利用vue仓库vuex(vue3建议使用pinia更加简单、便捷)
仓库代码:
//此文件名称 user.ts
import { store } from '../index'
import { defineStore } from 'pinia'
import { getAccessToken, removeToken, getTenantId, getPlatformId } from '@/utils/auth'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
import { getInfo, loginOut } from '@/api/login'
const { wsCache } = useCache()
interface UserVO {
id: number
avatar: string
nickname: string
}
interface UserInfoVO {
permissions: string[]
}
export const useUserStore = defineStore('admin-user', {
state: (): UserInfoVO => ({
permissions: [], //以此为例查看
roles: [],
isSetUser: false,
user: {
id: 0,
avatar: '',
nickname: ''
}
// closeRefresh: false
}),
getters: {
getPermissions(): string[] {
return this.permissions
},
getRoles(): string[] {
return this.roles
},
getIsSetUser(): boolean {
return this.isSetUser
},
getUser(): UserVO {
return this.user
}
// getSetCloseRefresh(): boolean {
// return this.closeRefresh
// }
},
actions: {
async setUserInfoAction() {
// console.log('this.closeRefresh', this.closeRefresh)
if (!getAccessToken()) {
this.resetState()
return null
}
let userInfo = wsCache.get(CACHE_KEY.USER)
if (!userInfo || !this.isSetUser) {
const params = {
// 平台ID
platformId: getPlatformId(),
// 租户编号
'tenant-id': getTenantId()
}
userInfo = await getInfo(params)
}
this.permissions = userInfo.permissions
this.roles = userInfo.roles
this.user = userInfo.user
this.isSetUser = true
wsCache.set(CACHE_KEY.USER, userInfo)
wsCache.set(CACHE_KEY.ROLE_ROUTERS, userInfo.menus)
},
async loginOut() {
await loginOut()
removeToken()
wsCache.clear()
this.resetState()
},
resetState() {
this.permissions = []
this.roles = []
this.isSetUser = false
// this.closeRefresh = false
this.user = {
id: 0,
avatar: '',
nickname: ''
}
// this.closeRefresh = false
},
async setIsSetUser() {
this.isSetUser = false
}
// async setCloseRefresh() {
// this.closeRefresh = true
// }
}
})
export const useUserStoreWithOut = () => {
return useUserStore(store)
}
页面调用(值开始存入在仓库中):
import router from './router'
import type { RouteRecordRaw } from 'vue-router'
import { isRelogin } from '@/config/axios/service'
import { getAccessToken, getPlatformId } from '@/utils/auth'
import { useTitle } from '@/hooks/web/useTitle'
import { useNProgress } from '@/hooks/web/useNProgress'
import { usePageLoading } from '@/hooks/web/usePageLoading'
import { useDictStoreWithOut } from '@/store/modules/dict'
import { useUserStoreWithOut } from '@/store/modules/user' //引用使用
import { usePermissionStoreWithOut } from '@/store/modules/permission'
const { start, done } = useNProgress()
const { loadStart, loadDone } = usePageLoading()
// 路由不重定向白名单
const whiteList = [
'/login',
'/social-login',
'/auth-redirect',
'/bind',
'/register',
'/oauthLogin/gitee'
]
// 路由加载前
router.beforeEach(async (to, from, next) => {
start()
loadStart()
if (getAccessToken()) {
if (to.path === '/login') {
next({ path: '/' })
} else {
// 获取所有字典
const dictStore = useDictStoreWithOut()
const userStore = useUserStoreWithOut() //转换使用
const permissionStore = usePermissionStoreWithOut()
if (!dictStore.getIsSetDict) {
await dictStore.setDictMap() //触发仓库里面的方法开始存值
}
if (!userStore.getIsSetUser && getPlatformId()) {
isRelogin.show = true
await userStore.setUserInfoAction()
isRelogin.show = false
// 后端过滤菜单
await permissionStore.generateRoutes()
permissionStore.getAddRouters.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw) // 动态添加可访问路由表
})
const redirectPath = from.query.redirect || to.path
const redirect = decodeURIComponent(redirectPath as string)
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect }
next(nextData)
} else {
next()
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
}
}
})
router.afterEach((to) => {
useTitle(to?.meta?.title as string)
done() // 结束Progress
loadDone()
})
页面获取仓库里面存的值:
import { CACHE_KEY, useCache } from '@/hooks/web/useCache' //获取引用存储
const { t } = useI18n() // 国际化
/**
* 字符权限校验
* @param {Array} value 校验值
* @returns {Boolean}
*/
export function checkPermi(value: string[]) {
if (value && value instanceof Array && value.length > 0) {
const { wsCache } = useCache()
const permissionDatas = value
const all_permission = '*:*:*'
const permissions = wsCache.get(CACHE_KEY.USER).permissions ///拿到仓库的值
const hasPermission = permissions.some((permission) => {
return all_permission === permission || permissionDatas.includes(permission)
})
return !!hasPermission
} else {
console.error(t('permission.hasPermission'))
return false
}
}
/**
* 角色权限校验
* @param {string[]} value 校验值
* @returns {Boolean}
*/
export function checkRole(value: string[]) {
if (value && value instanceof Array && value.length > 0) {
const { wsCache } = useCache()
const permissionRoles = value
const super_admin = 'admin'
const roles = wsCache.get(CACHE_KEY.USER).roles
const hasRole = roles.some((role) => {
return super_admin === role || permissionRoles.includes(role)
})
return !!hasRole
} else {
console.error(t('permission.hasRole'))
return false
}
}
三、使用事件总线(EventBus)方式进行传值(使用emit发送,使用on进行监听)可实现跨级、跨组件之间的数据传递
1、vue2中该通信方式直接集成在vue上,而vue3中,该功能被提出来,单独封装成库,所以当前需要先下载 mitt 库,然后使用:
npm install mitt
2、下载完成之后在utils/bus.ts中进行封装
import mitt from 'mitt'
const bus = mitt()
export default bus
2、使用emit进行发送:
<script setup lang="ts" name="SkuStock">
import bus from '@/utils/bus'
/** 初始化 **/
onMounted(() => {
bus.emit('mingChange', {
name: 'mingMing',
age: 18
})
})
</script>
3、使用on进行接受:
<script setup lang="ts">
import bus from '@/utils/bus'
onMounted(() => {
bus.on('mingChange', (data) => {
console.log('事件总线监听值', data)
//{name:mingMing,age:18}
})
})
</script>