Cascader 级联选择器定位问题解决

本文介绍了在Vue中使用级联选择器(Cascader)时遇到的回显问题,即当级联选项过多时,数据无法正确回显。问题的根本原因是数据不一致导致组件无法更新。解决方案包括使用`v-if`(可能导致闪烁)和添加`key`属性以触发重新渲染。通过在`el-cascader`组件上添加`:key`属性并结合`modalKey`变量,可以确保每次点击时组件都能正确更新,从而解决回显问题。

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

正常定位样式:

 前提:当级联太多时候就会出现回显问题,一两个倒没什么问题

上代码:

 <template>
   <el-form
      :model="ruleForm"
      ref="ruleForm"
      label-width="100px"
    >
      <el-form-item label="工种类型:" prop="workTypeId">
        <el-cascader
          filterable
          :show-all-levels="false"
          placeholder="请选择工种类型"
          clearable
          style="width:80%"
          :props="props"
          v-model="ruleForm.workTypeId"
          :options="worksTypes"
        ></el-cascader>
      </el-form-item>
  </el-form>
</template>
<script>
export default{
 data () {
    return {
      props: {
          value: 'id',
          label: 'label',
          children: 'children'
       },
     ruleForm:{
       workTypeId:[],
     },
     worksTypes:[],
     }
 },
mounted(){
  this.getTypes()
  this.getValue()
},
methods:{
  //获取值
  getValue(){
    this.axios.get('api').then(function (response) {
        console.log(response);
        this.ruleForm.workTypeId = response
        this.modalKey = this.modalKey+1
    })
    .catch(function (error) {
      console.log(error);
  });
 },
//获取筛选项值
  getTypes(){
    this.axios.get('api').then(function (response) {
      console.log(response);
      this.worksTypes = response
  })
    .catch(function (error) {
      console.log(error);
  });
 }
},
</script>

图片:定位时准时不准

 出现这种情况无法回显根本原因:就是数据不一样无法更新

有两种解决方法:

第一种就是用v-if方法,但这种会导致刚点击弹窗的时候那一栏会突然显示问题所以不推荐

第二总就是给它加个key,让每一次点击都能重新渲染

代码:

<template>
   <el-form
      :model="ruleForm"
      ref="ruleForm"
      label-width="100px"
    >
      <el-form-item label="工种类型:" prop="workTypeId">
        <el-cascader
          :key="modalKey"
          filterable
          :show-all-levels="false"
          placeholder="请选择工种类型"
          clearable
          style="width:80%"
          :props="props"
          v-model="ruleForm.workTypeId"
          :options="worksTypes"
        ></el-cascader>
      </el-form-item>
  </el-form>
</template>
<script>
export default{
 data () {
    return {
      props: {
          value: 'id',
          label: 'label',
          children: 'children'
       },
     modalKey:0,  //key 
     ruleForm:{
       workTypeId:[],
     },
     worksTypes:[],
     }
 },
mounted(){
  this.getTypes()
  this.getValue()
},
methods:{
//获取值
getValue(){
this.axios.get('api').then(function (response) {
      console.log(response);
      this.ruleForm.workTypeId = response
      this.modalKey = this.modalKey+1
  })
    .catch(function (error) {
      console.log(error);
  });
},
//获取筛选项里的值
  getTypes(){
    this.axios.get('api').then(function (response) {
      console.log(response);
      this.worksTypes = response
  })
    .catch(function (error) {
      console.log(error);
  });
 }
},
</script>

这样就解决了

<think>嗯,用户想了解如何从零开始实现一个Cascader级联选择器组件。我需要先回忆一下这类组件的常见功能和结构。Cascader通常用于多层级数据的选择,比如省市区选择。用户可能需要知道如何构建交互、处理数据联动以及样式设计。 首先,应该考虑组件的数据结构。通常,级联选择器的数据是树形结构,每个节点可能有子节点。所以,数据模型需要支持递归遍历。接下来是交互部分,当用户选择一个选项后,如何展开下一级菜单。这里可能需要事件处理和动态渲染子菜单。 然后,UI部分需要考虑如何展示多级菜单,可能需要使用绝对定位来浮动子菜单,并确保它们正确对齐。同时,处理点击外部区域关闭菜单的功能,这可能需要用到全局事件监听。 另外,用户可能希望组件支持多选,所以需要处理Checkbox的状态联动,比如选中父节点时自动选择所有子节点,或者部分选中状态。这部分逻辑比较复杂,需要考虑如何递归更新节点的选中状态。 还有,样式方面可能需要参考现有的UI库,比如Ant Design,用户提到可以复用它们的类名来保持样式一致。同时,动画效果如展开和收起的过渡效果也需要考虑。 测试也是重要的一环,需要确保不同场景下的交互正确,比如动态加载数据、异步数据源的处理等。最后,封装组件为可复用的NPM包,编写文档和示例代码,方便其他开发者使用。 总结一下,实现步骤可能包括:设计数据模型、处理用户交互、渲染多级菜单、状态管理、样式和动画、测试与优化。需要分步骤讲解,并给出代码示例,帮助用户逐步构建组件。</think>### 如何手写实现级联选择器Cascader) #### 一、核心设计思路 1. **数据结构** 使用树形结构存储层级数据,节点对象需包含: - `label`(显示文本) - `value`(唯一标识) - `children`(子节点数组) ```typescript interface TreeNode { label: string; value: string; children?: TreeNode[]; } ``` 2. **交互逻辑** - 点击父级选项时展开子菜单(使用事件冒泡机制) - 子菜单定位需计算父元素偏移量(通过`getBoundingClientRect`) - 点击非菜单区域关闭所有层级(通过`事件委托`实现) #### 二、关键代码实现 ```tsx // 1. 递归渲染菜单 const renderMenu = (nodes: TreeNode[], level: number) => { return ( <div className="menu-level" style={{ left: level * 200 }}> {nodes.map(node => ( <div key={node.value} onClick={(e) => handleItemClick(e, node)} className="menu-item" > {node.label} {node.children && <span className="arrow" />} </div> ))} </div> ); }; // 2. 联动控制逻辑 const handleItemClick = (e: React.MouseEvent, node: TreeNode) => { e.stopPropagation(); if (node.children) { setActiveLevel(prev => [...prev.slice(0, level), node.value]); // 更新激活路径 } else { onSelect(getSelectedPath()); // 最终选择值 } }; ``` #### 三、样式与动画 1. 使用`position: absolute`实现浮动层叠效果 2. 通过`transform: translateY()`实现平滑展开动画 3. 复用Antd的样式类名保持一致性(如`.ant-cascader-menu`)[^3] #### 四、进阶优化 1. **异步数据加载** 在节点添加`isLeaf`标记,通过`loadData`回调实现动态加载 ```ts const loadData = async (selectedPath: string[]) => { const res = await fetch(`/api/data?path=${selectedPath.join('/')}`); updateTree(selectedPath, res.data); }; ``` 2. **多选模式** 使用Checkbox组件并实现状态联动: ```ts const updateCheckState = (node: TreeNode) => { const allChildrenChecked = node.children?.every(c => c.checked); node.indeterminate = !allChildrenChecked && node.children?.some(c => c.checked); node.checked = allChildrenChecked; }; // 需递归更新父节点状态 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值