不使用插件封装
<!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}
网友评论