JS实现左侧菜单工具栏

本文实例为大家分享了JS实现左侧菜单工具栏的具体代码,供大家参考,具体内容如下

摘要

该js脚本可帮助你快速实现左侧菜单工具栏。通过js封装成一个方法类,直接new该对象即可快速生成左侧菜单工具栏。

一、效果展示

二、menu.js文件

(1)WenMenuNode节点

let WenMenuNode = function ({
                                text,
                                wenMenu,
                                attributes = {},
                                subs = [],
                                parentElement = null,
                                iconHTML = '',
                                level = 1,
                                parentNode = null,
                                isActive = false,
                                onLaunch = null,
                            }) {
    this._level = level;
    this._text = text;
    this._attributes = attributes;
    this._wenMenu = wenMenu;
    this._subs = subs;
    this._onLaunch = onLaunch;
    this._childHeight = 0;
    this._height = 0;
    this.style = {
        childHeight: 0,
    }
 
    this._parentElement = parentElement;
    this._parentNode = parentNode;
    this._element = this._wenMenu.createElement('li', {
        class: "wen-menu-li",
    });
    this._textElement = this._wenMenu.createElement('a', this._attributes);
    this._iconHTML = iconHTML;
    this._childNodes = [];
    this._childElement = null;
    this._activeChild = null;
    if (this._parentElement) this._parentElement.append(this._element);
    this._isActive = isActive;
    if (this._isActive) {
        if (this._level == 1) {
            this._wenMenu._activeMenu = this;
        } else if (this._parentNode) {
            this._parentNode._activeChild = this;
        }
    }
    this.create().onLaunch();
}
 
 
WenMenuNode.prototype.create = function () {
    let a = this._textElement;
    let icon = this._wenMenu.createElement('i', {
        class: "wen-menu-icon",
    })
    if (this._level > 1) {
        a.innerHTML = '<span class="wen-menu-tree">--</span>';
    }
    icon.innerHTML = this._iconHTML;
    a.append(icon);
    a.innerHTML += `<span class="wen-menu-text">${this._text}</span>`;
    if (this._level == 1) {
        a.classList.add('wen-menu-first');
    }
    this._element.append(a);
    if (this._subs.length) {
        let ul = this._wenMenu.createElement('ul', {
            class: "wen-menu-ul" + (this._level == 1 ? " wen-menu-ul-second" : ""),
        });
        this._element.append(ul);
 
        this._childElement = ul;
        this._subs.forEach((item, i) => {
            let node = new WenMenuNode({
                text: item.text,
                wenMenu: this._wenMenu,
                attributes: item.attributes,
                subs: item.subs,
                parentElement: ul,
                iconHTML: item.iconHTML,
                level: this._level + 1,
                parentNode: this,
                isActive: this._isActive && i == 0,
                onLaunch: (childNode) => {
                    this._childNodes.push(childNode);
                    if (i == this._subs.length - 1) {
                        this.setEventListener(true);
                    }
                }
            });
        });
    } else {
        this.setEventListener(false);
    }
    return this;
}
 
 
WenMenuNode.prototype.onLaunch = function () {
    if (this._onLaunch) {
        this._onLaunch.call(this._parentNode, this);
    }
    return this;
}
 
