首页 前端知识 VUE父子之间的传值(以vue3为例)

VUE父子之间的传值(以vue3为例)

2024-08-14 22:08:36 前端知识 前端哥 839 977 我要收藏

一、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>
转载请注明出处或者链接地址:https://www.qianduange.cn//article/15588.html
标签
评论
发布的文章

04-Json/Ajax/Vue的知识

2024-08-21 10:08:39

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!