CSS3 树形视图

版权声明:转载请注明出处——http://blog.csdn.net/chy555chy/article https://blog.csdn.net/chy555chy/article/details/83384725

树视图是仿 https://webpack.js.org/concepts/ 做的
图标用的是阿里的iconfont,http://www.iconfont.cn/
在这里插入图片描述

<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<style>
@font-face { font-family: 'icons'; src: url('data:application/font-woff;charset=utf-8;base64,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') format('woff'); }

* {
	font-size: 16px;
	line-height: 2;
	font-weight: 600; 
	margin: 0;
	padding: 0;
	/*
	(1)content-box
	width 和 height 只包括内容(默认)
	(2)border-box 
	width 和 height 属性包括内容,内边距和边框,但不包括外边距。
	*/
	box-sizing: border-box;
}
ul {
	list-style:none;
}
a {
	/* 去掉默认的下划线 */
	text-decoration: none;
	color: #535353;
	/* 属性改变时,需要执行过渡动画的属性名和动画时间 */
	transition: color 1000ms;
	pointer-events: auto;
}
a:hover{
	color: #144f80;
}
li {
	/*
	由于伪元素不是一个DOM对象,所以它不能绑定事件,因此为了绑定事件只能借助其父元素
	pointer事件包括了mouse、touch、pen。
	pointer-events:auto | none | visiblepainted | visiblefill | visiblestroke | visible | painted | fill | stroke | all
	(1)auto:与pointer-events属性未指定时的表现效果相同。在svg内容上与visiblepainted值相同
	(2)none:元素永远不会成为鼠标事件的target。但是,当其后代元素的pointer-events属性指定其他值时,鼠标事件可以指向后代元素,在这种情况下,鼠标事件将在捕获或冒泡阶触发父元素的事件侦听器。
	其他值只能应用在SVG上。
	*/
	pointer-events: none;
}
li::before {
	pointer-events: auto;
}

.treenode-expandable::before {
	/* !import是一个增加样式权重的方法,让浏览器首选执行这个语句 */
	font-family: icons !important;
	content: '\F103';
	cursor: pointer;
	color: #175d96;
	margin-right: 0.5em;
	position: absolute;
	top: 0.1em;
	left: 0.3em;
}
.treenode-expandable {
	position: relative;
}
/* 
elementA>elementB 表示选择父元素为A的所有子元素B
elementA elementB 表示选择祖先元素为A的所有子元素B
 */
.treenode-expandable>a {
	margin-left: 1.5em;
}
.treenode-expandable>ul {
	margin-left: 1.5em;
	position: relative;
}
.treenode-expandable>ul::before {
	/* 如果不设置content伪元素就不会生效 */
	content: '';
	/* absolute的是相对relative的父对象进行定位的。注意:position的默认值为static */
	position: absolute;
	height: calc(100% - 1em);
	border-left: 1px dashed #777676;
}
.treenode::before {
	content: '';
	position: absolute;
	width: 1em;
	top: 1em;
	border-top: 1px dashed #777676;
}
.treenode {
	position: relative;
}
.treenode>a {
	margin-left: 1.5em;
}
</style>
<script>
	//这是一个map对象,map的key和value用方括号包裹,并用逗号分隔
	const listData = new Map([
		[{text: '第1个标签', href: '#1'},
			[	
				[{text: '子节点 1', href: '#1.1'}],
				[{text: '子节点 2', href: '#1.2'}, [
					[{text: '子节点 1', href: '#1.2.1'}],
					[{text: '子节点 2', href: '#1.2.2'}],
					[{text: '子节点 3', href: '#1.2.3'}]]
				],
				[{text: '子节点 3', href: '#1.3'}],
			]
		],
		[{text: '第2个标签', href: '#2'},
			[
				[{text: '子节点 1', href: '#2.1'}],
				[{text: '子节点 2', href: '#2.2'}],
				[{text: '子节点 3', href: '#2.3'}],
			]
		],
		[{text: '第3个标签', href: '#3'},
			[
				[{text: '子节点 1', href: '#3.1'}],
				[{text: '子节点 2', href: '#3.2'}],
				[{text: '子节点 3', href: '#3.3'}],
			]
		]
	]);

	function createList(listData) {
		const list = document.createElement('ul');
		for(const data of listData) {
			const li = document.createElement('li');
			const a = document.createElement('a');
			a.innerText = data[0].text;
			a.setAttribute('href', data[0].href);
			li.appendChild(a);
			const hasChild = (data.length > 1);
			if(hasChild) {
				li.appendChild(createList(data[1]));
			}
			li.setAttribute('class', 'treenode' + (hasChild ? '-expandable' : ''));
			list.appendChild(li);
		}
		return list;
	}
	
	window.onload = () => {
		document.body.appendChild(createList(listData));
		//querySelectorAll会查找元素内部匹配条件的所有元素,而querySelector只会查找元素内部第一个匹配条件的元素
		document.querySelectorAll('.treenode-expandable', '::before').forEach(node => {
			node.onclick = (event)=> {
				//event.target指的是触发事件的元素源,localName用来获取触发事件元素的标签
				switch(event.target.localName) {
					case "li":
						const ul = node.querySelector('ul');
						//setAttribute用来设置元素的属性,而display是style对象内的属性
						ul.style.display = (ul.style.display == "" ? "none" : "");
						break;
					case "a":
						//preventDefault方法用来阻止元素发生默认的行为(点击a标签默认会转向锚点链接)
						//event.preventDefault();
						break;
				}
				//由于事件会逐层向上传递(事件冒泡),因此必须调用该方法阻止事件继续传播
				event.stopPropagation();
			}
		});
	}
</script>
</head>
<body>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/chy555chy/article/details/83384725
今日推荐