WenMenuNode.prototype.setEventListener = function (hasSub = false) {
    if (hasSub) {
        this._height = this._subs.length * this._wenMenu._menuHeight;
        this._childHeight = this._childElement.clientHeight;
        if (this._isActive) {
            this._textElement.setAttribute('wen-active', '');
            this._textElement.setAttribute('wen-expand', '');
            this.style.childHeight = this._childHeight + this._wenMenu._menuSpacing;
        } else {
            this._textElement.setAttribute('wen-icon', '')
            this._textElement.setAttribute('wen-collapse', '');
            this.style.childHeight = 0;
        }
        this._childElement.style.height = this.style.childHeight + "px";
        this._textElement.addEventListener('click', (e) => {
            if (this._wenMenu._autoCollapse) {
                this.resetHeight();
                this.setHeight({
                    menuNode: this,
                })
            } else {
                let height = 0, target = e.target;
                if (target.classList.value.indexOf('wen-menu-text') >= 0) {
                    target = target.parentElement;
                }
                if (target.getAttribute('wen-expand') === null) {
                    // todo:: 展开
                    height = this.style.childHeight = this._height + this._wenMenu._menuSpacing;
                    target.setAttribute('wen-expand', '');
                    target.removeAttribute('wen-collapse');
                } else {
                    // todo:: 收起
                    height = -this.style.childHeight;
                    this.style.childHeight = 0;
                    target.setAttribute('wen-collapse', '');
                    target.removeAttribute('wen-expand');
                    this.resetHeight(this._childNodes)
                }
                this._childElement.style.height = this.style.childHeight + 'px';
                if (this._parentNode) {
                    this.setHeight({
                        menuNode: this._parentNode,
                        direction: 'up',
                        childHeight: height,
                        childNode: this,
                    })
                }
            }
        });
    } else {
        if (this._isActive) {
            this._textElement.classList.add('wen-active');
        }
        this._textElement.addEventListener('click', (e) => {
            if (this._wenMenu._autoCollapse) {
                this.resetHeight();
                this.setHeight({
                    menuNode: this._parentNode,
                    direction: 'up',
                    childNode: this,
                    childHeight: this._height,
                })
            }
            this.removeActive(this._wenMenu._activeMenu)
            this._isActive = true;
            this._textElement.classList.add('wen-active');
            let target = e.target;
            if (target.classList.value.indexOf('wen-menu-text') >= 0) {
                target = target.parentElement;
            }
            if (target.classList.value.indexOf('wen-menu-first') >= 0) {
                this._wenMenu._activeMenu = this;
            } else if (this._parentNode) {
                this.addActive(this._parentNode, this)
            } else {
                this._wenMenu._activeMenu = this;
            }
            if (this._wenMenu._event) {
                this._wenMenu._event.call(this, e)
            }
        });
    }
    return this;
}
 
 
WenMenuNode.prototype.setHeight = function ({
                                                menuNode = null,
                                                direction = 'down',
                                                childHeight = 0,
                                                childNode = null,
                                            }) {
    if (!menuNode) {
        return 0;
    }
    menuNode._textElement.setAttribute('wen-expand', '');
    menuNode._textElement.removeAttribute('wen-collapse');
    if (this._wenMenu._autoCollapse) {
        menuNode.style.childHeight = menuNode._height;
    }
    if (direction == 'down') {
        if (menuNode._subs.length) {
            menuNode.style.childHeight += (this._wenMenu._menuSpacing * (childNode ? childNode._level : 1));
            if (menuNode._isActive) {
                menuNode.style.childHeight += this.setHeight({
                    menuNode: menuNode._activeChild,
                });
            }
            if (menuNode._childElement) {
                menuNode._childElement.style.height = menuNode.style.childHeight + "px";
            }
            if (menuNode._parentNode) {
                this.setHeight({
                    menuNode: menuNode._parentNode,
                    direction: 'up',
                    childNode: menuNode,
                    childHeight: menuNode.style.childHeight,
                });
            }
        }
    } else {
        menuNode.style.childHeight += (childHeight + this._wenMenu._menuSpacing);
        menuNode._childElement.style.height = menuNode.style.childHeight + "px";
        if (menuNode._parentNode) {
            this.setHeight({
                menuNode: menuNode._parentNode,
                direction: 'up',
                childHeight: menuNode.style.childHeight,
                childNode: menuNode,
            });
        }
    }
    return menuNode.style.childHeight;
}
 
WenMenuNode.prototype.resetHeight = function (menuNodes) {
    if (!menuNodes) {
        menuNodes = this._wenMenu._menuNodes;
    }
    menuNodes.forEach((node) => {
        if (node._childElement) {
            node.style.childHeight = 0;
            node._childElement.style.height = '0px';
        }
        if (node._childNodes.length) {
            node._textElement.setAttribute('wen-collapse', '');
            node._textElement.removeAttribute('wen-expand');
            this.resetHeight(node._childNodes);
        }
    });
    return this;
}
 
WenMenuNode.prototype.addActive = function (menuNode, activeChildNode) {
    menuNode._isActive = true
    menuNode._textElement.setAttribute('wen-active', '');
    menuNode._textElement.removeAttribute('wen-icon');
    if (this._wenMenu._autoCollapse) {
        menuNode._textElement.setAttribute('wen-expand', '');
        menuNode._textElement.removeAttribute('wen-collapse');
    }
    menuNode._activeChild = activeChildNode;
    if (menuNode._parentNode) {
        this.addActive(menuNode._parentNode, menuNode);
    } else {
        this._wenMenu._activeMenu = menuNode;
    }
    return this;
}
 
/**
 * 去除active属性
 * @param    WenMenuNode menuNode
 * @return    WenMenuNode
 */
