美文网首页
树形结构菜单

树形结构菜单

作者: 小柠有点萌 | 来源:发表于2020-08-04 14:05 被阅读0次
image.png

不使用插件封装

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
    <title></title>
    <link rel="stylesheet" href="css/reset.min.css">
    <style>
        .container {
            box-sizing: border-box;
            margin: 20px auto;
            padding: 10px;
            width: 600px;
            height: 300px;
            border: 1px dashed #AAA;
            -webkit-user-select: none;
            overflow: auto;
        }

        .level {
            display: none;
            font-size: 14px;
            margin-left: 10px;
        }

        .level.level0 {
            display: block;
            margin-left: 0;
        }

        .level li {
            position: relative;
            padding-left: 15px;
            line-height: 30px;
        }

        .level li .icon {
            position: absolute;
            left: 0;
            top: 9px;
            box-sizing: border-box;
            width: 12px;
            height: 12px;
            line-height: 8px;
            text-align: center;
            border: 1px solid #AAA;
            background: #EEE;
            cursor: pointer;
        }

        .level li .icon:after {
            display: block;
            content: "+";
            font-size: 12px;
            font-style: normal;
        }

        .level li .icon.open:after {
            content: "-";
        }

        .level li .title {
            color: #000;
        }
    </style>
    </head>
    <body>
        <div class="container">
            <ul class="level level0" id="zTree1"></ul>
        </div>

    <script type="text/javascript">
        (async function(){
            function queryData() {
                return new Promise(resolve => {
                    let xhr = new XMLHttpRequest;
                    xhr.open('GET', './data.json');
                    xhr.send();
                    xhr.onreadystatechange = function () {
                        if (xhr.status === 200 && xhr.readyState === 4) {
                            resolve(JSON.parse(xhr.responseText));
                        }
                    };
                    
                });
            }
            let result=await queryData();
            let  i=0;
            function bindHtml(result){
                i++;
                let str = ``;
                result.forEach(element => {
                    let {
                            name,
                            children,
                            open
                        } = element;
                        
                    str += `<li>
                        <a href="javascript:;" class="title">${name}</a>
                        ${children && children.length>0?`
                            <em class="icon ${open?'open':''}"></em>
                            <ul class="level level${i}" 
                                style="display:${open?'block':'none'}">
                                ${bindHtml(children)}
                            </ul>
                        `:``}
                    </li>`
                });
                i--;
                return  str;
            }
            let zTree=document.querySelector("#zTree1");
            zTree.innerHTML=bindHtml(result);

            zTree.addEventListener('click', (ev) => {
                // this -> 实例
                let target = ev.target,
                    targetTag = target.tagName;
                // 合并事件源(把A处理成为EM)
                if (targetTag === 'A') {
                    target = target.nextElementSibling;
                    targetTag = target ? "EM" : "";
                }

                // 如果事件源是EM
                if (targetTag === "EM") {
                    let ulBox = target.nextElementSibling;
                    if (!ulBox) return;
                    let sty = ulBox.style.display;
                    if (sty === "block") {
                        // 当前是展示的:我们让其隐藏
                        ulBox.style.display = "none";
                        target.className = "icon";
                        return;
                    }
                    // 当前是隐藏的:我们让其展示
                    ulBox.style.display = "block";
                    target.className = "icon open";
                    return;
                }
            });
            })();
        </script>

</body>
</html>

使用插件封装

html

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>zTree树形结构菜单</title>
    <!-- import css -->
    <link rel="stylesheet" href="css/reset.min.css">
    <style>
        .container {
            box-sizing: border-box;
            margin: 20px auto;
            padding: 10px;
            width: 600px;
            height: 300px;
            border: 1px dashed #AAA;
            -webkit-user-select: none;
            overflow: auto;
        }

        .level {
            display: none;
            font-size: 14px;
            margin-left: 10px;
        }

        .level.level0 {
            display: block;
            margin-left: 0;
        }

        .level li {
            position: relative;
            padding-left: 15px;
            line-height: 30px;
        }

        .level li .icon {
            position: absolute;
            left: 0;
            top: 9px;
            box-sizing: border-box;
            width: 12px;
            height: 12px;
            line-height: 8px;
            text-align: center;
            border: 1px solid #AAA;
            background: #EEE;
            cursor: pointer;
        }

        .level li .icon:after {
            display: block;
            content: "+";
            font-size: 12px;
            font-style: normal;
        }

        .level li .icon.open:after {
            content: "-";
        }

        .level li .title {
            color: #000;
        }
    </style>
</head>

