VUE3 父子组件传参、事件传递
最近由于刚接触使用VUE3开发需求,涉及到VUE3父子组件传参、事件传递情景,在开发中做一些积累。
·
VUE3 父子组件传参、事件传递
最近由于刚接触使用VUE3开发需求,涉及到VUE3父子组件传参、事件传递情景,在开发中做一些积累。
应用场景
需要实现点击顶部栏的菜单按钮时,实现左侧菜单展开/关闭。
很显然,页面分为顶部栏、左侧菜单栏、内容这三大部分,实现此需求需要跨组件传参。
页面布局如下:
<template>
<div id="layout-container">
<!-- 左侧菜单 -->
<LeftMenu />
<div id="layout-right">
<!-- 顶部导航栏 -->
<TopBar/>
<div>
<router-view />
</div>
</div>
</div>
</template>
思路:父组件作为枢纽,掌控数据的状态和操作,父组件将展开状态同步到顶部栏、左侧菜单栏,顶部栏icon点击时触发事件,将要修改成的状态传递给父组件。
父组件向子组件传参
核心在于父组件: 绑定数据到自组件,子组件props接收。
1、父组件 -> 左侧菜单栏
父组件代码:
<template>
<div>
<!-- 左侧菜单 绑定数据 -->
<LeftMenu :isCollapse="isCollapse" />
</div>
</template>
左侧菜单栏代码:
<template>
<div>
<el-menu default-active="1" :collapse="isCollapse">
<el-menu-item v-for="menu in menuList" :key="menu.id" :index="menu.id">
<el-icon>
<component :is="menu.icon" />
</el-icon>
<div v-if="!isCollapse" class="menu-title"> {{ menu.title }}</div>
</el-menu-item>
</el-menu>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'LeftMenu',
// 接收参数
props: {
isCollapse: {
type: Boolean
}
},
setup() {
const menuList = [
{ id: '1', icon: 'Connection', title: 'Connection' },
{ id: '2', icon: 'Iphone', title: 'Connection' }
]
return {
menuList
}
},
})
</script>
2、父组件 -> 顶部栏
父组件代码:
<template>
<div>
<!-- 顶部导航栏 绑定数据 -->
<TopBar :isCollapse="isCollapse" />
</div>
</template>
顶部栏代码:
<template>
<div>
<el-button link>
<el-icon>
<Fold v-if="isCollapse" />
<Expand v-else />
</el-icon>
</el-button>
<span></span>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: "TopBar",
// 接收数据
props: {
isCollapse: {
type: Boolean
}
}
})
</script>
子组件触发父组件事件
子组件向父组件传递参数主要通过事件上传时的参数实现,emit
顶部栏 -> 父组件
父组件代码:
<template>
<div>
<div id="layout-right">
<!-- 顶部导航栏 绑定对应事件 -->
<TopBar @changeCollapse="changeCollapse" />
</div>
</div>
</template>
<script lang="ts" >
import { defineComponent, ref } from 'vue'
import TopBar from '@/components/TopBar.vue';
export default defineComponent({
name: "Layout",
components: {
TopBar
},
setup() {
const isCollapse = ref(false)
// 事件
const changeCollapse = (val) => {
isCollapse.value = !isCollapse.value
}
return {
isCollapse,
changeCollapse
}
}
})
</script>
顶部栏代码:
<template>
<div>
<el-button @click="changeCollapse" link >
展开/关闭
</el-button>
<span>顶部导航栏</span>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: "TopBar",
emits: ["changeCollapse"],
setup(props, context) {
const changeCollapse = () => {
//触发父组件事件
context.emit("changeCollapse")
}
return {
changeCollapse
}
}
})
</script>
综合
最终,结合这几个点,就能实现此需求了。
完整代码如下,注意此项目配置了i18n多语言,具体可参考 本博主VUE2多语言使用,不过本篇使用的是VUE3与多语言结合,可能会有部分出入。
父组件:
<template>
<div id="layout-container">
<!-- 左侧菜单 -->
<LeftMenu :isCollapse="isCollapse" />
<div id="layout-right">
<!-- 顶部导航栏 -->
<TopBar :isCollapse="isCollapse" @changeCollapse="changeCollapse" />
<div class="padding20">
<router-view />
</div>
</div>
</div>
</template>
<script lang="ts" >
import { defineComponent, ref } from 'vue'
import LeftMenu from '@/components/LeftMenu.vue';
import TopBar from '@/components/TopBar.vue';
export default defineComponent({
name: "Layout",
components: {
LeftMenu,
TopBar
},
setup() {
const isCollapse = ref(false)
const changeCollapse = () => {
isCollapse.value = !isCollapse.value
}
return {
isCollapse,
changeCollapse
}
}
})
</script>
<style lang="scss" scoped>
#layout-container {
display: flex;
#layout-right {
width: 100%;
}
}
</style>
左侧菜单:
<template>
<div id="menu-box">
<el-menu :default-active="currentActiveIndex" class="el-menu-vertical-demo" :collapse="isCollapse"
@select="handleSelect">
<el-menu-item v-for="menu in menuList" :key="menu.id" :index="menu.id">
<el-icon>
<component :is="menu.icon" />
</el-icon>
<div v-if="!isCollapse" class="menu-title"> {{ menu.title }}</div>
</el-menu-item>
</el-menu>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { useI18n } from 'vue-i18n' // 多语言
import router from '@/router/index'
import { Menu } from "@/config/interface"
export default defineComponent({
name: 'LeftMenu',
props: {
isCollapse: {
type: Boolean
}
},
setup() {
const { t } = useI18n()
const menuList = [
{ id: '1', icon: 'Connection', title: t('tenant.label1'), path: '/tenant' },
{ id: '2', icon: 'Iphone', title: t('android.label1'), path: '/android' },
{ id: '3', icon: 'Iphone', title: t('androidManage.label1'), path: '/androidManage' },
{ id: '4', icon: 'Iphone', title: t('orderManage.label1'), path: '/orderManage' },
]
// 高亮同步路由
// const currentActiveIndex = ref((menuList.find((menu) => menu.path === window.location.pathname) as Menu).id);
const currentActiveIndex = ref((menuList.find((menu) => ('#' + menu.path) === window.location.hash) as Menu).id);
/**
* @param index
* 菜单选中路由跳转
*/
const handleSelect = (index: string) => {
let path = menuList[Number(index) - 1]['path'];
if (router.currentRoute.value.path !== path) // 目标路由与当前路由不同则跳转
router.push(path)
}
return {
menuList,
currentActiveIndex,
handleSelect
}
},
})
</script>
<style lang="scss" scoped>
#menu-box {
margin-right: 10px;
.menu-title {
width: 130px;
}
}
</style>
顶部栏:
<template>
<div :style="{ boxShadow: 'var(--el-box-shadow-lighter)' }" id="topBar">
<el-button @click="changeCollapse" link id="bar-menu-icon">
<el-icon>
<Fold v-if="isCollapse" />
<Expand v-else />
</el-icon>
</el-button>
<span class="vertical-middle">{{ $t('common.label1') }}</span>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: "TopBar",
props: {
isCollapse: {
type: Boolean
}
},
emits: ["changeCollapse"],
setup(props, context) {
const changeCollapse = () => {
context.emit("changeCollapse")
}
return {
changeCollapse
}
}
})
</script>
<style lang="scss" scoped>
#topBar {
padding: 10px 20px;
#bar-menu-icon {
font-size: 20px;
}
}
</style>
更多推荐
所有评论(0)