@hotwired/stimulus 和 TailwindCSS 实现多级嵌套级联选择器
首先,我们需要安装 @hotwired/stimulus 和 tailwindcss:
npm install @hotwired/stimulus tailwindcss
接着,在 HTML 文件中引入 Stimulus 和 tailwindcss:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Stimulus Cascader Example</title>
<link rel="stylesheet" href="https://unpkg.com/tailwindcss/dist/tailwind.min.css">
</head>
<body>
<div class="p-4">
<div class="relative inline-block">
<button type="button" class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" data-controller="cascader">
<span data-cascader-target="label">请选择</span>
<svg class="ml-2 -mr-0.5 h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M6.293 6.707a1 1 0 011.414 0L10 8.586l2.293-2.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
<div class="absolute z-10 mt-2 w-64 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 overflow-hidden" data-cascader-target="menu" data-action="click->cascader#toggle">
<ul class="py-1">
<li>
<button type="button" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cascader-target="option" data-cascader-value="1">选项1</button>
<ul class="py-1 hidden" data-cascader-target="submenu">
<li>
<button type="button" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cascader-target="option" data-cascader-value="1-1">选项1-1</button>
</li>
<li>
<button type="button" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cascader-target="option" data-cascader-value="1-2">选项1-2</button>
</li>
</ul>
</li>
<li>
<button type="button" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cascader-target="option" data-cascader-value="2">选项2</button>
<ul class="py-1 hidden" data-cascader-target="submenu">
<li>
<button type="button" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cascader-target="option" data-cascader-value="2-1">选项2-1</button>
</li>
<li>
<button type="button" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cascader-target="option" data-cascader-value="2-2">选项2-2</button>
<ul class="py-1 hidden" data-cascader-target="submenu">
<li>
<button type="button" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cascader-target="option" data-cascader-value="2-2-1">选项2-2-1</button>
</li>
<li>
<button type="button" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cascader-target="option" data-cascader-value="2-2-2">选项2-2-2</button>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<script src="https://unpkg.com/@hotwired/stimulus"></script>
<script>
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["menu", "option", "label"];
connect() {
this.selected = [];
this.updateLabel();
this.menuTargets.forEach((menu) => {
menu.addEventListener("click", (event) => {
event.stopPropagation();
});
});
document.addEventListener("click", (event) => {
this.hide();
});
}
toggle(event) {
event.stopPropagation();
this.menuTargets.forEach((menu) => {
menu.classList.toggle("hidden");
});
}
hide() {
this.menuTargets.forEach((menu) => {
menu.classList.add("hidden");
});
}
selectOption(event) {
event.stopPropagation();
const option = event.target.closest("[data-cascader-value]");
if (!option) return;
const value = option.getAttribute("data-cascader-value");
const level = value.split("-").length;
this.selected[level - 1] = value;
this.selected = this.selected.slice(0, level);
this.updateLabel();
const submenu = option.querySelector("[data-cascader-target='submenu']");
if (submenu) {
submenu.classList.remove("hidden");
}
}
updateLabel() {
const labels = this.optionTargets
.filter((option) => {
const value = option.getAttribute("data-cascader-value");
return this.selected.indexOf(value) !== -1;
})
.map((option) => option.textContent.trim());
this.labelTarget.textContent = labels.length ? labels.join(" / ") : "请选择";
}
}
</script>
</body>
</html>
这里我们使用了 Stimulus 的控制器来实现级联选择器。我们首先定义了两个 targets,分别是菜单和选项,然后通过 connect 方法来初始化一些状态,如 selected 数组用于记录当前选中的值,updateLabel 方法用于更新显示的标签内容等。
我们使用了 tailwindcss 来快速构建样式,包括按钮的样式、下拉菜单的样式等。我们在按钮上绑定了 click 事件,并在控制器中处理了这个事件。我们在菜单中嵌套了 ul 和 li 元素,并使用 data-cascader-value 属性来记录选项的值。我们在选项上绑定了 click 事件,并在控制器中处理了这个事件。我们在选项中嵌套了 ul 和 li 元素,并使用 data-cascader-target 属性来指定子菜单。当用户选择一个选项时,我们会更新 selected 数组,并更新显示的标签内容。如果选项有子菜单,我们会展开子菜单。
这个例子演示了如何使用 @hotwired/stimulus 和 tailwindcss 来实现一个简单的级联选择器,类似于 element-plus 中的 Cascader 组件。你可以根据自己的需求进行修改和扩展。
原文地址: https://www.cveoy.top/t/topic/mFAZ 著作权归作者所有。请勿转载和采集!