el-cascader 自动展开第一项或者某一项的下一级

这篇博客介绍了如何在Vue中使用Element UI的级联选择器组件(Cascader),并展示了一个示例,实现了特定的交互逻辑:当选择项只有一个时自动展开下一级,以及在第一级和最后一级时由用户手动选择。同时,展示了`visibleChange`、`lazyLoad`等关键属性和方法的用法,以及监听`showText`变化以更新输入框显示内容的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

想要实现的效果 当选择项只有一个的时候 自动展开下一级 最后一级和第一级的时候 用户自己点击 其他时候自动展开
看到源码是这样操作的 大家有更好的可以交流啊

请添加图片描述

<template>
  <el-cascader
    ref="cascader"
    v-model="path"
    placeholder="请选择关联项目"
    :props="props"
    :disabled="disabled"
    @visible-change="visibleChange"
  />
</template>

<script lang="ts">
import Vue from 'vue';
import { Component, Prop, Ref, Watch } from 'vue-property-decorator';
import FormBase from '@/components/form/FormBase';
import Fetch from '@/utils/fetch';
import type { Cascader } from 'element-ui';

@Component
export default class RelationItemPath extends FormBase<string> {
  @Prop({
    type: String,
    required: false,
    default: ''
  })
  private requestKey !: string;

  @Prop({
    type: Boolean,
    required: false,
    default: false
  })
  private showText !: boolean;

  @Prop({
    type: String,
    required: false,
    default: ''
  })
  private inputText !: string;

  @Prop({
    type: Boolean,
    required: false,
    default: false
  })
  private disabled !: boolean;

  @Ref()
  private readonly cascader !: Cascader

  private recordText=false; // 【修改的时候】用来判断路径改没改变  没改变传入的inputText,改变了新的选择的value

  private get path (): string {
    if (!this.value) {
      return '';
    }
    this.$refs.cascader && this.$emit('change', (this.$refs.cascader as any).inputValue);
    return this.value;
  }

  private set path (val) {
    const value = val;
    this.$emit('update:value', value);
    this.$emit('input', value);
  }

  private selectPath: string[] = [];
  private props = {
    lazy: true,
    value: 'value',
    label: 'label',
    emitPath: false, // 只返回最后一个节点
    lazyLoad: (node: any, resolve: any) => {
      const { level, pathNodes } = node;
      this.selectPath = [];
      // if (level === 0) {
      //   resolve([]);
      //   return;
      // }
      // if (level === 1) {
      //   this.dataOptions = this.dataPathOptions;
      // }
      if (pathNodes && pathNodes.length) {
        pathNodes.forEach((item: object, index: number) => {
          const value = pathNodes[index] ? pathNodes[index].value : '';
          this.selectPath.push(value);
        });
      }
      Fetch.get(`/api/project_info?application=${this.requestKey}&query=${this.selectPath.join('/')}`, {}, false).then(async response => {
        const nodes = response.data.map((item: any) => ({
          label: item.company_name || item.scan_type || item.name || item.train_type || item.parse_name,
          value: item.company_name || item.ID || item.name || item.train_type || item.parse_name,
          leaf: node.level >= 3
        }));
        resolve(Array.from(new Set(nodes)));
        if(response.data.length === 1 && level !== 3 && level !== 0 ){ // 当只有一级 自动展开下一级 后台固定关联项目只有四级 最后一级 用户自己选择
          await this.$nextTick()
          const nextMenu = (this.$refs.cascader as any).panel.$refs.menu[level]
          if (nextMenu) {
            const firstNode = nextMenu.$el.querySelector('.el-cascader-node[tabindex="-1"]');
            firstNode.focus();
            firstNode.click();
          }
        }
      });
    }
  };

  private visibleChange (visible: boolean) {
    console.log("visibleChange",this.path)
    const cascader = this.$refs.cascader as any;
    if (this.showText && !this.recordText) {
      cascader.inputValue = this.inputText;
      cascader.presentText = this.inputText;
    }
  }

  @Watch('showText', { immediate: true })
  private async onTextChange () {
    await this.$nextTick();
    const cascader = this.$refs.cascader as any;
    if (cascader && this.showText) {
      cascader.inputValue = this.inputText;
    }
  }

  @Watch('path')
  private async onPathChange () {
    await this.$nextTick();
    if (this.showText && (this.$refs.cascader as any).inputValue !== this.inputText) {
      this.recordText = true;
    }
  }
}
</script>

<style lang="scss" scoped>
@import '~@/components/input/input.scss';
</style>

