JS / JQ書き込みツリー構造---他の人が書いたコード-分析と説明

ツリー構造を作成したい場合は、誰もがこの記事テンプレートで詳細を読んでいますよね?これは非常に実用的ですが、理解できないと多くの問題が発生し、変更が少し難しいため、最初に作成者がこの機能をどのように実現するかを理解する必要があります。以下の作成者は値リンクの作成者であり、この記事の著者。

著者が作成したツリー構造は、ローカルの静的json形式に基づいています。バックエンドまたはデータベースから取得する場合がありますが、それと切り離すことはできません(多くの場所は非常に苦痛で疲れます!私はその後jsonに精通していません長い間、穴を開けないでください学びたい場合は、よく読んでください):

 

https://www.cnblogs.com/wpw1215/p/12021521.html

 

著者の基本的な考えを分析し、著者の考えに従って修正を加えましょう。

まず、作成者の静的json形式です。動的に取得する場合は、この形式に従う必要があります。作者のフォーマットはたくさんフォーマットされています。フォーマットの方法がわからない場合は、フォーマットツールを参照して、jsonフォーマットが正しいかどうかを確認してください。

 // 源数据
    const data = [
        {
            id: 1,
            name: "高配室",
            spread: true,
            tempChildren: [],
            children: [
                {
                    id: 2,
                    name: "第一个子节点",
                    edit: false,
                    checked: false,
                    children: [
                        {
                            id: 8,
                            edit: false,
                            checked: false,
                            name: "孙子节点",
                            children: []
                        },
                    ]
                },
                {
                    id: 5,
                    name: "第二个子节点",
                    checked: false,
                    edit: false,
                    children: []
                },
            ]
        }
    ];

サブクラスの子が空でない場合は、いいえが見つかりました[...]。それ以外の場合、children []は空またはnullです

たとえば、バックエンドから受け取るjson形式は次のとおりです(私が言ったように、バックエンドは私に与えました):

[{"GroupID":0,"GroupName":"根节点中国","ChildID":1,"spread":true,"tempChildInfo":[],"childInfo":[{"GroupID":7658,"ChildID":0,"PlicyID":0,"GroupName":"第1子节点山东省2","ParentID":0,"childInfo":[]},{"GroupID":9555,"ChildID":1,"PlicyID":0,"GroupName":"第2子节点广东省","ParentID":0,"childInfo":[{"GroupID":17811,"ChildID":1,"PlicyID":0,"GroupName":"第1孙节点深圳市","ParentID":9555,"childInfo":[{"GroupID":27590,"ChildID":0,"PlicyID":0,"GroupName":"第1曾孙节南山区点","ParentID":17811,"childInfo":null},{"GroupID":28320,"ChildID":0,"PlicyID":0,"GroupName":"第2曾孙节宝安区点","ParentID":17811,"childInfo":null}]},{"GroupID":20401,"ChildID":0,"PlicyID":0,"GroupName":"第2孙节点广州市","ParentID":9555,"childInfo":null}]}]}]

フォーマットツールによると:https//www.sojson.com/

このようにすると、はるかに明確になります。

let myooo =
[{
	"GroupID": 0,
	"GroupName": "根节点中国",
	"ChildID": 1,
	"spread": true,
	"tempChildInfo": [],
	"childInfo": [{
		"GroupID": 7658,
		"ChildID": 0,
		"PlicyID": 0,
		"GroupName": "第1子节点山东省2",
		"ParentID": 0,
		"childInfo": []
	}, {
		"GroupID": 9555,
		"ChildID": 1,
		"PlicyID": 0,
		"GroupName": "第2子节点广东省",
		"ParentID": 0,
		"childInfo": [{
			"GroupID": 17811,
			"ChildID": 1,
			"PlicyID": 0,
			"GroupName": "第1孙节点深圳市",
			"ParentID": 9555,
			"childInfo": [{
				"GroupID": 27590,
				"ChildID": 0,
				"PlicyID": 0,
				"GroupName": "第1曾孙节南山区点",
				"ParentID": 17811,
				"childInfo": null
			}, {
				"GroupID": 28320,
				"ChildID": 0,
				"PlicyID": 0,
				"GroupName": "第2曾孙节宝安区点",
				"ParentID": 17811,
				"childInfo": null
			}]
		}, {
			"GroupID": 20401,
			"ChildID": 0,
			"PlicyID": 0,
			"GroupName": "第2孙节点广州市",
			"ParentID": 9555,
			"childInfo": null
		}]
	}]
}]

