首先,我们需要安装 @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 组件。你可以根据自己的需求进行修改和扩展。

@hotwired/stimulus 和 TailwindCSS 实现多级嵌套级联选择器

原文地址: https://www.cveoy.top/t/topic/mFAZ 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录