<think>嗯,用户在使用element-plus的el-cascader组件时遇到了问题,想要只展示一级菜单。首先,我需要理解他的需求。他可能有一个级联选择器,但希望默认只显示第一级菜单,而不是展开所有层级。或者,用户希望在选择时只显示当前层级,而不是同时展示所有子级选项。这可能涉及到组件的配置或数据结构的处理。 根据用户提供的引用内容,尤其是引用[2]中提到通过设置props属性和绑定特定的数据格式来实现回显。比如,使用checkStrictly可以开启单选模式,允许单独选择任意一级。但用户的问题是关于显示层级,可能需要控制显示的层级数。 首先,我应该检查el-cascader的props配置。默认情况下,el-cascader会显示所有层级的选项,但用户可能希望只显示一级。这时可能需要设置props的expandTrigger属性,或者控制options的数据结构,只提供一级数据。不过,这可能不符合级联选择器的设计初衷,因为级联选择器通常用于多层级联选择。 另一种可能性是用户希望即使数据有子级,也只显示第一级,而子级在点击后再加载。这时候可能需要动态加载数据,即懒加载。引用[1]中提到了动态数据懒加载,所以可能需要结合lazy属性和相应的加载方法,但用户的问题是关于显示,而不是数据加载。 用户提供的引用[3]中提到开启单选模式后的问题,可能相关。如果设置props的checkStrictly为true,允许选择任意一级,但显示上可能仍然会展示所有层级。这时候可能需要通过CSS来控制显示的层级,比如隐藏子级菜单。 不过,用户的问题明确是“只展示一级菜单”,可能希望初始状态下只显示一级,点击后才展开一级。但el-cascader默认是点击父级后展开子级,所以这可能已经是默认行为。但用户可能遇到的情况是数据中存在多级,但希望只显示第一级,而隐藏其他层级。这可能需要调整数据结构,只传递一级数据,但这可能不符合级联选择器的使用场景。 或者,用户可能希望在选择后,输入框中只显示最后一级或第一级的标签,而不是完整路径。这时候可以通过设置show-all-levels属性为false,但这影响的是输入框中的显示,而不是菜单层级。 结合引用[2]中的示例,用户可能需要设置props的value、label、children字段,确保数据结构正确。如果数据中的子级没有被正确加载,可能导致显示问题。比如,如果children字段为空数组,el-cascader可能不会显示下级菜单,从而只展示一级。 因此,解决方案可能包括以下几点: 1. 确保options数据中每个节点只有一级,子级为空或未定义。 2. 设置props配置,指定正确的value、label、children字段。 3. 使用CSS隐藏下级菜单的显示,但这可能影响交互。 4. 结合lazy加载,但仅在需要时加载子级,初始只显示一级。 可能的示例代码是设置options为一级数据,不包含children,或者设置children为空数组。同时,在props中配置checkStrictly为true,允许选择一级节点。 需要验证这种配置是否有效,比如: ```vue <el-cascader :props="{ checkStrictly: true }" :options="options" /> ``` 其中options结构为: options: [ { value: '1', label: '一级菜单' }, // 没有children字段或children为空数组 ] ``` 这样可能只显示一级菜单,无法展开下级,因为不存在子节点。这可能是用户想要的只展示一级的效果。 总结,解决方案是确保数据中只有一级节点,并正确配置props,可能还需要调整样式或交互方式。需要提供示例代码和配置说明,帮助用户实现需求。</think>### el-cascader仅展示一级菜单解决方案 #### 问题分析 el-cascader组件默认根据`options`数据结构的层级关系逐级展开。若需仅展示一级菜单,可通过以下两种方式实现: 1. **数据控制**:限制数据仅包含一级节点(不包含子节点) 2. **交互控制**:通过CSS隐藏下级菜单或禁用展开行为 --- #### 方案1:通过数据控制 直接提供单层数据结构,不包含`children`字段或设置`children: []` ```vue <template> <el-cascader :options="flatOptions" :props="defaultProps"/> </template> <script setup> const flatOptions = [ { value: 'menu1', label: '一级菜单A' }, { value: 'menu2', label: '一级菜单B' }, // 无children字段或children为空数组 ]; const defaultProps = { value: 'value', label: 'label', children: 'children' // 无需修改,但数据中无子级 }; </script> ``` --- #### 方案2:通过CSS隐藏下级面板 若仍需保留层级数据但隐藏下级,可通过样式覆盖实现: ```css /* 隐藏二级及以下面板 */ .el-cascader-menu:nth-child(n+2) { display: none !important; } ``` --- #### 方案3:动态加载空子级(兼容懒加载模式) 若需兼容`lazy`模式,可在加载时返回空子节点: ```vue <template> <el-cascader :props="lazyProps" lazy/> </template> <script setup> const lazyProps = { lazy: true, async lazyLoad(node, resolve) { // 仅一级节点有数据,子级返回空 if (node.level === 0) { resolve([{ value: '1', label: '一级菜单' }]); } else { resolve([]); } } }; </script> ``` --- #### 效果验证 - **输入框**:仅显示选中项的标签(若需要显示完整路径,需设置`show-all-levels: false`[^2]) - **交互**:点击菜单项后不会展开下级(因无子节点或子级被隐藏) ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值