最上位レベルはルートノードであり、ルートノードはデータベースに確立されており、同じレベルの誰も確立されていないため、一意であることに注意してください。

顧客がこれでレベルを確立する必要がある場合、簡単なアイデアはページのルートノードを非表示にすることであり、インターフェイスの最初のバイトは最も高度であると見なされ、ルートノードまたはローカルと呼ばれます。このように、非表示のルートノードに新しい子ノードを作成できます。

次の図に示すように、これは実行され、同じレベルがルートノードでの新規作成です。理由は実際には非常に単純です。

 

コードでルート作成者と同じ形式を受け取る方法は?Myoooはバックグラウンドで受信されるため、上記と一致します。

  let tempData =
             [
                  {
                      "GroupID": 0,
                      "GroupName":"根节点",
                      "ChildID":1,
                      "spread":true,
                      "tempChildInfo":[],
                      "childInfo":myooo
                  }
              ];

上記は受信データであり、リクエストがある場合にのみ受信する必要があります。リクエストの形式は受信と一致しており、形式は作成者と同じである必要があります。

 // 发送数据给后端处理
    let data = {
          "id": 随机数id,
          "actionType": 1,//约定发送查询的内容
          "moduleType": 1,//约定发送查询的内容
          "reqData": ""
        }
      var sendStr = JSON.stringify(data);
      console.log("发送数据(转换后):" + sendStr);
      ws.send(sendStr);

さて、JSON形式は終わりました。CSSレイアウトに注意を払うべき場所がいくつかあります。

まず、この小さな部分はCSSを介して変更または非表示にでき、色が変わります。

2番目:このエディターの色もcssによって変更されます

3番目: 選択した色はcssを介して変更できます

4番目:それはより重要で重要です。新しく作成されたグループのサブカテゴリは自動的に後方にインデントされますが、これもメソッドではなくcssによって変更されます。

上記の誰もが著者がそれを書いた場所を見つけようとしますか?次のように、色がどこにあるかを確認します。

<style>
    .containerParent {
        display: flex;
        flex-direction: column;
        width: auto;
    }
 
    .containerChildren {
        margin-left: 15px;
        width: 300px;
        border-left-style: dotted;
        border-color: #D8D8D8;
    }
 
    .parentChild {
        width: 300px;
    }
 
    .operaion_row-button {
        display: inline-block;
        min-width: 50px;
    }
 
    .editContainer {
        display: inline-block;
        padding-left: 10px;
        padding-right: 10px;
        width: 100px;
        height: 20px;
        max-width: 100px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap
    }
 
    .editContainer:focus {
        color: goldenrod;
    }
 
    .Icon_class {
        width: 15px;
        height: 15px;
    }
 
    .parentIcon {
        margin-left: 10px;
    }
 
    .parent_span {
        margin-left: 10px;
    }
 
    .descriter {
        display: inline-block;
        margin-top: -3px;
        color: #D8D8D8;
        vertical-align: top;
    }
 
    .focusClass {
        color: blue;
    }
</style>

 

次は、動的レイアウトを使用して達成する作者です。このトリックは非常に高いです。

 // 获取父级数据,这个父级就是根节点内容
    function getParent(currentData) {
        if (currentData.id == "") return;//判断是不是删除的群组
        let html = "";
        currentData.map(data => { //这个是递归,也就是循环的意思
            let htmlValue = "";
            if (data.id != 9999) {//这个是删除群组功能用的,被删除的id变为9999就是删除的意思
             
//这个就是动态布局   
htmlValue = `
          <div class= "containerParent">
            <div class="parentChild">
              <img  src = ${data.spread == true ? "./imgs/free.svg" : "./imgs/shrink.svg"}  alt="切换是否显示图标" class="Icon_class" onclick = ${`"toggleFnc(${data.id})"`} />
              <span data-appid=${data.id} class="parent_span">${data.name}</span>
              <img  src = "./imgs/add.svg"  alt="新增按钮" class="Icon_class parentIcon" onclick = ${`"add(${data.id})"`} />
            </div>
            ${data.children && data.children.length > 0 ? getChildren(data.children) : ""}
          </div>
        `
            }
 
 
            html += htmlValue;//这个是刷新页面用的
        })
 
        return html;//这个是刷新页面用的
    }

