vue自定义大小导航展开收缩的效果

pc端业务开发中,我们经常会遇到左右布局的页面(左为navigation bar, 右为content),为了适应笔记本小屏的情况,常把左侧的导航栏做成可以收缩的状态,使页面的布局更加的合理,贴近用户的使用。

HTML

	<div class="my-slider" :class="{ 'my-slider-width': !navShow, 'my-hover-width': hoverShow }">
        <!-- LOGO -->
        <div class="my-slider-icon-logo">
            <i class="icon icon-logo"></i>
            <span class="my-slider-content" :class="{ 'my-slider-none': (!navShow && !hoverShow) }">我的个人中心</span>
        </div>
        <!-- icon开关 -->
        <div class="my-slider-back"
            :class="{ 'my-slider-width': !navShow }"
            @click="showNavIcon">
            <i class="icon icon-dedent" v-if="navShow"></i>
            <i class="icon icon-indent" v-else></i>
        </div>
        <!-- content -->
        <div class="my-nav"
            @mouseover="hoverInfo"
            @mouseout="hoverInfo">
            <ul class="my-navbar">
                <li
                    v-for="(item, index) in menuInfo"
                    :key="index"
                    v-if="item.show"
                    class="my-nav-child"
                    :class="{
                        'my-nav-click': $route.path === item.pathName,
                        'my-nav-show': item.itemsShow }">
                    <template v-if="item.pathName !== 'line'">
                        <a class="my-nav-a"
                            href="javascript:;"
                            v-if="item.pathName"
                            @click="routerTo(item)">
                            <i class="my-icon my-icon-color"
                                :class="[item.iconName]"></i>
                            <span class="my-nav-span">{{item.name}}</span>
                        </a>
                        <a class="my-nav-a"
                            href="javascript:;"
                            v-else
                            @click="openShow(item, index)">
                            <i class="my-icon my-icon-color" :class="[item.iconName]"></i>
                            <span class="my-nav-span">{{item.name}}</span>
                            <template v-if="navShow || hoverShow">
                                <i class="my-icon icon-angle-down"
                                    style="font-weight: bold;"
                                    v-if="!item.itemsShow && !item.pathName"></i>
                                <i class="my-icon icon-angle-up"
                                    style="font-weight: bold;"
                                    v-if="item.itemsShow && !item.pathName"></i>
                            </template>
                        </a>
                    </template>
                    <template v-else>
                        <a href="javascript:;" class="my-nav-a my-line-a">
                            <span v-if="navShow || hoverShow">切割线</span>
                            <span class="my-left-line"></span>
                            <span class="my-right-line" v-if="navShow || hoverShow"></span>
                        </a>
                    </template>
                    <collapse-transition>
                        <template v-if="!item.pathName">
                            <div class="my-box-info" v-if="item.itemsShow">
                                <li
                                    :class="{ 'my-nav-click': $route.path === node.pathName }"
                                    v-for="(node, nodeIndex) in item.items"
                                    :key="nodeIndex"
                                    v-if="node.show">
                                    <a class="my-nav-a"
                                        href="javascript:;"
                                        @click="routerTo(node)">
                                        <span class="my-point"></span>
                                        <span class="my-nav-span">{{node.name}}</span>
                                    </a>
                                </li>
                            </div>
                        </template>
                    </collapse-transition>
                </li>
            </ul>
        </div>
    </div>

methods