WenMenuNode.prototype.removeActive = function (menuNode) {
    menuNode._isActive = false;
    if (menuNode._subs.length) {
        menuNode._textElement.removeAttribute('wen-active');
        menuNode._textElement.setAttribute('wen-icon', '');
        if (this._wenMenu._autoCollapse) {
            menuNode._textElement.setAttribute('wen-collapse', '');
            menuNode._textElement.removeAttribute('wen-expand');
        }
        if (menuNode._activeChild) {
            this.removeActive(menuNode._activeChild);
        }
    } else {
        menuNode._textElement.classList.remove('wen-active');
    }
    return this;
}

(2) WenMenu对象

let WenMenu = function ({
                            ele,
                            menus,
                            event = null,
                            attributes = {},
                            menuHeight = 35,
                            menuSpacing = 0,
                            autoCollapse = true,
                            duration = 300,
                        }) {
    this._ele = ele;
    this._duration = duration;
    this._menus = menus;
    this._event = event;
    this._menuNodes = [];
    this._autoCollapse = autoCollapse;
    this.style = {
        width: '100%',
        height: '100%',
    }
    this._menuElement = this.createElement('ul', attributes);
    this._menuElement.classList.value += 'wen-menu-ul wen-menu-ul-first';
    this._ele.append(this._menuElement);
    this._activeMenu = null;
    this._menuHeight = menuHeight;
    this._menuSpacing = menuSpacing;
    this.init().createStyle().createMenu();
};
 
WenMenu.prototype.init = function () {
    if (this._ele.clientHeight) {
        this._ele.style.overflow = 'hidden';
        this._menuElement.style['overflow-y'] = 'scroll';
        let scrollWidth = this._menuElement.offsetWidth - this._menuElement.clientWidth;
        this.style.width = 'calc(100% + ' + scrollWidth + 'px)';
        this.style.height = this._ele.clientHeight + 'px';
    }
    return this;
}
 
/**
 * 创建菜单
 */
WenMenu.prototype.createMenu = function () {
    this._menus.forEach((item, i) => {
        let node = new WenMenuNode({
            text: item.text,
            attributes: item.attributes,
            subs: item.subs,
            parentElement: this._menuElement,
            wenMenu: this,
            isActive: i == 0,
        });
        this._menuNodes.push(node);
    });
    return this;
};
 
/**
 * 创建元素
 * @param    tagName
 * @param    attributes
 * @returns    {HTMLElement}
 */
WenMenu.prototype.createElement = function (tagName, attributes = {}) {
    let ele = document.createElement(tagName);
 
    function checkValue(value) {
        if (Object.prototype.toString.call(value) === "[object Array]") {
            value = value.join(',');
        } else if (Object.prototype.toString.call(value) === '[object Object]') {
            var valueStr = '';
            Object.keys(value).forEach(function (name) {
                valueStr += name + ":" + checkValue(value[name]) + ";";
            });
            value = valueStr;
        }
        return value;
    }
 
    if (attributes) {
        Object.keys(attributes).forEach((name) => {
            let value = checkValue(attributes[name]);
            ele.setAttribute(name, value);
        })
    }
    return ele;
};
 
 
WenMenu.prototype.createStyle = function () {
    let style = this.createElement('style'),
        head = document.querySelector('head');
    style.innerHTML = `
        .wen-menu-ul-first, .wen-menu-ul-first *{
            padding: 0px;
            margin: 0px;
            border-spacing: 0px;
            list-style: none;
        }
        .wen-menu-ul-first{
            width: ${this.style.width};
            height: ${this.style.height};
        }
        .wen-menu-ul {
            overflow: hidden;
        }
        
        .wen-menu-ul-first, .wen-menu-ul-second {
            background: rgba(0, 0, 0, 0.1);
        }
        .wen-menu-li {
            padding-left: 22px;
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
        }
        .wen-menu-ul-first > .wen-menu-li {
            padding: 0px;
        }
        .wen-menu-ul-second > .wen-menu-li {
            padding: 0px 0px 0px 18px;
        }
        .wen-menu-tree {
            border-left: 1px dashed rgba(0, 0, 0, 1);
            width: 16px;
        }
        .wen-menu-text{
            width: calc(100% - 16px);
            display: flex;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
            -o-text-overflow: ellipsis;
        }
        .wen-menu-li a {
            display: inline-block;
            width: 100%;
            height: ${this._menuHeight}px;
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
            position: relative;
            cursor: pointer;
            display: flex;
            align-items: center;
        }
        .wen-menu-ul, .wen-menu-li a[wen-icon]:after, .wen-menu-li a[wen-active]:after {
            -webkit-transition: all ${this._duration}ms linear;
            -moz-transition: all ${this._duration}ms linear;
            -ms-transition: all ${this._duration}ms linear;
            -o-transition: all ${this._duration}ms linear;
            transition: all ${this._duration}ms linear;
        }
        .wen-menu-li a[wen-expand]:after {
            -webkit-transform: scale(1.3) rotate(90deg);
            -moz-transform: scale(1.3) rotate(90deg);
            -ms-transform: scale(1.3) rotate(90deg);
            -o-transform: scale(1.3) rotate(90deg);
            transform: scale(1.3) rotate(90deg);
        }
        .wen-menu-li a[wen-collapse]:after {
            -webkit-transform: scale(1.3) rotate(180deg);
            -moz-transform: scale(1.3) rotate(180deg);
            -ms-transform: scale(1.3) rotate(180deg);
            -o-transform: scale(1.3) rotate(180deg);
            transform: scale(1.3) rotate(180deg);
        }
        .wen-menu-li a[wen-icon]:after {
            content: '▷';
            position: absolute;
            right: 5px;
            font-weight: bold;
        }
        .wen-menu-li a[wen-active]:after {
            content: '▷';
            position: absolute;
            right: 5px;
            font-weight: bold;
        }
        .wen-menu-first {
            padding-left: 15px !important;
        }
        .wen-menu-li a[wen-active], .wen-active {
            color: white;
        }
        .wen-menu-li a[wen-active].wen-menu-first, .wen-active.wen-menu-first {
            border-left: 3px solid white;
        }
    `;
    if (!head) {
        head = document.body;
    }
    head.append(style);
    return this;
}

