需求
实现一个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();
由此我们就可以实现一个表格通用栏组件了。