自学前端12:逆向操作!!! vuez红子组件如何调用父组件方法

社区Vue前端框架

前言

上一篇写了弹出框出现位置定位,以及标签禁用的实现。本篇文章就开始写五个标签功能的实现,本篇文章针对重新加载标签,展开功能实现的过程。

弹出框定义点击事件

在弹出框中,定义了click事件,绑定了onContextmenuItem方法。

<li class="el-dropdown-menu__item" :class="item.disabled ? 'is-disabled' : ''" tabindex="-1" 
    @click="onContextmenuItem(item)">
    <Icon size="12" :name="item.icon" />
    <span>{{ item.label }}</span>
</li>

我们看看onContextmenuItem是如何定义的。

const emits = defineEmits<{
    (e: 'contextmenuItemClick', item: ContextmenuItemClickEmitArg): void
}>()

// 点击标签,将contextItem emit给父组件
const onContextmenuItem = (item: ContextmenuItemClickEmitArg) => {
    if (item.disabled) return
    item.menu = toRaw(state.menu)
    emits('contextmenuItemClick', item)
}

onContextmenuItem将item的menu赋值(标签禁用的不赋值,直接return返回,同时调用父组件的contextmenuItemClick方法。*

在vue中,defineProps是子组件接收父组件传递的值,defineEmits则子组件调用父组件事件,同时还可以传递参数,总的来说都是父子组件通信的。

这里的item指的就是之前讲的contextmenuItems中的功能标签。

contextmenuItems: [
    {name: 'refresh', label: '重新加载', icon: 'fa fa-refresh'},
    {name: 'close', label: '关闭标签', icon: 'fa fa-times'},
    {name: 'fullScreen', label: '当前标签全屏', icon: 'el-icon-FullScreen'},
    {name: 'closeOther', label: '关闭其他标签', icon: 'fa fa-minus'},
    {name: 'closeAll', label: '关闭全部标签', icon: 'fa fa-stop'},
]

弹出框组件调用了父组件tabs的contextmenuItemClick方法,并传递了item作为参数。

ContextmenuItemClickEmitArg

其中,形参中的ContextmenuItemClickEmitArg类型是自定义的接口。

export interface ContextMenuItem {
    name: string
    label: string
    icon?: string
    disabled?: boolean
}

export interface ContextmenuItemClickEmitArg extends ContextMenuItem {
    menu?: RouteLocationNormalized
}

相当于在contextmenuItems类型上,添加了一个menu字段。menu字段在BuildAdmin中指的是菜单路由,这个munu是如何赋值的呢?

在上一篇讲到弹出框弹出时,右键tab标签,调用弹出框组件的onShowContextmenu方法显示弹出框时,onShowContextmenu就绑定了tab的路由,将menu赋值给了state.menu,在弹出框的标签点击事件onContextmenuItem就将state.menu赋值给了item.menu。

picture.image

赋值在代码的61和82行。

tabs定义标签事件

在tabs中使用弹出框组件时,通过v-on来定义contextmenuItemClick方法,这样弹出框组件才能接收。

<Contextmenu ref="contextmenuRef" :items="state.contextmenuItems" @contextmenuItemClick="onContextmenuItem"/>

contextmenuItemClick又指向了onContextmenuItem方法,contextmenuItemClick就是实现标签功能具体的方法。

const onContextmenuItem = async (item: ContextmenuItemClickEmitArg) => {
    const {name, menu} = item
    if (!menu) return
    switch (name) {
        case 'refresh':
            proxy.eventBus.emit('onTabViewRefresh', menu)
            break
        case 'close':
            closeTab(menu)
            break
        case 'closeOther':
            closeOtherTab(menu)
            break
        case 'closeAll':
            closeAllTab(menu)
            break
        case 'fullScreen':
            if (route.path !== menu?.path) {
                router.push(menu?.path as string)
            }
            navTabs.setFullScreen(true)
            break
    }
}

在onContextmenuItem中,就是对ContextmenuItemClickEmitArg类型的item做了一个switch case的判断。

if (!menu) return是对禁用的标签不作处理,因为在上图onContextmenuItem方法的第81行,如果标签禁用,则menu不赋值。

思考

为什么非要在tabs中实现实现这些功能,还要父子组件各种值和方法传递,直接在弹出框组件实现不好吗?

  1. 灵活性:如果有多个组件使用弹出框组件,父组件通过传递不同的item,就能定制每个组件的弹出框标签列表。

  2. tabs中已经拿到了一些变量,例如所有的tab(tabsViews),激活的tab等。就拿关闭其他标签来说,你得知道打开了哪些标签,才能关闭。这些在tabs实现的时候都定义了,所以在tabs中实现这些功能比较方便,直接可以复用。

结语

本篇主要根据vue3中父子组件方法调用通信,讲了BuildAdmin的弹出框标签功能架构的实现,主要是对emit的一个理解和使用.下一篇文章写重新加载标签功能的具体实现.

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论