import collapseTransition from './collapse-transition'

    export default {
        components: { collapseTransition },
        data () {
            return {
                navShow: true,
                hoverShow: false,
                // 导航数据
                menuInfo: [
                    {
                        name: '个人资料',
                        pathName: '/',
                        roleId: 'data',
                        iconName: 'icon-work-info',
                        items: [],
                        show: true,
                        itemsShow: false
                    },
                    {
                        name: '我的收藏',
                        pathName: '/collection',
                        roleId: 'collection',
                        iconName: 'icon-work-info',
                        items: [],
                        show: true,
                        itemsShow: false
                    },
                    {
                        name: '我的爱好',
                        pathName: '',
                        roleId: 'role',
                        iconName: 'icon-work-info',
                        items: [
                            {
                                name: '写代码',
                                pathName: '/write',
                                roleId: 'serviceEntry',
                                show: true
                            },
                            {
                                name: '改BUG',
                                pathName: '/change',
                                roleId: 'directory',
                                show: true
                            }
                        ],
                        show: true,
                        itemsShow: false
                    },
                    {
                        name: '我的关注',
                        pathName: '/focus',
                        roleId: 'focus',
                        iconName: 'icon-work-info',
                        items: [],
                        show: true,
                        itemsShow: false
                    },
                    {
                        name: '切割线',
                        pathName: 'line',
                        roleId: 'line',
                        iconName: '',
                        items: [],
                        show: true,
                        itemsShow: false
                    },
                    {
                        name: '我的下载',
                        pathName: '',
                        roleId: 'role',
                        iconName: 'icon-work-info',
                        items: [
                            {
                                name: '知识下载',
                                pathName: '/knowledge',
                                roleId: 'knowledge',
                                show: true
                            },
                            {
                                name: '目录下载',
                                pathName: '/directory',
                                roleId: 'directory',
                                show: true
                            }
                        ],
                        show: true,
                        itemsShow: false
                    },
                    {
                        name: '我的游戏',
                        pathName: '',
                        roleId: 'role',
                        iconName: 'icon-work-info',
                        items: [
                            {
                                name: 'QQ农场',
                                pathName: '/farm',
                                roleId: 'change',
                                show: true
                            },
                            {
                                name: 'QQ斗地主',
                                pathName: '/landlord',
                                roleId: 'landlord',
                                show: true
                            },
                            {
                                name: 'QQ飞车',
                                pathName: '/coaster',
                                roleId: 'coaster',
                                show: true
                            }
                        ],
                        show: true,
                        itemsShow: false
                    },
                    {
                        name: '我的学院',
                        pathName: '/college',
                        roleId: 'college',
                        iconName: 'icon-work-info',
                        items: [],
                        show: true,
                        itemsShow: false
                    },
                    {
                        name: '我的资料',
                        pathName: '',
                        roleId: 'role',
                        iconName: 'icon-work-info',
                        items: [
                            {
                                name: 'vue',
                                pathName: '/vue',
                                roleId: 'vue',
                                show: true
                            },
                            {
                                name: 'react',
                                pathName: '/react',
                                roleId: 'react',
                                show: true
                            },
                            {
                                name: 'node',
                                pathName: '/node',
                                roleId: 'node',
                                show: true
                            }
                        ],
                        show: true,
                        itemsShow: false
                    }
                ]
            }
        },
        methods: {
            // 展开子集列
            openShow (item, index) {
                if (item.pathName) {
                    return
                }
                for (let i = 0; i < this.menuInfo.length; i++) {
                    if (this.menuInfo[i].itemsShow && index === i) {
                        for (let j = 0; j < this.menuInfo.length; j++) {
                            this.menuInfo[j].itemsShow = false
                        }
                        return
                    }
                }
                for (let i = 0; i < this.menuInfo.length; i++) {
                    this.menuInfo[i].itemsShow = false
                }
                this.menuInfo[index].itemsShow = true
            },
            // 导航大小按钮控制事件
            showNavIcon () {
                this.navShow = !this.navShow
                this.$store.commit('cdeploy/changeWidth', this.navShow)
            },
            // 路由调转
            routerTo (item) {
                if (item.pathName) {
                    const obj = {
                        contentRouter: item.pathName,
                        id: item.pathName,
                        contentTitle: item.name
                    }
                    this.$router.push({
                        path: item.pathName
                    })
                }
            },
            // hover效果
            hoverInfo () {
                this.hoverShow = !this.hoverShow
            }
        }
    }

