前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我攻克的技术难题 - BuildAdmin16:边栏隐藏、页面全屏,我用vue是如何实现的

我攻克的技术难题 - BuildAdmin16:边栏隐藏、页面全屏,我用vue是如何实现的

原创
作者头像
叫我阿柒啊
发布2024-02-16 21:46:32
3150
发布2024-02-16 21:46:32
举报

前言

弹出框的五个标签功能,重新加载、关闭标签、关闭其他标签、关闭所有标签都已经实现了,现就剩下当前标签全屏标签还没有实现。

在BuildAdmin中,一共实现了两种全屏。一种是main区域全屏,即边栏消失,页面占据整个浏览器页面,是在弹出框的实现的。

另一种全屏是页面占据整个显示器屏幕,是在后面的导航菜单栏实现的。

本篇文章要讲的是第一种全屏方式的实现。

全屏Fullscreen

根据我们的对全屏(例如浏览器全屏、播放器全屏)的一些使用经验,全屏的功能主要分为两部分:全屏和退出全屏。我们从图中可以看到,这里的全屏指的是:header和aside区域隐藏,main占据整个页面,即100%

如果想要隐藏一个html元素(组件),在css中,将display属性设置为none即可。在vue中,v-ifv-show同样也是用于决定组件是否渲染(展示),BuildAdmin中使用的是v-if。

tabFullScreen

如果想要多个组件同时隐藏/展示,在vue中只需要将多个元素的v-if属性指向同一个boolean变量,当变量为true时都展示;为false都隐藏;如果有的隐藏有的展示,用!取反即可。如何定义这个变量,多个组件能同时访问的当然是之前讲到的状态变量了,即pinia。

在之前讲的tabs中所有的状态变量都定义在了navTabs中,这里也不例外。定义了tabFullScreen变量来控制全屏。

我们先看看onContextmenuItem中全屏逻辑是如何定义的。

代码语言:typescript
复制
case 'fullScreen':
    if (route.path !== menu?.path) {
        router.push(menu?.path as string)
    }
    navTabs.setFullScreen(true)
    break

case中也是处理了两种情况,一是将当前激活的tab全屏,二是将非激活的tab全屏。针对于第二种情况,将当前route与传入的menu比较,如果不同,先进行跳转。

然后调用navTabs的setFullScreen方法。

代码语言:typescript
复制
const setFullScreen = (fullScreen: boolean): void => {
    state.tabFullScreen = fullScreen
}

此时tabFullScreen由默认值false变成了true。

隐藏aside、header

去看aside.vue中菜单栏aside是如何隐藏的。

el-aside中v-if条件,瑟吉欧对navTabs中的tabFullScreen进行了取反,当tabFullScreen为true时,aside就为false被隐藏。

header和aside同样的实现方式。

这样就实现了header和aisde隐藏、main全屏的功能。接下来就是实现取消全屏。

取消全屏

从全屏的实现过程来反推,取消全屏就是将tabFullScreen设置为false就行了。

有人就会说了,取消全屏不都是按ESC吗。ESC用于取消整个屏幕的那种全屏,对于这种全屏BuildAdmin中定义了一个取消按钮按钮组件,来实现取消全屏。

如图,取消全屏是一个居中的位置可变的按钮,鼠标放到上面和离开时,会以浏览器窗口为参照进行位置改变。(position:fixed)

closeFullScreen组件

BuildAdmin中定义了closeFullScreen.vue来实现取消全屏的组件。

代码语言:html
复制
<template>
    <div title="layouts.Exitfullscreen" @mouseover.stop="onMouseover" @mouseout.stop="onMouseout">
        <div @click.stop="onCloseFullScreen" class="close-full-screen" :style="{ top: state.closeBoxTop + 'px' }">
            <Icon name="el-icon-Close"/>
        </div>
        <div class="close-full-screen-on"></div>
    </div>
</template>

取消全屏组件的主要部分,就是\<Icon>d定义的关闭图标,其他的div元素都是用来触发事件改变元素位置

在最外层的第一个div中,绑定了mouseovermouseout鼠标进入进出的方法。

代码语言:typescript
复制
const onMouseover = () => {
    state.closeBoxTop = 20
}
const onMouseout = () => {
    state.closeBoxTop = -30
}

这两个方法,都对closeBoxTop变量进行的修改,当鼠标进入时,修改为20,当鼠标移开时,设置为-30。我们看看closeBoxTop是用来干什么的。