三、Example-Code

(1)html文件

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>说明文档</title>
    <script src="/js/canvas/menu.js"></script>
    <style>
        * {
            padding: 0px;
            margin: 0px;
            border-spacing: 0px;
            list-style: none;
        }
        body {
            min-height: 100vh;
            padding: 0px;
            margin: 0px;
        }
        .readme-title {
            background: rgba(0, 0, 50, 0.3);
            width: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
        }
        .readme-body {
            width: 100%;
            height: calc(100% - 75px);
            display: flex;
            justify-content: start;
        }
        .readme-menu-box {
            width: 250px;
            height: 100%;
            position: fixed;
            left: 0px;
            top: 0px;
            background: rgba(100, 10, 10, 0.2);
            overflow: auto;
        }
    </style>
</head>
<body>
<div class="readme-body">
    <div class="readme-menu-box">
        <div class="readme-title">
            <h2>目录</h2>
        </div>
    </div>
</div>
</body>
</html>

(2)JS代码

a、菜单列表

let menuOptions = [{
                    text: "导入数据列表",
                    subs: [
                        {
                            text: "全部数据",
                            attributes: {
                                "data-url": "",
                            },
                            subs: [
                                {
                                    text: "消费金额",
                                    attributes: {
                                        "data-url": "",
                                    }
                                }, {
                                    text: "放款金额",
                                    attributes: {
                                        "data-url": "",
                                    }
                                }, {
                                    text: "返佣金额",
                                    attributes: {
                                        "data-url": "",
                                    }
                                }, {
                                    text: "导入数据",
                                    attributes: {
                                        "data-url": "",
                                    }
                                }, {
                                    text: "查看",
                                    attributes: {
                                        "data-url": "",
                                    }
                                }, {
                                    text: "编辑",
                                    attributes: {
                                        "data-url": "",
                                    }
                                }
                            ]
                        }, {
                            text: "消费金额",
                            attributes: {
                                "data-url": "",
                            }
                        }, {
                            text: "放款金额",
                            attributes: {
                                "data-url": "",
                            }
                        }, {
                            text: "返佣金额",
                            attributes: {
                                "data-url": "",
                            }
                        }, {
                            text: "导入数据",
                            attributes: {
                                "data-url": "",
                            }
                        }, {
                            text: "查看",
                            attributes: {
                                "data-url": "",
                            }
                        }, {
                            text: "编辑",
                            attributes: {
                                "data-url": "",
                            }
                        }
                    ]
                }, {
                    text: "异常数据列表",
                    subs: []
                }, {
                    text: "数据修正",
                    subs: []
                }, {
                    text: "修正审核-客服经理",
                    subs: []
                }, {
                    text: "修正审核-财务",
                    subs: []
                }, {
                    text: "导入日志",
                    subs: []
                }]

b、菜单实例化

