You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
91 lines
2.9 KiB
91 lines
2.9 KiB
import "./common.js";
|
|
//#region js/contact.js
|
|
/**
|
|
* 自定义下拉组件
|
|
* 将原生 <select> 替换为可自定义样式的下拉
|
|
*/
|
|
function initCustomSelects() {
|
|
document.querySelectorAll(".c-field__select").forEach((native) => {
|
|
if (native.dataset.customized) return;
|
|
native.dataset.customized = "true";
|
|
native.classList.add("c-custom-select__native");
|
|
native.tabIndex = -1;
|
|
const wrapper = document.createElement("div");
|
|
native.parentNode.insertBefore(wrapper, native);
|
|
wrapper.appendChild(native);
|
|
wrapper.className = "c-custom-select";
|
|
const trigger = document.createElement("button");
|
|
trigger.type = "button";
|
|
trigger.className = "c-custom-select__trigger";
|
|
trigger.setAttribute("aria-haspopup", "listbox");
|
|
trigger.setAttribute("aria-expanded", "false");
|
|
wrapper.appendChild(trigger);
|
|
const dropdown = document.createElement("div");
|
|
dropdown.className = "c-custom-select__dropdown";
|
|
dropdown.setAttribute("role", "listbox");
|
|
wrapper.appendChild(dropdown);
|
|
function renderOptions() {
|
|
dropdown.innerHTML = "";
|
|
Array.from(native.options).forEach((opt, i) => {
|
|
if (opt.disabled) return;
|
|
const btn = document.createElement("button");
|
|
btn.type = "button";
|
|
btn.className = "c-custom-select__option";
|
|
btn.setAttribute("role", "option");
|
|
btn.dataset.value = opt.value;
|
|
btn.textContent = opt.textContent;
|
|
if (opt.selected && opt.value) btn.classList.add("is-active");
|
|
btn.addEventListener("click", () => selectOption(i));
|
|
dropdown.appendChild(btn);
|
|
});
|
|
}
|
|
function updateTrigger() {
|
|
const sel = native.selectedIndex;
|
|
const opt = native.options[sel];
|
|
trigger.textContent = opt ? opt.textContent : "";
|
|
trigger.classList.toggle("is-placeholder", !opt || opt.disabled);
|
|
dropdown.querySelectorAll(".c-custom-select__option").forEach((btn) => {
|
|
btn.classList.toggle("is-active", btn.dataset.value === native.value);
|
|
});
|
|
}
|
|
function selectOption(index) {
|
|
native.selectedIndex = index;
|
|
native.dispatchEvent(new Event("change", { bubbles: true }));
|
|
updateTrigger();
|
|
close();
|
|
}
|
|
function open() {
|
|
renderOptions();
|
|
dropdown.classList.add("is-visible");
|
|
trigger.classList.add("is-open");
|
|
trigger.setAttribute("aria-expanded", "true");
|
|
}
|
|
function close() {
|
|
dropdown.classList.remove("is-visible");
|
|
trigger.classList.remove("is-open");
|
|
trigger.setAttribute("aria-expanded", "false");
|
|
}
|
|
function toggle() {
|
|
dropdown.classList.contains("is-visible") ? close() : open();
|
|
}
|
|
trigger.addEventListener("click", toggle);
|
|
document.addEventListener("click", (e) => {
|
|
if (!wrapper.contains(e.target)) close();
|
|
});
|
|
wrapper.addEventListener("keydown", (e) => {
|
|
if (e.key === "Escape") {
|
|
close();
|
|
trigger.focus();
|
|
}
|
|
if (e.key === "Enter" || e.key === " ") {
|
|
e.preventDefault();
|
|
toggle();
|
|
}
|
|
});
|
|
updateTrigger();
|
|
});
|
|
}
|
|
$(function() {
|
|
initCustomSelects();
|
|
});
|
|
//#endregion
|