Plain JS Cascading选择未知深度

问题描述 投票:8回答:2

想要进行通用的级联下拉,但递归很弱

该代码应该最终结束

  • 在做出选择时,可以选择一件物品 - 衣服或小工具
  • 选择时可选择Levis / Gucci或LG / Apple
  • 一个选择与Levis牛仔裤或夹克或Gucci鞋或礼服 - 选择时
  • 一件选用Levis牛仔裤尺码OR levis夹克尺码OR
  • 一款选择Gucci鞋码或Gucci连衣裙尺码

要么

  • 只需选择LG电视或手机或Apple Macbook或iPhone,即可选择
  • 一个选择LG电视尺寸或LG电话尺寸或
  • 一款选择Apple Macbook尺寸或Apple iPhone尺寸

当我实际递归时,我失去了思路 - 或者也许可以使用过滤?

我假设一个人可以制作一组路径,然后根据路径显示/隐藏

const selObject = {
  "-- Select Item --": {
    "Clothes": {
      "-- Select brands --": {
        "Levis": {
          "-- Select product --": {
            "Jeans": {
              "-- Select size --": [
                "38",
                "39",
                "40"
              ]
            },
            "Jackets": {
              "-- Select size --": [
                "41",
                "42",
                "43"
              ]
            }
          }
        }, // end Levis
        "Gucci": {
          "-- Select product --": {
            "Shoes": {
              "-- Select size --": [
                "45",
                "50",
                "55"
              ]
            },
            "Dresses": {
              "-- Select size --": [
                "8",
                "9",
                "10"
              ]
            }
          }
        } // end Gucci
      } // end brands  
    }, // End clothes
    "Gadgets": {
      "-- Select brands --": {
        "LG": {
          "-- Select product --": {
            "TVs": {
              "-- Select size --": [
                "38",
                "39",
                "40"
              ]
            },
            "Phones": {
              "-- Select size --": [
                "8",
                "9",
                "10"
              ]
            }
          }
        }, // end Levis
        "Apple": {
          "-- Select product --": {
            "Macbooks": {
              "-- Select size --": [
                "15",
                "17",
                "21"
              ]
            },
            "iPhones": {
              "-- Select size --": [
                "8",
                "9",
                "10"
              ]
            }
          }
        } // end Apple
      } // end brands
    } // end  Gadgets
  } // end items
} // end  

function createSel(obj) {
  Object.keys(obj).forEach(function(item) {
    if (typeof obj[item] == "object") {
      var list = obj[item];
      //console.log(item,typeof list);
      if (typeof list == "object") {
        if (list.length) {
          list.forEach(function(val) {
            console.log('<br/>'+val)
          })  
        }  
        else createSel(list)
      }
    } else {
      console.log("no", obj[item])
    }
  });
}
window.onload = function() {
  createSel(selObject)
}
<form name="myform" id="myForm">
  <div id="selContainer">
  </div>
</form>
javascript cascadingdropdown
2个回答
4
投票

在React中执行此操作会更容易。但对于一个简单的JS解决方案,下面可能是你的后续。

基本上我所做的就是使用递归来创建组件,并附加事件。

const selObject = {
  "-- Select Item --": {
    "Clothes": {
      "-- Select brands --": {
        "Levis": {
          "-- Select product --": {
            "Jeans": {
              "-- Select size --": [
                "38",
                "39",
                "40"
              ]
            },
            "Jackets": {
              "-- Select size --": [
                "41",
                "42",
                "43"
              ]
            }
          }
        }, // end Levis
        "Gucci": {
          "-- Select product --": {
            "Shoes": {
              "-- Select size --": [
                "45",
                "50",
                "55"
              ]
            },
            "Dresses": {
              "-- Select size --": [
                "8",
                "9",
                "10"
              ]
            }
          }
        } // end Gucci
      } // end brands  
    }, // End clothes
    "Gadgets": {
      "-- Select brands --": {
        "LG": {
          "-- Select product --": {
            "TVs": {
              "-- Select size --": [
                "38",
                "39",
                "40"
              ]
            },
            "Phones": {
              "-- Select size --": [
                "8",
                "9",
                "10"
              ]
            }
          }
        }, // end Levis
        "Apple": {
          "-- Select product --": {
            "Macbooks": {
              "-- Select size --": [
                "15",
                "17",
                "21"
              ]
            },
            "iPhones": {
              "-- Select size --": [
                "8",
                "9",
                "10"
              ]
            }
          }
        } // end Apple
      } // end brands
    } // end  Gadgets
  } // end items
} // end  


