基于Element封装一个表格操作栏按钮组件

367 阅读1分钟

需求

实现一个el-table操作栏的表格操作按钮组件,操作按钮超过一定限制数量的时候,超出的按钮隐入下拉菜单中,点击下拉菜单进行操作;按钮需要支持动态控制显隐,loading效果,自定义样式,tooltip提示等效果,效果如下:

实现

思路:定义父组件接受插槽内容,再定义子组件,在按钮状态更新的时候通过EventBus通知父组件渲染按钮

代码如下:

父组件action-bar.vue

<!-- 通用表格操作栏 --><template>  <div>    <div v-show="originalSlot">      <slot></slot>    </div>    <!-- 正常显示的按钮 -->    <div v-for="(item, index) in visibleBtn" :key="index" class="visible-btn">      <el-tooltip class="item" effect="dark" :content="item.props.tooltipText" placement="top-start"        v-if="item.props.showTooltip && !originalSlot">        <el-button type="text" v-bind="item.props" :disabled="isDisabled(item.props)" :loading="item.props.loading"          :command="item.command ? item.command : index" @click="clickMethods(item.props, item.clickFn)">          <span :style="{ ...item.props.textStyle }">{{ item.label }}</span>        </el-button>      </el-tooltip>      <el-button type="text" v-bind="item.props" :disabled="isDisabled(item.props)" :loading="item.props.loading"        :command="item.command ? item.command : index" @click="clickMethods(item.props, item.clickFn)"        v-if="!item.props.showTooltip && !originalSlot">        <span :style="{ ...item.props.textStyle }">{{ item.label }}</span>      </el-button>    </div>    <!-- 隐藏进下拉菜单的按钮 -->    <el-dropdown v-if="hideBtn.length > 0 && !originalSlot" :hide-on-click="hideOnClick">      <el-button type="text">        <i class="el-icon-more-outline"></i>      </el-button>      <el-dropdown-menu slot="dropdown" class="dropdown-menu">        <div @click="clickMethods(element.props, element.clickFn)" v-for="(element, subIndex) in hideBtn" :key="subIndex">          <el-tooltip class="item" effect="dark" :content="element.props.tooltipText" placement="top-start"            v-if="element.props.showTooltip">            <span :class="isDisabled(element.props) ? 'wrapper el-button' : ''">              <el-dropdown-item :disabled="isDisabled(element.props)"                :command="element.command ? element.command : subIndex">                <i class="el-icon-loading" v-if="element.props.loading"></i>                <span :style="{ ...element.props.textStyle }">{{ element.label                }}</span>              </el-dropdown-item>            </span>          </el-tooltip>          <span :class="isDisabled(element.props) ? 'wrapper el-button' : ''" v-else>            <el-dropdown-item :disabled="isDisabled(element.props)" :command="element.command ? element.command : subIndex">              <i class="el-icon-loading" v-if="element.props.loading"></i>              <span :style="{ ...element.props.textStyle }">{{ element.label              }}</span>            </el-dropdown-item>          </span>        </div>      </el-dropdown-menu>    </el-dropdown>  </div></template><script>import { EventBus } from '../../event-bus.js';export default {  name: 'action-bar',  props: {    limitCount: {//限制显示的按钮数量,默认为1,超出多少个就会进行隐藏      type: Number | String,      default: 1    },    originalSlot: {//如果设置为true,默认插槽输入啥,原本输出      type: Boolean,      default: false    },    hideOnClick: {//是否在点击后隐藏下拉菜单      type: Boolean,      default: true    }  },  data() {    return {      timeoutIns: null    }  },  created() {    // 监听子组件的事件通知    EventBus.$on('changeSlot', () => {      if (this.timeoutIns) clearTimeout(this.timeoutIns)      this.timeoutIns = setTimeout(() => {        this.setBtnArray()      }, 100)    });  },  mounted() {    if (!this.originalSlot) {      this.$nextTick(() => {        this.setBtnArray()      })    }  },  data() {    return {      visibleBtn: [],// 显示的按钮      hideBtn: []// 隐藏的按钮    };  },  methods: {    // 分发数组    setBtnArray() {      this.$nextTick(() => {        let btnObjArray = this.$slots.default.map(item => {          if (!item.componentInstance) {            return          }          const btnObj = {            props: { ...item.componentInstance._props },//继承el-button的属性            label: item.componentInstance.$slots.default[0].text,//按钮的问题            clickFn: item.componentInstance.$listeners.click//子组件的点击事件作为参数          }          if (item.data.attrs) {            Object.assign(btnObj, {}, item.data.attrs)          }          return btnObj        })        btnObjArray = btnObjArray.filter(item => item !== undefined);        // 显示的按钮        this.visibleBtn = btnObjArray.slice(0, this.limitCount)        // 隐藏的按钮        this.hideBtn = btnObjArray.slice(this.limitCount, btnObjArray.length)      })    },    clickMethods(props, clickFn) {      if (props.disabled || props.loading || typeof clickFn !== 'function') {// 需要去除不能点击,或者不是函数的情况        return false      } else {        clickFn()      }    },    // 判断是否该禁用    isDisabled(props){      return props.disabled || props.loading    }  },};</script><style lang="scss" scoped>.wrapper.el-button {  display: inline-block;  padding: 0;  margin: 0;  width: 100%;  text-align: left !important;  border: none;  cursor: not-allowed;}.dropdown-menu{  white-space: nowrap;}.visible-btn {  display: inline-block;  margin-right: 10px;}</style>

子组件action-bar-button.vue

<!-- 通用表格操作栏按钮 --><template>  <div>  </div></template><script>import { EventBus } from '../../event-bus.js';export default {  name: 'action-bar-button',  props:{    disabled:{//是否禁用      type:Boolean,      default:false    },    showTooltip:{//是否hover时显示tooltip      type:Boolean,      default:false    },    tooltipText:{//tooltip的文字,只在showTooltip为true时有效      type:String,      default:'提示文字'    },    loading:{//loading效果      type:Boolean,      default:false    },    textStyle:{//按钮文字的样式      type:Object,      default:()=>{}    }  },  data() {    return {    }  },  updated(){    // 数据更新时通知父组件    EventBus.$emit('changeSlot')  },  methods: {  },};</script>

event-bus.js

import Vue from 'vue';export const EventBus = new Vue();

由此我们就可以实现一个表格通用栏组件了。