自学前端16:边栏隐藏、页面全屏,我用vue是如何实现的

社区前端框架Vue

前言

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

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

picture.image

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

picture.image

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

全屏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变量来控制全屏。

picture.image

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

case 'fullScreen':
    if (route.path !== menu?.path) {
        router.push(menu?.path as string)
    }
    navTabs.setFullScreen(true)
    break

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

picture.image

然后调用navTabs的setFullScreen方法。

const setFullScreen = (fullScreen: boolean): void => {
    state.tabFullScreen = fullScreen
}

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

隐藏aside、header

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

picture.image

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

header和aside同样的实现方式。

picture.image

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

取消全屏

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

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

picture.image

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

closeFullScreen组件

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

<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鼠标进入进出的方法。

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; ,使其变成相对于浏览器的固定定位。

<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。

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就行了。

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事件触发面积的。

picture.image

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

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

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

引入组件

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

picture.image

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

优化

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

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

picture.image

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

结语

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

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