el-cascader 实现最后一级点击一行选中

el-cascader 实现最后一级点击一行选中,无需点击单选框!!

我是将el-cascader 封装成组件了

父亲 这样引用

<el-form-item label="作业申请单位" prop="name">
  <TaskUnit :value.sync="queryParams.name" placeholder="请选择"></TaskUnit>
</el-form-item>

废话不多说直接上组件代码!!!!

要实现对最后一级(叶子节点)点击文字也可以选定的功能,我们需要修改组件逻辑和样式。这通常需要通过自定义 el-cascader 的展示节点,并为最后一级添加特殊的点击事件处理。

下面是代码:

<template>
  <el-cascader
    ref="cascader"
    @change="changeUnit"
    :title="title"
    v-model="taskUnit"
    :options="taskUnitOption"
    :props="propsData"
    :show-all-levels="false"
    clearable
    :placeholder="placeholder"
  >
    <!-- 自定义节点内容,使最后一级点击文字可选 -->
    <template slot-scope="{ node, data }">
      <span
        class="custom-node-content"
        :class="{ 'leaf-node': isLeafNode(data) }"
        @click="handleNodeClick(node, data, $event)"
      >
        {{ node.label }}
      </span>
    </template>
  </el-cascader>
</template>

<script>
import { getList} from "@/api/system/user";

/**
 * @description
 * 作业单位的级联选择器
 * @property {String} value 绑定值 .sync修饰
 * @property {String} valueName 绑定值中文 .sync修饰
 * @property {String} placeholder 组件占位符
 */
export default {
  name: 'TaskUnit',
  props: {
    value: {
      type: String,
      default: ''
    },
    valueName: {
      type: String,
      default: ''
    },
    placeholder: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      //列表
      taskUnitOption: [],
      // 作业单位绑定值
      taskUnit: [],
      // 显示的title
      title: '',
      // Cascader 组件的属性配置
      propsData: {
        checkStrictly: true,
        value: 'id',
        // label: 'name', // 假设你的选项中有 name 字段用于展示
        // children: 'children', // 假设选项中有 children 字段用于子节点
        expandTrigger: 'hover' // 悬停时展开子菜单
      }
    };
  },
  watch: {
    // 监听外部value变化,同步到内部taskUnit
    value: {
      handler(val) {
        if (val) {
          this.taskUnit = val.split(',');
          this.updateTitle(); // 更新标题
        } else {
          this.taskUnit = []; // 没传值时赋值为空
          this.title = ''; // 清空标题
        }
      },
      immediate: true // 立即执行,确保组件加载时同步
    }
  },
  mounted() {
    this.init(); // 初始化
  },
  methods: {
    // 选择单位
    changeUnit(list) {
      console.log('选择列表:', list);

      const nodes = this.$refs.cascader.getCheckedNodes();
      if (nodes.length === 0) {
        this.title = ''; // 清空标题
        this.$emit('update:value', '');
        this.$emit('update:value-name', '');
        return;
      }

      // 更新标题
      this.updateTitle(nodes[0]);

      // 绑定数据
      this.$emit('update:value', list.join(','));
      this.$emit('update:value-name', this.title);
    },

    // 更新标题
    updateTitle(node) {
      if (!node) return;

      const labelList = node.pathLabels || [];
      this.title = labelList.join('/');
    },

    // 列表
    async getTaskUnit() {
      try {
        const res = await getList(); // 改为不根据用户权限进行控制
        this.taskUnitOption = res.data || []; // 确保防止 undefined
      } catch (error) {
        console.error('获取作业单位列表失败:', error);
        this.$message.error('获取作业单位列表失败');
      }
    },

    // 初始化函数
    init() {
      this.getTaskUnit(); // 获取单位列表
    },

    /**
     * 判断节点是否为叶子节点
     * @param {Object} data - 节点数据
     * @returns {Boolean} 是否为叶子节点
     */
    isLeafNode(data) {
      return !data.children || data.children.length === 0;
    },

    /**
     * 处理节点点击事件
     * @param {Object} node - 级联选择器节点对象
     * @param {Object} data - 节点数据
     * @param {Event} event - 点击事件对象
     */
    handleNodeClick(node, data, event) {
      // 只有在点击叶子节点文本时才触发选中
      if (this.isLeafNode(data)) {
        event.stopPropagation(); // 阻止冒泡,防止触发其他点击事件

        // 构建选中路径
        const path = [];
        let currentNode = node;

        while (currentNode) {
          path.unshift(currentNode.value);
          currentNode = currentNode.parent;
        }

        // 直接设置选中值
        this.taskUnit = path;

        // 触发选中事件(模拟change事件)
        this.$nextTick(() => {
          this.changeUnit(path);

          // 手动关闭下拉菜单
          if (this.$refs.cascader && typeof this.$refs.cascader.toggleDropDownVisible === 'function') {
            this.$refs.cascader.toggleDropDownVisible(false);
          }
        });
      }
    }
  }
};
</script>

<style lang="scss" scoped>
::v-deep .el-input__suffix {
  display: none;
}

.el-cascader-menu__item {
  cursor: pointer; /* 鼠标指针变为手形,表示可点击 */
}

/* 自定义样式:取消单选框的显示 */
.el-cascader-menu__item .el-checkbox {
  display: none;
}

/* 自定义节点内容样式 */
.custom-node-content {
  display: block;
  width: 100%;
  height: 100%;
}

/* 叶子节点的特殊样式 */
.leaf-node {
  cursor: pointer;
  color: #606266;
  transition: color 0.3s;

  &:hover {
    color: #409EFF;
  }
}

/* 确保整个节点区域可点击 */
::v-deep .el-cascader-node__label {
  width: 100%;
  padding-right: 0;
}

/* 选中的样式 */
::v-deep .el-cascader-menu__item.is-active {
  color: #409EFF;
  font-weight: bold;
}
</style>

实现说明

  1. 自定义节点内容

    • 使用 slot-scope 自定义节点的内容展示。
    • 为每个节点添加了 custom-node-content 类,为叶子节点添加了 leaf-node 类用于特殊样式。
  2. 增加点击事件处理

    • 添加了 handleNodeClick 方法,专门处理节点点击事件。
    • 在点击叶子节点文本时,会构建完整路径并触发选中效果。
    • 使用 event.stopPropagation() 防止事件冒泡导致其他不需要的行为。
  3. 判断叶子节点

    • 添加 isLeafNode 方法,用于判断节点是否为叶子节点(没有子节点)。
  4. CSS 样式优化

    • 为叶子节点添加了特殊的悬停效果,使其看起来可点击。
    • 确保节点的整个区域都可以点击,而不只是复选框。
  5. 手动关闭下拉菜单

    • 在点击叶子节点后,手动关闭级联选择器的下拉菜单,提供更好的用户体验。

这个实现确保了在保留原有功能的基础上,当用户点击最后一级(叶子节点)的文本时,也能够正确选中该节点。样式上也进行了适当的调整,使叶子节点的可点击性更加明显。