<body>
    <div class="container">
        <ul class="level level0" id="zTree1"></ul>
    </div>

    <div class="container">
        <ul class="level level0" id="zTree2"></ul>
    </div>

    <div class="container">
        <ul class="level level0" id="zTree3"></ul>
    </div>

    <!-- IMPORT JS -->
    <!-- 
        写插件(目的是重复利用):
        1. 先把一个的效果/功能实现全了
        2. 把插件的配置和功能需求规划好
        3. 基于面向对象实现插件化开发(面向对象中:每一个插件就是一个类,调用插件就是创建这个类的一个实例,这样既可以实现某些信息的私有化,也可以实现某些方法公用)
     -->
    <!-- <script src="js/zTree.js"></script> -->
    <script src="js/zTree-plugin.js"></script>
    <script>
        // $zTree([element],[data]);
        function queryData() {
            return new Promise(resolve => {
                let xhr = new XMLHttpRequest;
                xhr.open('GET', './data.json');
                xhr.onreadystatechange = function () {
                    if (xhr.status === 200 && xhr.readyState === 4) {
                        resolve(JSON.parse(xhr.responseText));
                    }
                };
                xhr.send(null);
            });
        }

        queryData().then(result => {
            $zTree(zTree1, result);
            $zTree(zTree2, result);
            $zTree(zTree3, result);
        });
    </script>
</body>

</html>

js/zTree-plugin.

/* 
let $zTree = (function () {
    function $zTree(element, data) {
        return new $zTree.fn.init(element, data);
    }
    $zTree.fn = $zTree.prototype = {
        constructor: $zTree,
        //...
    };

    let init = $zTree.fn.init = function init(element, data) {

    };
    init.prototype = $zTree.fn;

    return $zTree;
})();
 */


let $zTree = (function () {
    class zTree {
        // this.xxx=xxx 设置私有属性
        constructor(element, data) {
            // 把参数挂载到实例上,这样我们就可以在其它方法中基于this.xxx获取到这些信息了(一般我们把需要在其它方法中使用的信息都挂载到实例上:这样可以实现信息的公用,也是面向对象插件开发的优势 => 保证各个方法中的THIS是实例)
            this.element = element;
            this.data = data;
            this.level = 0;
            this.init();
        }
        // zTree.prototype
        bindHTML(result) {
            this.level++;
            let str = ``;
            result.forEach(item => {
                let {
                    name,
                    children,
                    open
                } = item;
                str += `<li>
                    <a href="javascript:;" class="title">${name}</a>
                    ${children && children.length>0?`
                        <em class="icon ${open?'open':''}"></em>
                        <ul class="level level${this.level}" 
                            style="display:${open?'block':'none'}">
                            ${this.bindHTML(children)}
                        </ul>
                    `:``}
                </li>`;
            });
            this.level--;
            return str;
        }
        delegate() {
            this.element.addEventListener('click', (ev) => {
                // this -> 实例
                let target = ev.target,
                    targetTag = target.tagName;

                // 合并事件源(把A处理成为EM)
                if (targetTag === 'A') {
                    target = target.nextElementSibling;
                    targetTag = target ? "EM" : "";
                }

                // 如果事件源是EM
                if (targetTag === "EM") {
                    let ulBox = target.nextElementSibling;
                    if (!ulBox) return;
                    let sty = ulBox.style.display;
                    if (sty === "block") {
                        // 当前是展示的:我们让其隐藏
                        ulBox.style.display = "none";
                        target.className = "icon";
                        return;
                    }
                    // 当前是隐藏的:我们让其展示
                    ulBox.style.display = "block";
                    target.className = "icon open";
                    return;
                }
            });
        }
        init() {
            // 在这里控制先做什么再做什么的逻辑顺序(大脑)
            // 1.数据绑定,this.element是DOM,this.data是数据
            this.element.innerHTML = this.bindHTML(this.data);
            // 2.事件委托实现效果
            this.delegate();
        }
    }

    return function $zTree(element, data) {
        // init params
        if (element == null || typeof element !== "object" || element.nodeType !== 1) {
            throw new TypeError('element must to be a html element!');
        }
        if (data == null || !Array.isArray(data) || data.length <= 0) {
            throw new TypeError('data must to be a array and not empty!');
        }
        return new zTree(element, data);
    };
})();

reset.min.css

body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,button,input,textarea,th,td{margin:0;padding:0}body{font-size:12px;font-style:normal;font-family:"\5FAE\8F6F\96C5\9ED1",Helvetica,sans-serif}small{font-size:12px}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4,h5,h6{font-size:100%}ul,ol{list-style:none}a{text-decoration:none;background-color:transparent}a:hover,a:active{outline-width:0;text-decoration:none}table{border-collapse:collapse;border-spacing:0}hr{border:0;height:1px}img{border-style:none}img:not([src]){display:none}svg:not(:root){overflow:hidden}html{-webkit-touch-callout:none;-webkit-text-size-adjust:100%}input,textarea,button,a{-webkit-tap-highlight-color:rgba(0,0,0,0)}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]),video:not([controls]){display:none;height:0}progress{vertical-align:baseline}mark{background-color:#ff0;color:#000}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}button,input,select,textarea{font-size:100%;outline:0}button,input{overflow:visible}button,select{text-transform:none}textarea{overflow:auto}button,html [type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted ButtonText}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-cancel-button,[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.clearfix:after{display:block;height:0;content:"";clear:both}

相关文章

网友评论

      本文标题:树形结构菜单

      本文链接:https://www.haomeiwen.com/subject/xsslqktx.html