vue 子路由不写router view可以显示吗_portal 在 vue 中的使用

Vue Portal 使用与子路由隐藏布局技巧
本文探讨了在 Vue 中使用 Portal 来解决页面打印时排除布局元素的问题。通过介绍 Vue 的 Portal 库 portal-vue,展示了如何在隐藏布局的同时,保持业务页面的显示。文章详细解释了如何配置和利用 <portal> 和 <portal-target> 标签来实现在不同层级的 router-view 之间动态传输内容,以达到预期效果。

960bd653fbac58f92faa77e0a001a7c0.png

之前在学 React 的时候了解过 portal,简单的来说就是可以将子组件渲染到父组件以外的地方。官网上说 portal 的典型用例是当父组件有overflow: hiddenz-index样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框。

但是当时对此例并无太多感觉,这就导致了我一度以为这是个没什么卵用的 API,大多数的使用场景应该是在封装一些公共组件上。但是近期遇到的一个需求,却确确实实出现了能够使用这个 API 的场景。

做过后台管理系统都知道,一个后台管理系统中,最基础的结构就是布局。而我们的各个业务页面基本都是在布局中显示的,通过布局中的侧边栏/标签栏/面包屑进行页面切换。

而这些通过 vue 实现基本上都是用 vue-router。如下面两个页面:

import Layout from '@/layout'

export default [
  {
    name: 'Admin',
    path: '/admin',
    component: Layout,
    redirect: '/admin/role',
    meta: { title: '后台管理', icon: 'el-icon-monitor' },
    children: [
      {
        path: 'role',
        name: 'AdminRole',
        meta: { title: '角色管理', noCache: true },
        component: () => import('@/views/admin/role')
      },
      {
        path: 'user',
        name: 'AdminUser',
        meta: { title: '账号管理', noCache: true },
        component: () => import('@/views/admin/user')
      }
    ]
  }
]

如此便可以通过前端路由,实现对 layout 布局组件的复用。

对于不需要 layout 的页面,只需:

  {
    path: '/404',
    hidden: true,
    component: () => import('@/views-constant/error-page/404')
  }

不使用 layout 即可。而整个 app 其实就是一个个嵌套的 router-view。最外层的整个 app 是 router-view,里面的业务页面也是 router-view。

这样的架构,几乎就可以满足中小型后台的全部需求了。

但是,需求总是不可控的。

前些日子,后台需要做个页面。这个页面需要在管理员确认一些信息后,将页面内容打印下来。打印页面自然是用 window.print 方法就好。但是问题出在,window.print 会把整个页面都打印下来,其中就包括侧边栏/导航栏/面包屑这些属于布局的部分。因此要实现这个功能的核心就是在某些情况下,我们可以动态的控制 layout 是否显示。

但是实际上,通过 vue-router 我们知道。平时的业务页面都是 layout 的子组件。如果我们把 layout 隐藏,业务页面自然也会被隐藏,这可如何是好?

答案就是标题。

使用 portal 方法即可。在我们隐藏 layout 的时候,实际上就是隐藏项目最外层的那个 router-view。我们要做的就是隐藏最外面的 router-view 同时把当前页面 的 router-view 渲染到最外层 router-view 同级就好。

但是问题是 vue 并没有 portal API。不过好在有一个 vue 库叫做 portal-vue 可以帮助我们实现 portal 功能,用起来也十分简单:

import PortalVue from 'portal-vue'

Vue.use(PortalVue)

而使用起来只需要两个标签即可完成 portal 功能:

<portal><portal to="app" /> 和 <portal-target name="app"><portal-target />

如此便可以将 portal 内的节点渲染到 portal-target 中,两者通过 name&to 进行关联传送。无论两个组件的相对位置如何。

带入到我们的需求中,我们只需要将内部渲染业务页面的 router-view 传送渲染到最外部的 router-view 下面就好,具体代码如下:

<!-- 业务页面 -->
<template>
  <section class="app-main">
    <transition name="fade-transform" mode="out-in">
      <keep-alive :include="cachedViews">
        <portal v-if="$store.state.app.printing" to="app">
          <router-view :key="key" />
        </portal>
        <router-view v-else :key="key" />
      </keep-alive>
    </transition>
  </section>
</template>
<!-- 最外部的 router-view -->
<template>
  <div id="app">
    <router-view v-show="!$store.state.app.printing" />
    <portal-target name="app" />
  </div>
</template>

这两个页面通过 name&to 进行关联,通过 vuex 进行公共状态共享。

这样我们在需要的时候,将 vuex 中相应的 printing 置为 true。便可以将内部 router-view 的节点内容渲染到最外部的 router-view 同级。此时的效果就类似隐藏了布局,但是实际上 portal-vue 做的绝不是仅仅移动 dom 那么简单。portal-vue 做的是 vNode 层面的移动,有兴趣可以自行研究。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值