vue-PC端实现菜单栏拖拽改变菜单栏宽度

2,563 阅读1分钟

vue-PC端实现菜单栏拖拽改变菜单栏宽度

本文解决方案参考vue-split-pane插件

思路

页面布局中,菜单栏的宽度决定着页面的其他布局宽度,故改变菜单栏宽度,其他布局宽度随着菜单栏宽度变化即可。

菜单栏拖拽改变菜单栏宽度,使用原生事件:onmousedown(鼠标按下事件)、onmousemove(鼠标移动事件)、onmouseup(松开鼠标事件)。

实现

项目整体布局文件

<template>
    <div
        ref="layout"
        @mouseup="onMouseUp"
        @mousemove="onMouseMove"
    >
        <!-- 头部导航 -->
        <navbar />
        <!-- 左侧菜单栏 -->
        <sidebar class="sidebar-container" />
        <!-- 拖拽对象组件 -->
        <resizer 
           v-show="isMenuOpend" 
           @mousedown.native="onMouseDown" 
        />
        <!-- 页面主内容组件 -->
        <div class="main-container">
            <tags-view />
            <app-main />
        </div>
    </div>
</template>

<script>
    import { Navbar, Sidebar, AppMain, TagsView } from './components';
    import Resizer from './components/Resizer';

    export default {
        name: 'Layout',
        components: {
            Navbar,
            Sidebar,
            AppMain,
            TagsView,
            Resizer
        },
        data() {
            return {
                active: false
            };
        },
        computed: {
            isMenuOpend() {
                return this.sidebar.opened;
            },
            sidebar() {
                return this.$store.state.app.sidebar;
            }
        },
        methods: {
            onMouseDown() {
                // 记录鼠标按下
                this.active = true;
            },
            onMouseUp() {
                // 记录鼠标抬起
                this.active = false;
            },
            onMouseMove(e) {
                // 鼠标没有按键或者是没有初始化
                if (e.buttons === 0 || e.which === 0) {
                    // 认为鼠标抬起
                    this.active = false;
                }
                // 如果鼠标按下了
                if (this.active) {
                    // 并且距离网页水平位置在200与400之间,就改变菜单栏的宽度
                    if (e.clientX > 200 && e.clientX < 400) {
                        this.$refs.layout.style.setProperty('--sideBarWidth', e.clientX + 'px');
                    }
                }
            }
        }
    };
</script>

resizer组件


<template>
    <div :class="classes" />
</template>

<script>
    export default {
        props: {
            className: String
        },
        computed: {
            classes() {
                const classes = ['splitter-pane-resizer', this.className];
                return classes.join(' ');
            }
        }
    };
</script>

<style lang="scss" scoped>
.splitter-pane-resizer {
    box-sizing: border-box;
    background: #000;
    position: absolute;
    opacity: .2;
    z-index: 1;
    background-clip: padding-box;
    width: 11px;
    height: 100%;
    margin-left: -5px;
    border-left: 5px solid rgba(255, 255, 255, 0);
    border-right: 5px solid rgba(255, 255, 255, 0);
    // 光标
    cursor: col-resize;
    // 使用了scss变量
    left: $sideBarWidth;
}

</style>

tips

  • e.which

e.which之前没接触过,百度了一下:

e.which不是一个事件,which是event对象的一个属性,大多数人e在事件处理程序中标注该属性。它包含被按下以触发事件的键的关键代码(例如:keydown,keyup)。

document.onkeypress = function(myEvent) { // doesn't have to be "e"
    console.log(myEvent.which);
};

使用该代码,控制台将打印出您在键盘上按下的任何按键的代码。

e.which对应的输入字符

e.which属性值 对应输入值
1 鼠标左键
2 鼠标中键(滚轮)
3 鼠标右键
48-57 对应字符0-9
65-90 对应字符A-Z
97-122 对应字符a-z
8 Backspace键
9 Tab键
13 Enter键
16 Shift键
17 Ctrl键
20 Alt键
27 Esc键
33-36 对应按键PageUp,PageDown,End,Home
37-40 对应左上右下方向键
45-46 对应Insert,Delete键
48-57 对应按键0-9,非小键盘
65-90 对应按键A-Z
91 Windows键
96-105 对应按键0-9,小键盘
106,107,109,110,111 对应按键 * + - . / ,小键盘
112-123 对应按键f1-f12
  • 使用js改变scss变量

scss变量首先要在scss文件中声明,并且在所有希望使用菜单栏宽度的地方都使用这个变量。

// scss变量名         js引用的变量名   默认值
$sideBarWidth: var(--sideBarWidth, 200px);

将scss文件引入到vue文件中(引入方式多种多样,任意一种都可以,全局也可以,局部也可以)。

在js中修改变量的值

this.$refs.layout.style.setProperty('--sideBarWidth', e.clientX + 'px');

本文使用 mdnice 排版