• JS与树本(复杂)


    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>树形组件</title>
    </head>
    <link rel="stylesheet" type="text/css" href="task.css">
    <body>
    <fieldset id="tree-module">
    <legend>树形组件</legend>
    <input type="text" id="searchText">&nbsp;
    <button id="search">搜索</button><button id="clear">清除</button>
    <br>
    <p id="result"></p>
    <div id="tree-area">
    <div class="nodebody-visible"><label class="node-header"><div class="arrow empty-arrow"></div> <span class="node-title">前端攻城狮</span><span>&nbsp;&nbsp;</span><img class="addIcon" src="images/add.png"></label></div>
    </div>
    </fieldset>
    <script src="task.js"></script>
    </body>
    </html>

    //////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////////////

    span{
    margin:0;
    padding:0;
    }
    #tree-module{
    display: inline-block;
    400px;
    position: relative;
    left: 50%;
    margin-left: -200px;
    }
    #clear{
    margin-left: 10px;
    }
    #result{
    font-size: 14px;
    font-family: "Microsoft YaHei UI";
    text-align: center;
    height: 16px;
    }

    /* 以下是结点部分的样式 */
    .nodebody-visible {
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
    justify-content: flex-start;
    margin: 5px 18px;
    background-color: #ffffff;
    user-select:none;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    }
    .nodebody-hidden {
    display: none;
    }
    .arrow{
    display: inline-block;
    margin-right: 6px;
    }
    .right-arrow{
    0;
    height: 0;
    border-left: 10px solid #6898c2;
    border-top: 5px solid transparent;
    border-bottom: 5px solid transparent;
    cursor: pointer;
    }
    .down-arrow{
    0;
    height: 0;
    border-top: 10px solid #6898c2;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    cursor: pointer;
    }
    .empty-arrow{
    border-left:10px solid transparent;
    }
    .node-title{
    font-family: "Microsoft YaHei UI";
    font-size: 14px;
    color: #6898c2;
    line-height: 1.5em;
    }
    .node-title:hover{
    color: blue;
    cursor: pointer;
    }
    .node-title-highlight{
    color: red;
    font-weight: bold;
    }
    .addIcon,.deleteIcon{
    display: none;
    vertical-align: top;
    }
    .addIcon:hover,.deleteIcon:hover{
    cursor: pointer;
    }
    .node-header:hover>.addIcon,.node-header:hover>.deleteIcon{
    display: inline;
    }
    br{
    clear: both;
    }
    legend {
    font-family: "黑体";
    font-size: 20px;
    }
    .root, fieldset {
    float: left;
    }

    /////////////////////////////////////////////////////////////////////////

    /////////////////////////////////////////////////////////////////////////

    // ==========================================封装TreeNode================================================
    function TreeNode(obj) {
    this.parent = obj.parent;
    this.childs = obj.childs || [];
    this.data = obj.data || "";
    this.selfElement = obj.selfElement; // 访问对应的DOM结点
    this.selfElement.TreeNode = this; // 对应的DOM结点访问回来
    }
    // 原型模式封装公共操作
    TreeNode.prototype = {
    constructor: TreeNode,
    // 解耦样式操作,四个参数表示是否改变箭头、可见性、改为高亮、改为普通,后两个参数可省略
    render: function (arrow, visibility, toHighlight, deHighlight) {
    if (arguments.length < 3) {
    toHighlight = false;
    deHighlight = false;
    }
    if (arrow) {
    if (this.isLeaf()) { // 是个叶节点,设为空箭头
    this.selfElement.getElementsByClassName("arrow")[0].className = "arrow empty-arrow";
    }
    else if (this.isFolded()) { // 折叠状态,设为右箭头
    this.selfElement.getElementsByClassName("arrow")[0].className = "arrow right-arrow";
    }
    else { // 展开状态,设为下箭头
    this.selfElement.getElementsByClassName("arrow")[0].className = "arrow down-arrow";
    }
    }
    if (visibility) { // 改变可见性
    if (this.selfElement.className.indexOf("nodebody-visible") == -1) { // 本不可见,改为可见
    this.selfElement.className = this.selfElement.className.replace("hidden", "visible");
    }
    else { //改为不可见
    this.selfElement.className = this.selfElement.className.replace("visible", "hidden");
    }
    }
    if (toHighlight) { // 设为高亮
    this.selfElement.getElementsByClassName("node-title")[0].className = "node-title node-title-highlight";
    }
    if (deHighlight) { // 取消高亮
    this.selfElement.getElementsByClassName("node-title")[0].className = "node-title";
    }
    },
    // 删除结点,DOM会自动递归删除子节点,TreeNode递归手动删除子节点
    deleteNode: function () {
    var i;
    // 递归删除子节点
    if(!this.isLeaf()){
    for(i=0;i<this.childs.length;i++){
    this.childs[i].deleteNode();
    }
    }
    this.parent.selfElement.removeChild(this.selfElement);// 移除对应的DOM结点
    for (i = 0; i < this.parent.childs.length; i++) { // 从父节点删除该孩子
    if (this.parent.childs[i] == this) {
    this.parent.childs.splice(i, 1);
    break;
    }
    }
    // 调整父结点箭头样式
    this.parent.render(true, false);
    },
    // 增加子节点
    addChild: function (text) {
    if (text == null) return this;
    if (text.trim() == "") {
    alert("节点内容不能为空!");
    return this;
    }
    // 先增加子节点,再渲染自身样式
    // 若当前节点关闭,则将其展开
    if(!this.isLeaf() && this.isFolded()){
    this.toggleFold();
    }
    // 创建新的DOM结点并附加
    var newNode = document.createElement("div");
    newNode.className = "nodebody-visible";
    var newHeader = document.createElement("label");
    newHeader.className = "node-header";
    var newSymbol = document.createElement("div");
    newSymbol.className = "arrow empty-arrow";
    var newTitle = document.createElement("span");
    newTitle.className = "node-title";
    newTitle.innerHTML = text;
    var space = document.createElement("span");
    space.innerHTML = "&nbsp;&nbsp;";
    var newDelete = document.createElement("img");
    newDelete.className = "deleteIcon";
    newDelete.src = "images/delete.png";
    var newAdd = document.createElement("img");
    newAdd.className = "addIcon";
    newAdd.src = "images/add.png";
    newHeader.appendChild(newSymbol);
    newHeader.appendChild(newTitle);
    newHeader.appendChild(space);
    newHeader.appendChild(newAdd);
    newHeader.appendChild(newDelete);
    newNode.appendChild(newHeader);
    this.selfElement.appendChild(newNode);
    // 创建对应的TreeNode对象并添加到子节点队列
    this.childs.push(new TreeNode({parent: this, childs: [], data: text, selfElement: newNode}));
    // 渲染自身样式
    this.render(true, false);
    return this; // 返回自身,以便链式操作
    },
    // 展开、收拢结点
    toggleFold: function () {
    if (this.isLeaf()) return this; // 叶节点,无需操作
    // 改变所有子节点的可见状态
    for (var i=0;i<this.childs.length;i++)
    this.childs[i].render(false, true);
    // 渲染本节点的箭头
    this.render(true, false);
    return this; // 返回自身,以便链式操作
    },
    // 判断是否为叶结点
    isLeaf: function(){
    return this.childs.length == 0;
    },
    // 判断结点是否处于折叠状态
    isFolded: function(){
    if(this.isLeaf()) return false; // 叶结点返回false
    if(this.childs[0].selfElement.className == "nodebody-visible") return false;
    return true;
    }
    };
    //=======================================以上是封装TreeNode的代码=============================================

    //=============================================事件绑定区===============================================
    // 创建根节点对应的TreeNode对象
    var root = new TreeNode({parent: null, childs: [], data: "前端攻城狮", selfElement: document.getElementsByClassName("nodebody-visible")[0]});
    // 为root绑定事件代理,处理所有节点的点击事件
    addEvent(root.selfElement, "click", function (e) {
    var target = e.target || e.srcElement;
    var domNode = target;
    while (domNode.className.indexOf("nodebody") == -1) domNode = domNode.parentNode; // 找到类名含有nodebody前缀的DOM结点
    selectedNode = domNode.TreeNode; // 获取DOM对象对应的TreeNode对象
    // 如果点在节点文字或箭头上
    if (target.className.indexOf("node-title") != -1 || target.className.indexOf("arrow") != -1) {
    selectedNode.toggleFold(); // 触发toggle操作
    }
    else if (target.className == "addIcon") { // 点在加号上
    selectedNode.addChild(prompt("请输入子结点的内容:"));
    }
    else if (target.className == "deleteIcon") { // 点在减号上
    selectedNode.deleteNode();
    }
    });

    // 给root绑定广度优先搜索函数,无需访问DOM,返回一个搜索结果队列
    root.search = function (query) {
    var resultList = [];
    // 广度优先搜索
    var queue = []; // 辅助队列,顺序存储待访问结点
    var current = this;
    // 当前结点入队
    queue.push(current);
    while (queue.length > 0) {
    // 从“待访问”队列取出队首结点访问,并将其所有子节点入队
    current = queue.shift();
    // 还原当前结点颜色
    current.render(false, false, false, true);
    // 读取当前结点data
    if (current.data == query) resultList.push(current); //找到了
    // 将当前结点的所有孩子节点入“待访问”队
    for (var i=0;i<current.childs.length;i++) {
    queue.push(current.childs[i]);
    }
    }
    return resultList;
    };
    // 搜索并显示结果
    addEvent(document.getElementById("search"), "click", function () {
    var text = document.getElementById("searchText").value.trim();
    if(text == "") {
    document.getElementById("result").innerHTML = "请输入查询内容!";
    return;
    }
    // 执行搜索
    var resultList = root.search(text);
    // 处理搜索结果
    if (resultList.length == 0) {
    document.getElementById("result").innerHTML = "没有查询到符合条件的结点!";
    }
    else {
    document.getElementById("result").innerHTML = "查询到" + resultList.length + "个符合条件的结点";
    // 将所有结果结点沿途展开,结果结点加粗红色展示
    var pathNode;
    for (var x = 0;x<resultList.length;x++) {
    pathNode = resultList[x];
    pathNode.render(false, false, true, false);
    while (pathNode.parent != null) {
    if (pathNode.selfElement.className == "nodebody-hidden") pathNode.parent.toggleFold(); // 若是收拢状态,则展开
    pathNode = pathNode.parent;
    }
    }
    }
    });
    // 清除搜索结果
    addEvent(document.getElementById("clear"), "click", function () {
    document.getElementById("searchText").value = "";
    root.search(null); // 清除高亮样式
    document.getElementById("result").innerHTML = "";
    });
    //==================================================================================================

    //=======================================Demo展示区==================================================
    //动态生成Demo树
    root.addChild("技术").addChild("IT公司").addChild("谈笑风生");
    root.childs[0].addChild("HTML5").addChild("CSS3").addChild("JavaScript").addChild("PHP").addChild("Node.JS").toggleFold();
    root.childs[0].childs[4].addChild("JavaScript").toggleFold();
    root.childs[1].addChild("百度").addChild("腾讯").addChild("大众点评").toggleFold();
    root.childs[2].addChild("身经百战").addChild("学习一个").addChild("吟两句诗").toggleFold();
    root.childs[2].childs[2].addChild("苟利国家生死以").toggleFold();
    //初始化查询Demo值
    document.getElementById("searchText").value = "JavaScript";
    //==================================================================================================

    // 跨浏览器兼容的工具函数
    function addEvent(element, type, handler) {
    if (element.addEventListener) {
    element.addEventListener(type, handler);
    }
    else if (element.attachEvent) {
    element.attachEvent("on" + type, handler);
    }
    else {
    element["on" + type] = handler;
    }
    }

  • 相关阅读:
    HBase(2) Java 操作 HBase 教程
    HBase(1) 基本入门篇
    MongoDB 谨防索引seek的效率问题
    MongoDB一次节点宕机引发的思考(源码剖析)
    MongoDB-系统时钟跳变引发的风波
    是什么造成了数据库的卡顿
    了解 MongoDB 看这一篇就够了
    Reactive(3)5分钟理解 SpringBoot 响应式的核心-Reactor
    Reactive(2) 响应式流与制奶厂业务
    suanec-rotatelogs
  • 原文地址:https://www.cnblogs.com/xiaohaishuangyu/p/6021660.html
Copyright © 2020-2023  润新知