close-full-screen

第二个div(.close-full-screen)就相当于取消全屏按钮本体了。其中style属性的top绑定了closeBoxTop变量。众所周知,top被用来修改元素的位置。

平时我们知道top位置的改变是针对于父元素的,这里位置相当于的是浏览器,所以要设置position: fixed; ,使其变成相对于浏览器的固定定位。

代码语言:scss
复制
<style scoped lang="scss">
    .close-full-screen {
        display: flex;
        align-items: center;
        justify-content: center;
        position: fixed;
        right: calc(50% - 20px);
        z-index: 9999999;
        height: 40px;
        width: 40px;
        background-color: rgba($color: #000000, $alpha: 0.1);
        border-radius: 50%;
        box-shadow: var(--el-box-shadow-light);
        transition: all 0.3s ease;
        .icon {
            color: rgba($color: #000000, $alpha: 0.6) !important;
        }
        &:hover {
            background-color: rgba($color: #000000, $alpha: 0.3);
            .icon {
                color: rgba($color: #ffffff, $alpha: 0.6) !important;
            }
        }
    }    

-30px就相当于向上移动了30px,即隐藏了30px。

代码语言:typescript
复制
const state = reactive({
    closeBoxTop: 20,
})
onMounted(() => {
    setTimeout(() => {
        state.closeBoxTop = -30
    }, 300)
})

我们在组件挂载完成时,在生命周期函数中使用setTimeout将closeBoxTop设置为-30px自动将取消全屏按钮隐藏在浏览器中。其实在新建closeBoxTop时直接设置为-30px是一样的效果....

至于为什么是-30px,因为Icon的大小为40px,想要保留多少可以自己决定的,-29px和-31px都无所谓。

同时这个div绑定了一个点击事件onCloseFullScreen,即点击这个取消全屏按钮会发生什么,当然是取消全屏了,就是将tabFullScreen设置为false就行了。

代码语言:typescript
复制
import {useNavTabs} from '@/stores/navTabs'
const navTabs = useNavTabs()

const onCloseFullScreen = () => {
    navTabs.setFullScreen(false)
}

这时候aside和header就会显示了,两个组件会重新新建渲染。

close-full-screen-on

第三个div(.close-full-screen-on),刚开始看代码的时候,我没明白这个div是干什么的,后来在自己实现这一块代码时,才恍然大悟这个div是用来增加mouseover和mouseout事件触发面积的。

因为第二个div上移30px,留在浏览器内的大小只有10px了。如果没有这个100 * 60的div,鼠标只要稍微移动,就会触发mouseout事件,取消全屏按钮就会隐藏。

代码语言:scss
复制
.close-full-screen-on {
    position: fixed;
    top: 0;
    z-index: 9999998;
    height: 60px;
    width: 100px;
    left: calc(50% - 50px);
}

z-index设置得很大,元素优先级就很高,就可以在最上面。

引入组件

最后就是在layouts/index.vue中引入取消全屏按钮组件。

使用v-if,当tabFullScree为true全屏时,这个取消全屏按钮组件才会显示。

优化

当我取消全屏之后,会发现tab页的白色滑动块没了。后来我分析了一下原因,使用v-if来控制组件的隐藏,实际上会触发组件的销毁。所以,取消全屏会触发tabs新建并重新渲染,会调用生命周期函数onMounted

虽然组件是新建的,但是数据还在,在此之前渲染过tabs的tabsView不是空的,所以无法触发原本onMounted中activeRoute的赋值,也就无法触发watch中的selectNavTab

所以加了最后三行代码,在取消全屏重新渲染的时候,会触发selectNavTab来渲染滑动块。

结语

至此,弹出框的设计和功能实现已经全部完成了,在BuildAdmin管理系统页面设计架构,只剩下导航菜单栏这部分还没有写。后端接口的开发、前后端api交互模块的设计、菜单页面的开发都属于内容填充了。

本篇文章也是第五期训练营的第21篇文章,写完本篇又到了沉淀的慢节奏时刻了,休息一段时间,整理一下BuildAdmin系列的初稿,然后排版二次创作之后完成文章的输出,期待下一次相见。

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 全屏Fullscreen
    • tabFullScreen
      • 隐藏aside、header
      • 取消全屏
        • closeFullScreen组件
          • close-full-screen
            • close-full-screen-on
              • 引入组件
              • 优化
              • 结语
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档