使用el-cascader封装一个下拉级联按钮BaseCascadeDropDown

下拉级联按钮,未展开时
在这里插入图片描述

使用el-pop + el-cascader-panel封装

每次级联树展开时,需要动态计算弹窗的宽度,还不如直接使用el-cascader + el-button进行封装

<template>
  <el-popover
      ref="popover"
      placement="bottom"
      width="200"
      :trigger="trigger"
      v-model="visible"
    >
      <el-cascader-panel
        :options="children"
        @change="handleCascaderClick"
        :props="cascaderProps"
      ></el-cascader-panel>
      <slot name="button" slot="reference">
        <el-button
          v-if="children.length"
          :type="buttonConfig.type || 'text'"
          :size="buttonConfig.size"
          v-permissions="getPermissionCode(buttonConfig)"
          @click="handleClick(buttonConfig)"
          v-bind="{ ...buttonConfig }"
          >
          {{ buttonConfig.btn}}
          <i
            class="el-icon-arrow-down el-icon--right"
            v-if="!buttonConfig.hideArrow"
          ></i>
        </el-button>
      </slot>
    </el-popover>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'

const defaultCascaderProps = {
  expandTrigger: 'hover',
  value: 'key',
  label: 'btn',
}
@Component({
  name: 'BaseCascadeDropDown' //? 级联下拉按钮
})
export default class extends Vue {
  @Prop({ default: () => ({}) }) buttonConfig!: any //? 下拉按钮的配置
  @Prop({ default: () => ({}) }) data?: any //? 下拉按钮的数据,用于动态属性的配置,后面也会将数据传出入
  @Prop({ default: () => [] }) children: any[] //? 下拉按钮的选项
  @Prop({ default: 'hover' }) trigger: string //? 气泡的触发方式,,默认悬浮展示
  @Prop({ default: 'hover' }) expandTrigger: string //? 级联次级菜单的展开方式,默认悬浮展示
  @Prop({ default: () => defaultCascaderProps }) cascaderProps: any //? 级联的配置选项,次级菜单展开方式,默认悬浮展示
  //* 事件监听
  //* eventHandler //? 按钮列的总事件监听

  hide = false
  visible = false

  mounted() {
    const popoverRef: any = this.$refs.popover
    // if (!popoverRef.popperElm.children.length) {
    //   this.hide = true
    // }
  }
  togglePopover() {
    this.visible = !this.visible;
  }

  getPermissionCode(button) { //todo 获取权限码
    if (typeof button.permissionCode === 'function') {
      return button.permissionCode(this.data, button.key)
    }
    return button.permissionCode
  }

  handleClick(button) {
    this.togglePopover()
    let loadingInstance
    if (button.needLoading) {
      loadingInstance = this.$loading({
        lock: button.loadLock || true,
        text: button.loadText || 'Loading',
        spinner: button.loadSpinner || 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      })
    }
    const params = {
      event: button.key,
      data: this.data,
      extraParams: {
        button,
        closeLoading: () => {
          button.needLoading && loadingInstance.close()
        }
      }
    }
    if (typeof button.submit === 'function') {
      button.submit(params)
    }
    this.handleEventHandler(params)
  }
  handleCascaderClick(value) {
    this.visible = false;
    const subButtonConfig = this.children.find(
      (subButton) => subButton.key === value
    ) //? 子按钮的配置
    let loadingInstance
    if (subButtonConfig.needLoading) {
      loadingInstance = this.$loading({
        lock: subButtonConfig.loadLock || true,
        text: subButtonConfig.loadText || 'Loading',
        spinner: subButtonConfig.loadSpinner || 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      })
    }
    const params = {
      event: subButtonConfig.key,
      data: this.data,
      extraParams: {
        button: subButtonConfig,
        subButtonConfig,
        closeLoading: () => {
          subButtonConfig.needLoading && loadingInstance.close()
        }
      }
    }
    if (typeof subButtonConfig.submit === 'function') {
      subButtonConfig.submit(params)
    }
    this.handleEventHandler(params)
  }
  needHidden(button) {
    //todo 是否需要按钮隐藏
    if (typeof button.hidden === 'function') {
      return !!button.hidden(this.data, button.key || button.permissionCode)
    }
    return button.hidden
  }
  needDisabled(button) {
    //todo 判断是否需要禁用按钮
    if (typeof button.disabled === 'function') {
      return button.disabled(this.data, button.key || button.permissionCode)
    }
    return button.disabled
  }
  handleEventHandler({ event, data, extraParams = {} }) {
    //todo 调用外部方法
    this.$emit('eventHandler', {
      event,
      data,
      extraParams
    })
  }
}
</script>

<style lang="scss" scoped>

</style>

使用el-cascader + el-button进行封装

1、隐藏el-cascader里面的input框;
2、点击按钮时,弹出el-cascader会自动计算宽度的弹窗
3、每次点击(后)需要将勾选状态重置 —— 发现el-cascader组件内部问题,修改其勾选状态不生效,直接修改el-cascader组件内的数据也不生效,只能将其销毁重建