そのレイアウトを見てください:

<div class= "containerParent">
            <div class="parentChild">

                //img就是拿个伸缩图标
              <img  src = ${data.spread == true ? "./imgs/free.svg" : "./imgs/shrink.svg"}  alt="切换是否显示图标" class="Icon_class" onclick = ${`"toggleFnc(${data.id})"`} />

              
              <span data-appid=${data.id} class="parent_span">${data.name}</span>//获取父类名称
  
              //根节点的新增按钮,这里注意没有删除按钮,就是只能新建第1子节点,不能新建根节点同级的意思。
              <img  src = "./imgs/add.svg"  alt="新增按钮" class="Icon_class parentIcon" onclick = ${`"add(${data.id})"`} />
            </div>

            //这个是判断是否还有子类,如果根节点由子类就调用子类的方法 getChildren(data.children)
            ${data.children && data.children.length > 0 ? getChildren(data.children) : ""}
          </div>

1.格納式アイコンの機能:

実際、toggleFnc($ {data.id})を呼び出す方法は、親IDであるdata.idを渡すことです。

 // 切换子树中的显示状态
    function toggleFnc(val) { //val就是传过来的data.id,根节点的id就是0
        data.map(currentData => { //这个是遍历循环
            if (currentData.id == val) { //currentData.id 这个就是子类的id,val就是根节点id
               
                
                let temCuttentchildren = currentData.children;
                let temCuttenttempChildren = currentData.tempChildren;//这个tempChildren作者定义为[]空就是为空在这里使用

                //相互替换置空就是为了伸缩效果
                currentData.children = temCuttenttempChildren
                currentData.tempChildren = temCuttentchildren;
 
                currentData.spread = !currentData.spread //=true这个删除后就没有伸缩效果图
            }
        })
        container.innerHTML = getParent(data);//为了刷新页面使用
    };

新機能など。ルートサブクラスについて話しましょう。次に、サブクラスの呼び出しメソッドを見てみましょう。

//    获取子树数据,写法类似父类
    function getChildren(data) {//父类的data
        let currentData;
        let html = "";
        if (data.id == "" || data.id == 9999) return html;//删除的就不用管
        data.map((cuttentDate) => { //循环功能,遍历功能、递归功能的意思
        
        //在一些地方需要获取子类的群组id,所以我就自己写个方法,不需要可以忽略
        window.allphonegroupname(cuttentDate.GroupName,cuttentDate.GroupID);//把这个值传出去
            //这个cuttentDate 一定要是Object对象,否则不能进入判断
            if(!(cuttentDate instanceof Object)){
                  cuttentDate=JSON.parse(cuttentDate)
            }


            if (cuttentDate.id == 9999) return html;//删除的就不用管
            let htmlValue
            if (cuttentDate.id) { //这个cuttentDate 一定要是Object对象,否则不能进入
                //能进入到这里才是子类或者孙类···

                let spanVal = `<img  src = "./imgs/define.svg"  alt="确定按钮" class="Icon_class" onclick = ascertain(${cuttentDate.id})>`;
                let inputClick = cuttentDate.id + "checkbox" //<img>的id使用动态方式

                htmlValue =
                    `
          <div class="containerChildren">
                 <span class="descriter">...</span>
                 ${cuttentDate.checked == true ?
                        `<img  src = "./imgs/checked.svg" onclick = ${`"selectionFunc(${cuttentDate.id},${cuttentDate.checked})"`}  id=${inputClick} alt="选中按钮" class="Icon_class" >` :
                        `<img  src = "./imgs/unChecked.svg" onclick = ${`"selectionFunc(${cuttentDate.id},${cuttentDate.checked})"`}  id=${inputClick} alt="不选中按钮" class="Icon_class">`
                    }
         
             <span id=${cuttentDate.id} contenteditable = ${cuttentDate["edit"]} class="editContainer" title=${cuttentDate.name}>${cuttentDate.name}</span>
              ${cuttentDate.edit == false ? "" : spanVal}
      
              <img  src = "./imgs/add.svg"  alt="新增按钮" class="Icon_class" onclick = ${`"add(${cuttentDate.id})"`}>
              <img  src = "./imgs/remove.svg"  alt="删除按钮" class="Icon_class" onclick = ${`"remove(${cuttentDate.id})"`}>
             
            ${cuttentDate.children && cuttentDate.children.length > 0 ? getChildren(cuttentDate.children) : ""}
          </div >
           
        `
            }
            html += htmlValue //刷新使用
        })
 
        return html //刷新使用
    }

