使用缩进选项取消 <select> 标签的缩进

问题描述 投票:0回答:1

我有一棵树,作为嵌套字典实现,我需要想出一种方法让用户选择两个节点,其中一个必须是另一个的后代。

一个简单的下拉菜单可能会起作用,但我想缩进选项以清楚地传达哪个“子”选项来自哪个“父”选项。我认为通常这可以用

<optgroup>
来完成,但是 IINM 这些不能相互嵌套,我需要一个适用于任何任意深度的树的解决方案。

所以我做了一些挖掘,显然一种进行缩进的方法是在应该缩进的选项的标签上添加一堆

&nbsp;
。 (另请参阅thisthis)这就是我所做的:

let g_pLanguageTree = {
    "Name": "Indo-European",
    "Children": [
        {
            "Name": "Germanic",
            "Children": [
                {
                    "Name": "North Germanic",
                    "Children": [
                        {
                            "Name": "Norwegian",
                            "Children": []
                        },
                        {
                            "Name": "Swedish",
                            "Children": []
                        },
                        {
                            "Name": "Danish",
                            "Children": []
                        }
                    ]
                },
                {
                    "Name": "West Germanic",
                    "Children": [
                        {
                            "Name": "German",
                            "Children": []
                        },
                        {
                            "Name": "Dutch",
                            "Children": []
                        },
                        {
                            "Name": "English",
                            "Children": []
                        }
                    ]
                },
                {
                    "Name": "East Germanic",
                    "Children": [
                        {
                            "Name": "Gothic",
                            "Children": []
                        }
                    ]
                }
            ]
        },
        {
            "Name": "Italic",
            "Children": [
                {
                    "Name": "Umbrian",
                    "Children": []
                },
                {
                    "Name": "Oscan",
                    "Children": []
                },
                {
                    "Name": "Latin",
                    "Children": [
                        {
                            "Name": "Spanish",
                            "Children": []
                        },
                        {
                            "Name": "French",
                            "Children": []
                        },
                        {
                            "Name": "Italian",
                            "Children": []
                        },
                        {
                            "Name": "Portuguese",
                            "Children": []
                        },
                        {
                            "Name": "Romanian",
                            "Children": []
                        }
                    ]
                },
            ]           
        },
        {
            "Name": "Anatolian",
            "Children": [
                {
                    "Name": "Hittite",
                    "Children": []
                },
                {
                    "Name": "Luwian",
                    "Children": []
                }
            ]           
        },
        {
            "Name": "Armenian",
            "Children": []
        }
    ]
}

function CreateStageDropdown(pRootStage = g_pLanguageTree) {
    let eDropDown = document.createElement("select");
    document.getElementById("MainDiv").appendChild(eDropDown);
    let tOptions = CreateStageDropdown_Options(pRootStage, 0);
    for (let i = 0; i < tOptions.length; i++) {
        let eOption = document.createElement("option");
        eOption.label = tOptions[i];
        eOption.value = i;
        eDropDown.appendChild(eOption);
    }
    eDropDown.addEventListener("change", function(Event) {
        let sIn = eDropDown.value;
        let eSelected = eDropDown.querySelector("option[value = '"+sIn+"']");
        let sOut = tOptions[sIn].replaceAll(/\s*/g,"");
        eDropDown.label = sOut;
    });
    return [eDropDown, tOptions];
}

function CreateStageDropdown_Options(pStage, iNestingLayers) {
    let tOptions = [];
    
    tOptions.push("\u00A0\u00A0\u00A0\u00A0".repeat(iNestingLayers)+pStage.Name);
    let tChildren = pStage.Children;
    if (tChildren.length > 0) {
        for (let i = 0; i < tChildren.length; i++) {
            let pChild = tChildren[i];
            tOptions.push(CreateStageDropdown_Options(pChild, iNestingLayers + 1));
        }
    }
    tOptions = tOptions.flat();
    return tOptions;
}
<div id="MainDiv">
    <input type="button" value="Click to create dropdown" onclick="CreateStageDropdown()"/>
</div>
<div id="OtherDiv">
    <input type="button" value="Click to create dropdown (Just Germanic)" onclick="CreateStageDropdown(g_pLanguageTree.Children[0])"/>
</div>

它递归地遍历字典,每次必须在树中向下一层时,都会在选项名称的开头添加更多空格。

这种方法可行,但看起来确实很奇怪,当选择一个选项并关闭下拉列表时,框中显示的最终标签如此不一致地对齐。有时它向左对齐,有时稍微偏离中心,有时完全向右对齐。

