首先,需要安装 @hotwired/stimulus 和 @hotwired/turbo-rails。

然后,按照以下步骤实现多级Cascader级联选择器:

  1. 创建一个 Stimulus 控制器,命名为 CascaderController。

  2. 在 CascaderController 控制器中,定义一个 initialize 方法,用于初始化 Cascader。

  3. 在 initialize 方法中,获取 Cascader 的数据源,并将数据源保存在控制器的属性中。

  4. 在 initialize 方法中,获取 Cascader 的初始值,并将初始值保存在控制器的属性中。

  5. 在 initialize 方法中,根据数据源和初始值,生成 Cascader 的 HTML。

  6. 在 Cascader 的 HTML 中,定义多个 select 元素,用于选择 Cascader 的不同级别。

  7. 在 Cascader 的 HTML 中,为每个 select 元素添加 change 事件监听器,用于更新 Cascader 的值。

  8. 在 CascaderController 控制器中,定义一个 update 方法,用于更新 Cascader 的值。

  9. 在 update 方法中,根据当前选择的值,更新 Cascader 的下一级别的选项。

  10. 在 CascaderController 控制器中,定义一个 submit 方法,用于提交 Cascader 的值。

  11. 在 submit 方法中,将 Cascader 的值提交到服务器端。

  12. 在服务器端,根据 Cascader 的值,返回相应的数据。

  13. 在服务器端,将返回的数据转换为 JSON 格式,并将其返回给客户端。

  14. 在客户端,根据返回的数据,更新 Cascader 的下一级别的选项。

  15. 在客户端,重复步骤 10 到步骤 14,直到 Cascader 的值被提交到服务器端。

下面是一个示例 CascaderController 控制器的代码:

import { Controller } from "@hotwired/stimulus";
import { Turbo } from "@hotwired/turbo-rails";

export default class extends Controller {
  static targets = ["select"];

  initialize() {
    this.data = JSON.parse(this.element.dataset.data);
    this.value = JSON.parse(this.element.dataset.value);

    let html = "";
    let values = this.value;

    for (let i = 0; i < this.data.length; i++) {
      let options = "";
      let selected = values[i] || "";

      for (let j = 0; j < this.data[i].length; j++) {
        let option = this.data[i][j];
        let text = option.text;
        let value = option.value;
        let attrs = option.attrs || {};

        attrs.value = value;

        if (value == selected) {
          attrs.selected = "selected";
        }

        let attrsString = Object.keys(attrs)
          .map(key => `${key}="${attrs[key]}"`)
          .join(" ");

        options += `<option ${attrsString}>${text}</option>`;
      }

      html += `<select data-cascader-target="select" data-cascader-level="${i}">${options}</select>`;
    }

    this.element.innerHTML = html;
  }

  update(event) {
    let select = event.target;
    let level = parseInt(select.dataset.cascaderLevel);
    let value = select.value;

    this.value[level] = value;

    for (let i = level + 1; i < this.selectTargets.length; i++) {
      let select = this.selectTargets[i];
      let options = Array.from(select.options);

      options.forEach(option => {
        let attrs = option.dataset.attrs ? JSON.parse(option.dataset.attrs) : {};
        let disabled = attrs.disabled;

        if (disabled) {
          option.disabled = true;
        } else {
          option.disabled = false;
          option.selected = false;
        }
      });
    }

    if (value) {
      let url = this.element.dataset.url.replace(":value", JSON.stringify(this.value));

      Turbo.fetch(url).then(response => {
        return response.json();
      }).then(data => {
        let options = Array.from(select.options);

        options.forEach(option => {
          let attrs = option.dataset.attrs ? JSON.parse(option.dataset.attrs) : {};
          let value = option.value;
          let disabled = attrs.disabled;

          if (data[value]) {
            let text = data[value].text || "";
            let attrs = data[value].attrs || {};

            if (disabled) {
              option.disabled = false;
            }

            option.text = text;

            attrs.value = value;

            if (attrs.selected) {
              option.selected = true;
            }

            option.dataset.attrs = JSON.stringify(attrs);
          } else {
            option.disabled = true;
          }
        });
      });
    } else {
      for (let i = level + 1; i < this.selectTargets.length; i++) {
        let select = this.selectTargets[i];
        let options = Array.from(select.options);

        options.forEach(option => {
          let attrs = option.dataset.attrs ? JSON.parse(option.dataset.attrs) : {};
          let value = option.value;
          let disabled = attrs.disabled;

          if (!disabled) {
            option.disabled = true;
          }
        });
      }
    }
  }

  submit(event) {
    event.preventDefault();

    let form = this.element.closest("form");
    let input = document.createElement("input");

    input.setAttribute("type", "hidden");
    input.setAttribute("name", this.element.getAttribute("name"));
    input.setAttribute("value", JSON.stringify(this.value));

    form.appendChild(input);

    Turbo.visit(form.action, { method: form.method, body: new FormData(form) });
  }
}

在这个示例中,我们使用了 @hotwired/stimulus 和 @hotwired/turbo-rails 的一些特性,比如数据属性、目标、事件监听器、Turbo.fetch 等。我们还定义了一个 update 方法和一个 submit 方法,用于更新 Cascader 的值和提交 Cascader 的值。在 update 方法中,我们使用了 JSON.parse 和 JSON.stringify 方法,将 Cascader 的值转换为 JSON 格式,并将 JSON 格式转换为 Cascader 的值。在 submit 方法中,我们使用了 document.createElement、input.setAttribute 和 form.appendChild 方法,创建一个隐藏的 input 元素,并将 Cascader 的值作为其值提交到服务器端。

hotwiredstimulus 和 hotwiredturbo-rails 实现像element-plus 一样的多级Cascader 级联选择器

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

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