window.onload = function () {
            new WenMenu({
                ele: document.querySelector('.readme-menu-box'), // 菜单插入的位置
                menus: menuOptions,
                event: function (e) { }, // 菜单最底端点击事件触发
                attributes: {}, // 最外层ul属性设置
                menuHeight: 35, // 每个菜单项的高度
                autoCollapse: true, // 是否自动收起无活动菜单
            })
        };

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 使用ReactJS实现tab页切换、菜单栏切换、手风琴切换和进度条效果

    ReactJS是Facebook推出的产品.在2013年的Qcon大会(上海)上面,当时Facebook的前端工程师做过一次讲座,就专门介绍了ReactJS. ReactJS可以看做就是用来Render的.ReactJS是可以达到游戏级别的渲染,fps可以保持在60左右,相当的了不起,它做了一个虚拟dom tree加速了渲染过程,根据当时的数据说比angularjs快20%以上. 前沿 对于React, 去年就有耳闻, 挺不想学的, 前端那么多东西, 学了一个框架又有新框架要学

  • JavaScript NodeTree导航栏(菜单项JSON类型/自制)

    最近比较清闲,自己做了个JavaScript NodeTree,网上类似的东西其实挺多的,功能也比这个全,我做这个纯粹为了练练手. 图标可以自定义(16X16),菜单项完全是JSON类型定义的,方便修改. 界面: 使用方法: 1.将NodeTree-JSON.js以及CSS文件夹复制到项目中并引用. 2.引用JQuery框架. 3.修改NodeTree-JSON.js中的NodeTreeMenu菜单项,以下是简单说明. 复制代码 代码如下: var NodeTreeMenu = [ //id:节

  • JS实现自动固定顶部的悬浮菜单栏效果

    本文实例讲述了JS实现自动固定顶部的悬浮菜单栏效果.分享给大家供大家参考.具体如下: 这是一款自动固定顶部的悬浮菜单栏代码,不管你如何拉动滚动条,它会始终显示在网页的最顶部,用作网站的顶级导航或公告之类的比较合适吧. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-fix-top-float-menu-style-codes/ 具体代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 T

  • 原生JS仿苹果任务栏菜单,放大效果的菜单

    相信本菜单会让你学习到一些新鲜的JS技巧. JS仿苹果任务栏菜单 body{margin:0;padding:0} #menu{position:absolute;width:100%;bottom:0;text-align:center;} window.onload = function () { var oMenu = document.getElementById("menu"); var aImg = oMenu.getElementsByTagName("img&

  • 简单实现js菜单栏切换效果

    分享一个小案例,实现菜单栏的切换,点击左侧边栏,展示右侧主体的页面,供大家参考,具体内容如下 首先实现html页面的编写: <div id="header"></div> <div id="main"> <!--左侧边栏--> <div class="affix"> <h4>用户中心</h4> <ul> <li><a href=&qu

  • js实现顶部可折叠的菜单工具栏效果实例

    本文实例讲述了js实现顶部可折叠的菜单工具栏效果.分享给大家供大家参考.具体实现方法如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> &

  • Extjs学习笔记之四 工具栏和菜单

    ToolBar的使用很简单,关键是向ToolBar上面添加内容,默认地ToolBar添加的是Button,不过实际上可以向Toolbar添加任意的组件.下面是一个例子: 复制代码 代码如下: <script type="text/javascript"> Ext.onReady(function() { var tb = new Ext.Toolbar({ renderTo: document.body, width: 600, height: 100, items: [

  • JS实现仿苹果底部任务栏菜单效果代码

    本文实例讲述了JS实现仿苹果底部任务栏菜单效果代码.分享给大家供大家参考.具体如下: 这款仿苹果电脑的底部任务栏菜单,是纯JavaScript实现的菜单特效,鼠标放上有响应效果,菜单图标会变大,而且动画效果非常流畅,以前发过这种效果,但是是使用了jQuery实现的,今天这个没有jQuery插件哦. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-f-apple-buttom-nav-menu-style-codes/ 具体代码如下: <!D

  • 基于vue.js实现侧边菜单栏

    侧边菜单栏应该是很多项目里必不可少的 自己手写了一个 下面是效果图 下面就说一下实现的过程 还是比较简单的 首先导入一下需要的文件 <link rel="stylesheet" type="text/css" href="bootstrap/css/bootstrap.min.css" rel="external nofollow" > <link rel="stylesheet" typ

  • 非常酷的js图形渐隐导航菜单栏

    body { background:#799AE1; margin:0px; font:normal 12px 宋体; } table { border:0px; } td { font:normal 12px 宋体; } img { vertical-align:bottom; border:0px; } a { font:normal 12px 宋体; color:#215DC6; text-decoration:none; } a:hover { color:#428EFF } .sec_

随机推荐