css

	@import './clearfix.scss';
    @import './scroller.scss';

    .my-slider {
        width: 220px;
        background-color: #182132;
        height: 100%;
        padding-bottom: 113px;
        font-size: 14px;
        transition: all 300ms;
    }
    /* logo样式 */
    .my-slider-icon-logo {
        position: fixed;
        top: 0;
        left: 0;
        z-index: 2;
        .icon-logo {
            position: absolute;
            top: 0px;
            left: 0px;
            font-size: 52px;
            width: 60px;
            height: 60px;
            background-color: #182132;
            color: #2286ff;
            text-align: center;
            line-height: 60px;
        }
        .my-slider-content {
            position: absolute;
            top: 0;
            left: 60px;
            z-index: 2;
            width: 160px;
            background-color: #182132;
            color: #a3acb9;
            height: 60px;
            line-height: 60px;
            font-size: 18px;
            font-weight: bold;
            padding-left: 10px;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
            transition: all 300ms;
        }
        .my-slider-none {
            width: 0px;
            padding: 0px;
        }
    }
    /* 底部操作按钮 */
    .my-slider-back {
        position: fixed;
        bottom: 0;
        left: 0;
        width: 220px;
        padding-left: 23px;
        font-size: 14px;
        color: #b2bfd2;
        line-height: 42px;
        border-top: 1px solid #232c3c;
        cursor: pointer;
        background-color: #182132;
        z-index: 2;
        transition: all 300ms;
    }
    /* content */
    .my-nav {
        height: 100%;
        overflow: auto;
        @include scroller(#e6e9ea, 0px);
        transition: all 300ms;
    }
    .my-nav-child {
        font-size: 14px;
        position: relative;
        cursor: pointer;
        overflow: hidden;
        transition: all 300ms;
    }
    .my-nav-a {
        display: block;
        color: #979ba5;
        height: 42px;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        position: relative;
        &:hover {
            color: #fff;
            background-color: #303c4c;
            .my-point {
                background-color: #fff;
            }
        }
        .my-icon-color {
            font-size: 16px;
            position: absolute;
            top: 13px;
            left: 23px;
        }
        .icon-angle-down,
        .icon-angle-up {
            font-size: 8px;
            position: absolute;
            top: 16px;
            right: 20px;
        }
        .my-nav-span {
            position: absolute;
            top: 12px;
            left: 68px;
        }
        .my-point {
            width: 6px;
            height: 6px;
            display: inline-block;
            border-radius: 50%;
            background-color: #737987;
            margin: 20px 0 2px 28px;
        }
    }
    .my-nav-click {
        background-color: #3c96ff;
        a {
            color: #fff;
            .my-icon-color {
                color: #fff;
            }
            .my-point {
                background-color: #fff;
            }
        }
    }
    .my-nav-show {
        background-color: #202a3c;
    }
    /* line */
    .my-line-a {
        text-align: center;
        line-height: 42px;
        color: #555c66;
        &:hover {
            color: #555c66;
            background-color: #182132;
        }
    }
    .my-left-line,
    .my-right-line {
        position: absolute;
        height: 1px;
        background-color: #555c66;
        width: 45px;
        top: 22px;
    }
    .my-left-line {
        left: 7px;
    }
    .my-right-line {
        right: 7px;
    }
    /* 小屏宽度 */
    .my-slider-width {
        width: 60px!important;
    }
    .my-hover-width {
        position: absolute;
        top: 0;
        left: 0;
        width: 220px!important;
    }

效果图

在这里插入图片描述 在这里插入图片描述

优点

1:自定义导航中的icon
2:通过控制menuInfo这个对象来控制导航的生成,合理的参数变量来控制dom的操作
3:简易的动画效果
4:节约空间,方便用户使用

改进

1:代码写的有些冗余,可以简易优化一下
2:布局样式上也可以进行优化

Logo

前往低代码交流专区

更多推荐