问题描述:

需求是需要一个级联选择框,选择框有一定的高度,当选项比较长的时候,回显数据可以在选择框中不被隐藏,换行显示。el-cascader组件如下,满足不了需求,采用封装组件的方法来实现。
在这里插入图片描述

改后效果:

在这里插入图片描述
回显数据效果:
在这里插入图片描述

代码如下:

1、自定义组件CascaderTextarea.vue

<template>
    <div class="cascader-textarea-wrapper">
      <!-- 隐藏原生输入框的级联选择器 -->
      <el-cascader
        v-model="materialName"
        :options="options"
        :props="props"
        @change="handleChange"
        ref="cascaderRef"
        class="hidden-cascader"
      />
  
      <!-- 自定义文本区域 -->
      <textarea
        v-model="materialName"
        class="custom-textarea"
        placeholder="请选择"
        @focus="handleFocus"
        @click="handleClick"
        @input="handleSearch"
        rows="3"
      ></textarea>
    </div>
  </template>
  
  <script>
  export default {
    model: {
        prop: 'materialName',
        event: 'change'
    },
    props: {
        materialName: {
            type: String,
            default: ''
        },
      // 接收父组件传递的选项数据
      options: {
        type: Array,
        required: true
      },
      // 级联选择器配置项(可选)
      cascaderProps: {
        type: Object,
        default: () => ({})
      }
    },
    data() {
      return {
        selectedValue: [],       // 存储实际选择的路径值
        displayText: '',         // 文本区域显示的内容
        props: {
          expandTrigger: 'hover',
          emitPath: true,        // 返回完整路径
          ...this.cascaderProps  // 合并父组件传递的配置
        },
        filteredOptions: [],
        optionsCopy:[],
      };
    },
    methods: {
      handleSearch() {
        
        if(this.materialName==''){
          this.$emit('change', this.materialName)
          this.options=this.optionsCopy;
        }
       
      if (!this.materialName) {
        this.filteredOptions = [];
        return;
      }
      
      this.options = this.flattenOptions(this.options)
        .filter(option => 
          option.label.includes(this.materialName)
        );
    },
    flattenOptions(options, parent = null) {
      return options.reduce((acc, option) => {
        const flatOption = {
          ...option,
          parent
        };
        
        if (option.children) {
          return [
            ...acc,
            flatOption,
            ...this.flattenOptions(option.children, option)
          ];
        }
        
        return [...acc, flatOption];
      }, []);
    },
     
      // 处理值变化(同步显示文本)
      handleChange(value) {
        if (!value || value.length === 0) {
          this.displayText = '';
          return;
        }
        
        // 获取选中节点的标签路径
        const node = this.$refs.cascaderRef.getCheckedNodes()[0];
        if (node) {
          this.displayText = node.pathLabels[ node.pathLabels.length - 1];
        }
        this.$emit('change', this.displayText)
      },
  
      // 聚焦时展开下拉框
      handleFocus() {
        if(this.optionsCopy.length==0){
          var objStr= JSON.stringify(this.options);
          this.optionsCopy=JSON.parse(objStr);

        }
        this.$refs.cascaderRef.toggleDropDownVisible(true);
      },
  
      // 点击时展开下拉框
      handleClick() {
        if(this.optionsCopy.length==0){
          var objStr= JSON.stringify(this.options);
          this.optionsCopy=JSON.parse(objStr);

        }
        this.$refs.cascaderRef.toggleDropDownVisible(true);
      },
    
    },
   
  };
  </script>
  
  <style scoped>
  .cascader-textarea-wrapper {
    position: relative;
  }
  
  /* 隐藏原生输入框 */
  .hidden-cascader {
    position: absolute;
    opacity: 0;
    pointer-events: none;
  }
  
  /* 自定义文本区域样式 */
  .custom-textarea {
    width: 100%;
    padding: 8px 15px;
    border: 1px solid #dcdfe6;
    border-radius: 4px;
    resize: vertical;
    font-family: inherit;
    font-size: 14px;
    transition: border-color 0.2s;
    min-height: 80px;
    height: 200px;
    text-align: center;
  }
  
  .custom-textarea:focus {
    outline: none;
    border-color: #409eff;
  }
  </style>

2、测试页面

<template>
  <div>
    <div class="container">
      <cascader-textarea 
        :options="cascaderOptions"
        :cascader-props="{ label: 'name', value: 'value' }"
        v-model="materialName"
      />
    </div>
  </div>
</template>
  
<script>
import CascaderTextarea from './CascaderTextarea.vue';
  
  export default {
    components: { CascaderTextarea },
    data() {
      return {
        materialName:'五月五,粽叶香,愿您的生活如糯米般甜糯,如红枣般红火!端午安康,岁岁平安,百事‘粽’顺,幸福‘粽’在身边',
        cascaderOptions: [
          {
            value: 1,
            name: '东南',
            children: [
              { value: 11, name: '五月五,粽叶香,愿您的生活如糯米般甜糯,如红枣般红火!端午安康,岁岁平安,百事‘粽’顺,幸福‘粽’在身边' },
              { value: 12, name: '艾草青青挂门楣,龙舟竞渡逐浪飞。愿君端午享安康,吉祥如意永相随。记得吃粽佩香囊,千年习俗暖心扉' }
            ]
          },
          {
            value: 2,
            name: '华南',
            children: [
              { value: 21, name: '广东' },
              { value: 22, name: '海南' }
            ]
          }
        ]
      };
    },
    methods: {

}
  };
</script>
<style scoped>
   /deep/ .classRed .custom-textarea{
  background-color: #00FFFF;

}

.container{
    margin: auto;
    width: 10%;
    margin-top: 10%;
    height: 300px;
}

 </style>
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