<template>
  <div>
    <el-cascader
      ref="cascader"
      v-model="value"
      v-if="cascaderShow"
      class="cascader_dropdown"
      :options="children"
      @change="handleCascaderClick"
      :props="cascaderProps"
    ></el-cascader>
    <slot name="button">
      <el-button
        v-if="children.length"
        :type="buttonConfig.type || 'text'"
        :size="buttonConfig.size"
        v-permissions="getPermissionCode(buttonConfig)"
        @click="handleClick(buttonConfig)"
        v-bind="{ ...buttonConfig }"
        >
        {{ buttonConfig.btn }}
        <i
          class="el-icon-arrow-down el-icon--right"
          v-if="!buttonConfig.hideArrow"
        ></i>
      </el-button>
    </slot>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import { isBoolean } from 'xe-utils'

const defaultCascaderProps = {
  expandTrigger: 'hover',
  multiple: false,
  value: 'key',
  label: 'btn',
  children: 'children'
}
@Component({
  name: 'BaseCascadeDropDown' //? 级联下拉按钮
})
export default class extends Vue {
  @Prop({ default: () => ({}) }) buttonConfig!: any //? 下拉按钮的配置
  @Prop({ default: () => ({}) }) data?: any //? 下拉按钮的数据,用于动态属性的配置,后面也会将数据传出入
  @Prop({ default: () => [] }) children: any[] //? 下拉按钮的选项
  @Prop({ default: 'hover' }) trigger: string //? 气泡的触发方式,,默认悬浮展示
  @Prop({ default: 'hover' }) expandTrigger: string //? 级联次级菜单的展开方式,默认悬浮展示
  @Prop({ default: () => defaultCascaderProps }) cascaderProps: any //? 级联的配置选项,次级菜单展开方式,默认悬浮展示
  //* 事件监听
  //* eventHandler //? 按钮列的总事件监听

  value = []
  hide = false
  visible = false
  cascaderShow = true

  mounted() {
    const cascaderRef: any = this.$refs.cascader;
    // if (!popoverRef.popperElm.children.length) {
    //   this.hide = true
    // }
  }
  toggleDropDownVisible(visible?) {
    const cascaderRef: any = this.$refs.cascader;
    this.visible = isBoolean(visible) ? visible : !this.visible;
    cascaderRef.toggleDropDownVisible(this.visible)
  }

  getPermissionCode(button) { //todo 获取权限码
    if (typeof button.permissionCode === 'function') {
      return button.permissionCode(this.data, button.key)
    }
    return button.permissionCode
  }

  findCurrentItem(valuePath, data) { //todo 根据路径找到对应树形结构中的某个节点
  const { value, children } = this.cascaderProps;
    if (Array.isArray(valuePath) && valuePath.length) {
      const currentItem = data.find(item => item[value] === valuePath[0])
      valuePath.shift()
      if (!valuePath.length) { //* 没有下一级
        //* 找到当前级别的数据
        return currentItem
      }
      return this.findCurrentItem(valuePath, currentItem[children])
    }
  }

  handleClick(button) {
    this.toggleDropDownVisible()
    let loadingInstance
    if (button.needLoading) {
      loadingInstance = this.$loading({
        lock: button.loadLock || true,
        text: button.loadText || 'Loading',
        spinner: button.loadSpinner || 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      })
    }
    const params = {
      event: button.key,
      data: this.data,
      extraParams: {
        button,
        closeLoading: () => {
          button.needLoading && loadingInstance.close()
        }
      }
    }
    if (typeof button.submit === 'function') {
      button.submit(params)
    }
    this.handleEventHandler(params)
  }
  handleCascaderClick(valuePath) {
    if (Array.isArray(valuePath) && valuePath.length) {
      const subButtonConfig = this.findCurrentItem(valuePath, this.children)
      let loadingInstance
      if (subButtonConfig.needLoading) {
        loadingInstance = this.$loading({
          lock: subButtonConfig.loadLock || true,
          text: subButtonConfig.loadText || 'Loading',
          spinner: subButtonConfig.loadSpinner || 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        })
      }
      const params = {
        event: subButtonConfig.key,
        data: this.data,
        extraParams: {
          button: subButtonConfig,
          subButtonConfig,
          closeLoading: () => {
            subButtonConfig.needLoading && loadingInstance.close()
          }
        }
      }
      if (typeof subButtonConfig.submit === 'function') {
        subButtonConfig.submit(params)
      }
      this.handleEventHandler(params)
    }
    this.toggleDropDownVisible(false) //* 关闭弹窗
    this.visible = false
    this.cascaderShow = false; //* 临时将其销毁重建
    this.$nextTick(() => {
      this.cascaderShow = true;
    })
  }
  needHidden(button) {
    //todo 是否需要按钮隐藏
    if (typeof button.hidden === 'function') {
      return !!button.hidden(this.data, button.key || button.permissionCode)
    }
    return button.hidden
  }
  needDisabled(button) {
    //todo 判断是否需要禁用按钮
    if (typeof button.disabled === 'function') {
      return button.disabled(this.data, button.key || button.permissionCode)
    }
    return button.disabled
  }
  handleEventHandler({ event, data, extraParams = {} }) {
    //todo 调用外部方法
    this.$emit('eventHandler', {
      event,
      data,
      extraParams
    })
  }
}
</script>

<style lang="scss" scoped>
::v-deep {
  .cascader_dropdown {
    input {
      display: none;
    }
  }
  // .el-cascader__dropdown {
  //   .el-cascader-menu {
  //     min-width: 130px !important;
  //   }
  // }
}
</style>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值