js,html,css,vuejs手搓级联单选

javascript 复制代码
<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>级联选择器</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      #app {
        height: 700px;
      }
      .cascader-container {
        position: relative;
        display: inline-block;
      }
      .cascader-input {
        width: 250px;
        padding: 8px;
        border: 1px solid #ccc;
        border-radius: 4px;
        cursor: pointer;
      }
      .dropdown {
        position: absolute;
        top: 40px;
        left: 0;
        display: flex;
        border: 1px solid #ddd;
        background: white;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
      }
      .column {
        width: 150px;
        border-right: 1px solid #eee;
      }
      .column:last-child {
        border-right: none;
      }
      ul {
        list-style: none;
        padding: 5px;
      }
      li {
        display: flex;
        align-items: center;
        padding: 5px;
        cursor: pointer;
      }
      li:hover {
        background: #f5f5f5;
      }
      input[type="radio"] {
        margin-right: 8px;
      }
      .selected {
        color: #409eff;
        font-weight: bold;
      }
      .arrow {
        margin-left: auto;
      }
    </style>
  </head>
  <body>
    <div id="app" @click="hideDropdown">
      <div class="cascader-container" @click.stop>
        <input
          class="cascader-input"
          :value="selectedPath"
          readonly
          @click="toggleDropdown"
        />
        <div v-if="dropdownVisible" class="dropdown" @click.stop>
          <div
            v-for="(items, level) in visibleData"
            :key="level"
            class="column"
          >
            <ul>
              <li
                v-for="item in items"
                :key="item.value"
                @click.stop="toggleExpand(item, level)"
              >
                <input
                  type="radio"
                  name="cascader"
                  :value="item.value"
                  v-model="selectedValue"
                  @click.stop="selectItem(item)"
                />
                <span :class="{ selected: selectedValue === item.value }"
                  >{{ item.label }}</span
                >
                <span v-if="item.children" class="arrow">></span>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </div>

    <script>
      new Vue({
        el: "#app",
        data: {
          dropdownVisible: false,
          selectedValue: "",
          selectedPath: "请选择",
          options: [
            {
              value: "zhinan",
              label: "指南",
              children: [
                {
                  value: "shejiyuanze",
                  label: "设计原则",
                  children: [
                    {
                      value: "yizhi",
                      label: "一致",
                    },
                    {
                      value: "fankui",
                      label: "反馈",
                    },
                    {
                      value: "xiaolv",
                      label: "效率",
                    },
                    {
                      value: "kekong",
                      label: "可控",
                    },
                  ],
                },
                {
                  value: "daohang",
                  label: "导航",
                  children: [
                    {
                      value: "cexiangdaohang",
                      label: "侧向导航",
                    },
                    {
                      value: "dingbudaohang",
                      label: "顶部导航",
                    },
                  ],
                },
              ],
            },
            {
              value: "zujian",
              label: "组件",
              children: [
                {
                  value: "basic",
                  label: "Basic",
                  children: [
                    {
                      value: "layout",
                      label: "Layout 布局",
                    },
                    {
                      value: "color",
                      label: "Color 色彩",
                    },
                    {
                      value: "typography",
                      label: "Typography 字体",
                    },
                    {
                      value: "icon",
                      label: "Icon 图标",
                    },
                    {
                      value: "button",
                      label: "Button 按钮",
                    },
                  ],
                },
                {
                  value: "form",
                  label: "Form",
                  children: [
                    {
                      value: "radio",
                      label: "Radio 单选框",
                    },
                    {
                      value: "checkbox",
                      label: "Checkbox 多选框",
                    },
                    {
                      value: "input",
                      label: "Input 输入框",
                    },
                    {
                      value: "input-number",
                      label: "InputNumber 计数器",
                    },
                    {
                      value: "select",
                      label: "Select 选择器",
                    },
                    {
                      value: "cascader",
                      label: "Cascader 级联选择器",
                    },
                    {
                      value: "switch",
                      label: "Switch 开关",
                    },
                    {
                      value: "slider",
                      label: "Slider 滑块",
                    },
                    {
                      value: "time-picker",
                      label: "TimePicker 时间选择器",
                    },
                    {
                      value: "date-picker",
                      label: "DatePicker 日期选择器",
                    },
                    {
                      value: "datetime-picker",
                      label: "DateTimePicker 日期时间选择器",
                    },
                    {
                      value: "upload",
                      label: "Upload 上传",
                    },
                    {
                      value: "rate",
                      label: "Rate 评分",
                    },
                    {
                      value: "form",
                      label: "Form 表单",
                    },
                  ],
                },
                {
                  value: "data",
                  label: "Data",
                  children: [
                    {
                      value: "table",
                      label: "Table 表格",
                    },
                    {
                      value: "tag",
                      label: "Tag 标签",
                    },
                    {
                      value: "progress",
                      label: "Progress 进度条",
                    },
                    {
                      value: "tree",
                      label: "Tree 树形控件",
                    },
                    {
                      value: "pagination",
                      label: "Pagination 分页",
                    },
                    {
                      value: "badge",
                      label: "Badge 标记",
                    },
                  ],
                },
                {
                  value: "notice",
                  label: "Notice",
                  children: [
                    {
                      value: "alert",
                      label: "Alert 警告",
                    },
                    {
                      value: "loading",
                      label: "Loading 加载",
                    },
                    {
                      value: "message",
                      label: "Message 消息提示",
                    },
                    {
                      value: "message-box",
                      label: "MessageBox 弹框",
                    },
                    {
                      value: "notification",
                      label: "Notification 通知",
                    },
                  ],
                },
                {
                  value: "navigation",
                  label: "Navigation",
                  children: [
                    {
                      value: "menu",
                      label: "NavMenu 导航菜单",
                    },
                    {
                      value: "tabs",
                      label: "Tabs 标签页",
                    },
                    {
                      value: "breadcrumb",
                      label: "Breadcrumb 面包屑",
                    },
                    {
                      value: "dropdown",
                      label: "Dropdown 下拉菜单",
                    },
                    {
                      value: "steps",
                      label: "Steps 步骤条",
                    },
                  ],
                },
                {
                  value: "others",
                  label: "Others",
                  children: [
                    {
                      value: "dialog",
                      label: "Dialog 对话框",
                    },
                    {
                      value: "tooltip",
                      label: "Tooltip 文字提示",
                    },
                    {
                      value: "popover",
                      label: "Popover 弹出框",
                    },
                    {
                      value: "card",
                      label: "Card 卡片",
                    },
                    {
                      value: "carousel",
                      label: "Carousel 走马灯",
                    },
                    {
                      value: "collapse",
                      label: "Collapse 折叠面板",
                    },
                  ],
                },
              ],
            },
            {
              value: "ziyuan",
              label: "资源",
              children: [
                {
                  value: "axure",
                  label: "Axure Components",
                },
                {
                  value: "sketch",
                  label: "Sketch Templates",
                },
                {
                  value: "jiaohu",
                  label: "组件交互文档",
                },
              ],
            },
          ],
          expandedNodes: [],
        },
        computed: {
          visibleData() {
            let levels = [];
            let currentLevel = this.options;
            levels.push(currentLevel);
            for (let i = 0; i < this.expandedNodes.length; i++) {
              let found = currentLevel.find(
                (node) => node.value === this.expandedNodes[i]
              );
              if (found && found.children) {
                levels.push(found.children);
                currentLevel = found.children;
              } else {
                break;
              }
            }
            return levels;
          },
        },
        methods: {
          toggleDropdown() {
            this.dropdownVisible = !this.dropdownVisible;
          },
          hideDropdown() {
            this.dropdownVisible = false;
          },
          toggleExpand(item, level) {
            this.expandedNodes = this.expandedNodes.slice(0, level);
            if (item.children) {
              this.expandedNodes.push(item.value);
            }
          },
          selectItem(item) {
            this.selectedValue = item.value;
            this.selectedPath = this.getFullPath(item.value, this.options, "");
            this.dropdownVisible = false;
            console.log("this.selectedValue", this.selectedValue);
            console.log("this.selectedPath", this.selectedPath);
          },
          getFullPath(value, options, path) {
            for (let opt of options) {
              let newPath = path ? `${path} / ${opt.label}` : opt.label;
              if (opt.value === value) return newPath;
              
              if (opt.children) {
                let result = this.getFullPath(value, opt.children, newPath);
                if (result) return result;
              }
            }
            return "";
          },
        },
      });
    </script>
  </body>
</html>
相关推荐
blzlh2 分钟前
春招面试万字整理,全程拷打,干货满满(2)
前端·vue.js·面试
hollyhuang2 分钟前
div元素滚动,子元素出现跳动,怎么解决?
前端·css
崔璨8 分钟前
实现一个精简React -- 实现useEffect(10)
前端·react.js
Au_ust18 分钟前
React类的生命周期
前端·react.js·前端框架
Georgewu1 小时前
【HarmonyOS Next】鸿蒙中自定义弹框OpenCustomDialog、CustomDialog与DialogHub的区别详解
前端·华为·harmonyos
11在上班1 小时前
剖析initData在水合中的设计哲学
前端·设计模式
TitusTong1 小时前
使用 <think> 标签解析 DeepSeek 模型的推理过程
前端·ollama·deepseek
Hsuna1 小时前
一句配置让你的小程序自动适应Pad端
前端·javascript
curdcv_po1 小时前
Vue3移动电商实战 —— 外卖移动端轮播图实现
前端