所以我一直在尝试找到一种方法,在关闭下拉列表时从

select
元素本身的标签中删除所有不间断空格,并让它们 only 显示在
option 的标签中
当下拉菜单打开时显示。您可以看到我试图在事件侦听器中执行此操作,通过使用正则表达式将所有空白替换为空,但是呃...显然
select
没有
label
属性?

是否无法设置

select
元素的文本独立于已选择的
option
的标签?

javascript html select parent-child indentation
1个回答
0
投票

下拉菜单的实现依赖于浏览器和操作系统。不幸的是,没有足够的事件来描述您想要的操作,例如何时显示或隐藏选项。我得到的最接近的是

focus
blur
。我尝试用
mousedown
change
click
破解它,但最可靠的是等待用户
blur
后再更改值。

var oldValue = null

function CreateStageDropdown(pRootStage = g_pLanguageTree) {
  let eDropDown = document.createElement("select");
  document.getElementById("MainDiv").appendChild(eDropDown);
  let tOptions = CreateStageDropdown_Options(pRootStage, 0);
  for (let i = 0; i < tOptions.length; i++) {
    let eOption = document.createElement("option");
    eOption.label = tOptions[i];
    eOption.value = i;
    eDropDown.appendChild(eOption);
  }
  eDropDown.addEventListener("blur", function(Event) {
    let sIn = eDropDown.options[eDropDown.selectedIndex].label
    oldValue = sIn
    let sOut = sIn.replaceAll(/\s*/g, "");
    eDropDown.options[eDropDown.selectedIndex].label = sOut
  });

  eDropDown.addEventListener("change", function(Event) {
    //  eDropDown.blur()
  });


  eDropDown.addEventListener("focus", function(Event) {
    if (oldValue !== null) {
      eDropDown.options[eDropDown.selectedIndex].label = oldValue
      oldValue = null

    }
    //eDropDown.value = sOut;
  });
  return [eDropDown, tOptions];
}

function CreateStageDropdown_Options(pStage, iNestingLayers) {
  let tOptions = [];

  tOptions.push("\u00A0\u00A0\u00A0\u00A0".repeat(iNestingLayers) + pStage.Name);
  let tChildren = pStage.Children;
  if (tChildren.length > 0) {
    for (let i = 0; i < tChildren.length; i++) {
      let pChild = tChildren[i];
      tOptions.push(CreateStageDropdown_Options(pChild, iNestingLayers + 1));
    }
  }
  tOptions = tOptions.flat();
  return tOptions;
}

let g_pLanguageTree = {
  "Name": "Indo-European",
  "Children": [{
      "Name": "Germanic",
      "Children": [{
          "Name": "North Germanic",
          "Children": [{
              "Name": "Norwegian",
              "Children": []
            },
            {
              "Name": "Swedish",
              "Children": []
            },
            {
              "Name": "Danish",
              "Children": []
            }
          ]
        },
        {
          "Name": "West Germanic",
          "Children": [{
              "Name": "German",
              "Children": []
            },
            {
              "Name": "Dutch",
              "Children": []
            },
            {
              "Name": "English",
              "Children": []
            }
          ]
        },
        {
          "Name": "East Germanic",
          "Children": [{
            "Name": "Gothic",
            "Children": []
          }]
        }
      ]
    },
    {
      "Name": "Italic",
      "Children": [{
          "Name": "Umbrian",
          "Children": []
        },
        {
          "Name": "Oscan",
          "Children": []
        },
        {
          "Name": "Latin",
          "Children": [{
              "Name": "Spanish",
              "Children": []
            },
            {
              "Name": "French",
              "Children": []
            },
            {
              "Name": "Italian",
              "Children": []
            },
            {
              "Name": "Portuguese",
              "Children": []
            },
            {
              "Name": "Romanian",
              "Children": []
            }
          ]
        },
      ]
    },
    {
      "Name": "Anatolian",
      "Children": [{
          "Name": "Hittite",
          "Children": []
        },
        {
          "Name": "Luwian",
          "Children": []
        }
      ]
    },
    {
      "Name": "Armenian",
      "Children": []
    }
  ]
}



CreateStageDropdown()
<p>Select a sub item
</p>
<div id="MainDiv">
</div>
<p>and then</p>
<button>lose focus</button>

© www.soinside.com 2019 - 2024. All rights reserved.