そのレイアウトを見てください

                    `
          <div class="containerChildren">
                 <span class="descriter">...</span>
                //这个其实就是判断有没有选中,选中是打勾图片,不是是其他图片,不是checkebox,我就用input的chekbox
                 ${cuttentDate.checked == true ?
                        `<img  src = "./imgs/checked.svg" onclick = ${`"selectionFunc(${cuttentDate.id},${cuttentDate.checked})"`}  id=${inputClick} alt="选中按钮" class="Icon_class" >` :
                        `<img  src = "./imgs/unChecked.svg" onclick = ${`"selectionFunc(${cuttentDate.id},${cuttentDate.checked})"`}  id=${inputClick} alt="不选中按钮" class="Icon_class">`
                    }
         
            //获取群组名称
             <span id=${cuttentDate.id} contenteditable = ${cuttentDate["edit"]} class="editContainer" title=${cuttentDate.name}>${cuttentDate.name}</span>

              ${cuttentDate.edit == false ? "" : spanVal} //这个判断新增或删除,弹出确定按钮,我是不需要,我都让他显示
              
                //add(${cuttentDate.id}新增方法
              <img  src = "./imgs/add.svg"  alt="新增按钮" class="Icon_class" onclick = ${`"add(${cuttentDate.id})"`}>
                //remove(${cuttentDate.id})删除方法
              <img  src = "./imgs/remove.svg"  alt="删除按钮" class="Icon_class" onclick = ${`"remove(${cuttentDate.id})"`}>
             //判断还有没有子类,如果没有就结束,还有就继续循环,遍历,递归
            ${cuttentDate.children && cuttentDate.children.length > 0 ? getChildren(cuttentDate.children) : ""}
          </div >
           
        `

この種の動的フォーマットは自分で作成するため、判断の記述方法とネストされた判断の記述方法について推論を行う必要があります。

これによると、他に何を言う必要がありますか?最も簡単な方法は、whichメソッドを呼び出し、変更IDを渡してから、delete関数などのメソッドで受信して処理することです。

 // 删除数据
    function remove(val) { //val就是传过来的id,是子类id,不可能是根节点的,根节点没有删除
        let removeVal = function (data) { //该方法
            data.map(currentData => { //循环,删除,遍历的意思
                if (currentData.id == val) {
                    currentData.id = 9999; //如果要删除的群组就将它置为9999
                } else if (currentData.children.length > 0) {
                    removeVal(currentData.children);//删除的群组有子类,就顺便调用这个方法,把子类也删除了
                }
            })
        }
        removeVal(data);//把数据传过去
        container.innerHTML = getParent(data);//刷新页面
    }

コンテンツを配置する場所、グローバル変数は次のとおりです。

    const container = document.getElementById("container"); //把界面放在这个位置
    container.addEventListener("dblclick", dbClickFnc, false)
    container.innerHTML = getParent(data); //刷新页面

私は通常このように変更し、インターフェースwindow.shuaxin(mydata);を更新する必要があります。

function shuaxin(data){

      const container = document.getElementById("container");
      container.addEventListener("dblclick", dbClickFnc, false)
      container.innerHTML = getParent(data);
      // console.log("html:"+container.innerHTML);

    }

     // 源数据,跟作者一致的格式
      let mydata =
         [
              {
                  "GroupID": 0,
                  "GroupName":"根节点",
                  "ChildID":1,
                  "spread":true,
                  "tempChildInfo":[],
                  "childInfo":[]
              }
          ];

       
        const arrId = [];

    let isEditMode = false;//是否是编辑状态
    let edit = false;

何らかの方法でグローバル変数をバックエンドに送信するため。私の変更は非常に大きいので、後で投稿します!

 

おすすめ

転載: blog.csdn.net/bbs11007/article/details/109183570