function fillDropdown(target, obj) {
  const sel = document.createElement("select");
  const sub = document.createElement("div");
  if (typeof obj !== "object") {
    sub.innerHTML = "<p>Thank you for your selection</p>";
    target.appendChild(sub);
    return;
  }
  target.appendChild(sel);
  target.appendChild(sub);
  const [title, value] = Object.entries(obj)[0];
  //add our title option
  const option1 = document.createElement("option");
  option1.innerText = title;
  sel.appendChild(option1);
  //now add the sub items
  const items = Object.entries(value);
  items.forEach(([k, v]) => {
    const option = document.createElement('option');
    option.innerText = k;
    sel.appendChild(option);
  });
  sel.addEventListener("change", () => {
    sub.innerHTML = "";
    if (sel.selectedIndex > 0) {
      const i = items[sel.selectedIndex - 1];    
      fillDropdown(sub, i[1]);
    }
  }); 
}


window.onload = function() {
  //createSel(selObject);
  fillDropdown(
    document.querySelector('#selContainer'),
    selObject
  );
}
select {
  display: block;
  width: 100%;
  padding: 10px;
}
<form name="myform" id="myForm">
  <div id="selContainer">
  </div>
</form>

1
投票

这里有一些您可能想要考虑的其他选项:

使用OptGroup:

const selObject = { "-- Select Item --": { Clothes: { "-- Select brands --": { Levis: { "-- Select product --": { Jeans: { "-- Select size --": ["38", "39", "40"] }, Jackets: { "-- Select size --": ["41", "42", "43"] } } }, Gucci: { "-- Select product --": { Shoes: { "-- Select size --": ["45", "50", "55"] }, Dresses: { "-- Select size --": ["8", "9", "10"] } } } } }, Gadgets: { "-- Select brands --": { LG: { "-- Select product --": { TVs: { "-- Select size --": ["38", "39", "40"] }, Phones: { "-- Select size --": ["8", "9", "10"] } } }, Apple: { "-- Select product --": { Macbooks: { "-- Select size --": ["15", "17", "21"] }, iPhones: { "-- Select size --": ["8", "9", "10"] } } } } } } };

const generateDropDown = (obj, indent) => {
  const spaces = Array(indent).fill('&nbsp;').join('');
  
  if (Array.isArray(Object.values(obj)[0])) {
    return Object.values(obj)[0].map(e => "<option>" + spaces + e + "</option>").join('');
  } else {
    return Object.values(obj).map(brand => {
      return Object.keys(brand).map(product => {
        //?
        return `<optgroup label="${spaces + product}"> ${generateDropDown(brand[product], indent + 4)} </optgroup>`;
      }).join('');
    });
  }
};


const list = generateDropDown(selObject, 0).join(' ');

document.querySelector('#dropDown').innerHTML = list;
<select id="dropDown">

</select>

使用ul :(更加灵活的样式)

const selObject = { "-- Select Item --": { Clothes: { "-- Select brands --": { Levis: { "-- Select product --": { Jeans: { "-- Select size --": ["38", "39", "40"] }, Jackets: { "-- Select size --": ["41", "42", "43"] } } }, Gucci: { "-- Select product --": { Shoes: { "-- Select size --": ["45", "50", "55"] }, Dresses: { "-- Select size --": ["8", "9", "10"] } } } } }, Gadgets: { "-- Select brands --": { LG: { "-- Select product --": { TVs: { "-- Select size --": ["38", "39", "40"] }, Phones: { "-- Select size --": ["8", "9", "10"] } } }, Apple: { "-- Select product --": { Macbooks: { "-- Select size --": ["15", "17", "21"] }, iPhones: { "-- Select size --": ["8", "9", "10"] } } } } } } };

const generateDropDown = (obj, indent) => {  
  const values = Object.values(obj);
  if (Array.isArray(values[0])) {
    return values[0].map(e => `<li class="child">${e} </li>`).join(' ');
  } else {
    return values.map(brand => {
      return Object.keys(brand).map(product => {        
        return `<ul class="parent"> <li class="title">${product}</li> ${generateDropDown(brand[product], indent + 2)} </ul>`;
      }).join(' ');
    });
  }
};

const list = generateDropDown(selObject, 0).join(' ');

document.querySelector('#dropDown').innerHTML = list;

[...document.querySelectorAll('ul,li')].forEach(e => {	
	e.addEventListener('click', ev => {
  	ev.cancelBubble = true;    
    ev.target.classList.toggle('open');
  	// console.log(ev.target.innerText)
    // do some stuff when the element is clicked.    
  })
})
ul{
  padding: 0;
  margin: 0;
  list-style-type: none;
}

.parent, .child{
  padding-left: 15px;  
  display: none;
  cursor: pointer;
}

#dropDown > .parent {
  padding-left: 0;
  display: block;
  
}

.open ~ .parent{
  opacity: 1;
  display: block;
}

.open ~ .child{
  opacity: 1;
  display: block;
}

.title{
  font-weight: bold;
}

.title.open{
  color: red;
}
<div id="dropDown">

</div>
© www.soinside.com 2019 - 2024. All rights reserved.