Vue2+ElementUI 封装动态按钮组:打造灵活的按钮操作

871 阅读2分钟

引言

在项目开发过程中,我们常常会遇到各种按钮组操作的需求。无论是表单区域,还是表格展示中的操作列,都可能包含大量的操作按钮。然而,过多的按钮不仅会让界面显得杂乱无章,还会占据大量空间,影响用户体验。在这种情况下,一个动态按钮组组件就显得尤为重要。

接下来,我将详细介绍如何在 Vue2 和 ElementUI 的框架下封装这样一个动态按钮组组件,帮助你在项目开发中更加高效地管理按钮操作。

需求分析

1. 基本功能需求

  1. 动态按钮组显示
    • 接收一组按钮配置(buttonList),并根据配置渲染按钮。
    • 提供一个属性(如 maxVisibleButtons)用于控制最多显示几个按钮。超出部分的按钮将通过 el-dropdown 下拉菜单展示。
    • 默认情况下,按钮显示其 label 属性的内容,支持自定义按钮内容展示。
  2. 事件支持
    • 每个按钮点击时触发 click 事件,事件参数为当前点击按钮的配置信息(info)。

2. 组件功能扩展

  1. 支持 ElementUI 的 el-button 属性
    • 动态按钮组支持传递 el-button 的所有 props,以便开发者可以自定义按钮的样式、类型、大小等属性。
  2. 下拉菜单(el-dropdown)功能
    • 支持自定义 el-dropdown 的样式或行为(ElementUI 的 el-dropdown 部分属性,如:{ trigger: "click", placement: "bottom-start" })。
    • 支持自定义 el-dropdown 的触发内容,默认为 el-button
    • el-dropdown-item 支持自定义内容展示,默认显示按钮配置中的 label 属性。

实现细节

定义 Props

props: {
    // 按钮数组
    buttonList: {
      type: Array,
      required: true,
    },
    // 最多显示的按钮数量
    maxVisibleButtons: {
      type: Number,
      default: 3,
    },
    // 按钮公共Props
    buttonProps: {
      type: Object,
      default: () => ({}),
    }
    // 下拉选择框Props
    dropdownProps: {
      type: Object,
      default: () => ({}),
    }
}

计算属性

computed: {
    // 显示的按钮组
    visibleButtons() {
      return this.buttonList.slice(0, this.maxVisibleButtons);
    },
    // 隐藏的按钮组
    hiddenButtons() {
      return this.buttonList.slice(this.maxVisibleButtons);
    },
    // 是否有隐藏的按钮
    hasHiddenButtons() {
      return this.hiddenButtons.length > 0;
    }
}

方法

methods: {
    handleClick(button) {
      this.$emit("click", button);
    }
}

编写 template

<div>
    <!-- 默认显示的按钮 -->
    <el-button
        v-for="btn in visibleButtons"
        :key="btn.key"
        v-bind="{...buttonProps,...btn.props}"
        @click="handleClick(btn)"
    >
      <slot :name="btn.key" :scope="btn">
        {{ btn.label }}
      </slot>
    </el-button>

    <!-- 超出部分的下拉按钮 -->
    <el-dropdown class="more-dropdown" v-if="hasHiddenButtons" v-bind="dropdownProps" @command="handleClick">
      <slot name="dropdown">
        <el-button type="primary">
          更多<i class="el-icon-arrow-down el-icon--right"></i>
        </el-button>
      </slot>
      <el-dropdown-menu>
        <el-dropdown-item
            v-for="btn in hiddenButtons"
            :key="btn.key"
            v-bind="{...buttonProps,...btn.props}"
            :command="btn"
        >
          <slot :name="btn.key" :scope="btn">{{ btn.label }}</slot>
        </el-dropdown-item>
      </el-dropdown-menu>
    </el-dropdown>
</div>

样式

<style scoped>
.more-dropdown {
  margin-left: 10px;
}
</style>

组件源码

<script>
export default {
  name: "DynamicButtonGroup",
  props: {
    // 按钮数组
    buttonList: {
      type: Array,
      required: true,
    },
    // 最多显示的按钮数量
    maxVisibleButtons: {
      type: Number,
      default: 3,
    },
    // 按钮公共Props
    buttonProps: {
      type: Object,
      default: () => ({}),
    }
    // 下拉选择框Props
    dropdownProps: {
      type: Object,
      default: () => ({}),
    }
  },
  computed: {
    // 显示的按钮组
    visibleButtons() {
      return this.buttonList.slice(0, this.maxVisibleButtons);
    },
    // 隐藏的按钮组
    hiddenButtons() {
      return this.buttonList.slice(this.maxVisibleButtons);
    },
    // 是否有隐藏的按钮
    hasHiddenButtons() {
      return this.hiddenButtons.length > 0;
    },
  },
  methods: {
    handleClick(button) {
      this.$emit("click", button);
    },
  },
}
</script>

<template>
  <div>
    <!-- 默认显示的按钮 -->
    <el-button
        v-for="btn in visibleButtons"
        :key="btn.key"
        v-bind="{...buttonProps,...btn.props}"
        @click="handleClick(btn)"
    >
      <slot :name="btn.key" :scope="btn">
        {{ btn.label }}
      </slot>
    </el-button>

    <!-- 超出部分的下拉按钮 -->
    <el-dropdown class="more-dropdown" v-if="hasHiddenButtons" v-bind="dropdownProps" @command="handleClick">
      <slot name="dropdown">
        <el-button type="primary">
          更多<i class="el-icon-arrow-down el-icon--right"></i>
        </el-button>
      </slot>
      <el-dropdown-menu>
        <el-dropdown-item
            v-for="btn in hiddenButtons"
            :key="btn.key"
            v-bind="{...buttonProps,...btn.props}"
            :command="btn"
        >
          <slot :name="btn.key" :scope="btn">{{ btn.label }}</slot>
        </el-dropdown-item>
      </el-dropdown-menu>
    </el-dropdown>
  </div>
</template>

<style scoped>
.more-dropdown {
  margin-left: 10px;
}
</style>

FAQ

对于按钮权限处理,可以在 buttonList 的每个按钮中定义一个 permission 属性。在使用动态按钮组的页面中,通过一个计算属性调用权限判断方法,使用 filter 方法过滤出具有权限的按钮组。


感谢阅读,敬请斧正!