🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 前言 大家在做管理后台系统的时候,是否有遇到操作按钮太多(三个以上)的情况呢?如下图 ![](https://img.kancloud.cn/e7/64/e76402787b808bb15f7e2dd42bd209bb_387x145.png) ## 实现思路 * 总体利用插槽 `slot`+`ref`实现,但是可分两种方式实现,本组件都结合到一起了。 * 公共html代码: ``` html <div :ref="`operation+${customRef}`" class="operation-container">     <div :ref="`operation+${customRef}_button`">       <slot />     </div>     <el-popover       popper-class="btns-container"       :placement="placement"       width="auto"       trigger="hover"     >       <slot />       <i v-show="isFold" slot="reference" class="el-icon-more fold-icon" />     </el-popover>  </div> ``` ### 方式一: 先来一个简单的实现方式,只要超过len(如:len=3)则出现 ··· ,通过 `const children = this.$refs[`operation+${this.customRef}_button`].children`, 当children.length>=len,则满足折叠条件,则`isFold=true`,并且第`len`至`children.length-1`的DOM节点隐藏,即可: ```js this.isFold = children.length > this.len // 当按钮数量与len不相等,则从len-1开始隐藏,从而使得 ··· 按钮显示 const isLen = children.length === this.len ? this.len : this.len - 1 children.forEach((child, ins) => {        child.style.display = ins >= isLen ? 'none' : 'inline-block' }) ``` ### 方式二: 首先了解一下`offsetWidth`和`scrollWidth`的使用,可[点击前往](https://www.kancloud.cn/vvmily_king/vvmily/2306109)查看 当父级容器宽度小于内容宽度,则需要出现 ··· 按钮,超出父容器宽度的按钮,则隐藏即可,关键如何获取这两个宽度,则需要上面两个方法了,其他说明也在代码中有注释。具体实现如下 注:`const childrenWidth = children.map(item => item.offsetWidth) // Array.isArray(children)===false` ``` js // 获取父容器宽度(包含边线) const offsetWidth = this.$refs[`operation+${this.customRef}`].offsetWidth // 获取本Dom下内容的宽度 const scrollWidth = this.$refs[`operation+${this.customRef}`].scrollWidth this.isFold = offsetWidth < scrollWidth if (this.isFold) { // const childrenWidth = children.map(item => item.offsetWidth) // Array.isArray(children)===false     const childrenWidth = []     for (let i = 0; i < children.length; i++) {           childrenWidth.push(children[i].offsetWidth)     }     let maxCount = 0     const showMaxIndex = childrenWidth.findIndex((item, ins) => {            maxCount = item + maxCount + (ins ? 10 : 0)            return maxCount > offsetWidth      })      children.forEach((item, index) => {            item.style.display = index >= showMaxIndex ? 'none' : 'inline-block'       })       maxCount = null // 空变量,释放 } ``` ## 完整的组件代码 | props | 说明 | | --- | --- | | customRef | 任意数字/字符串 | | len | len=0:根据宽度计算显示个数;len>0:则表示默认显示len个按钮 | | placement | 同el-popover的 [placement的配置项](https://element.eleme.cn/#/zh-CN/component/popover) | ``` vue <template> <div :ref="`operation+${customRef}`" class="operation-container"> <div :ref="`operation+${customRef}_button`"> <slot /> </div> <el-popover popper-class="btns-container" :placement="placement" width="auto" trigger="hover" > <slot /> <i v-show="isFold" slot="reference" class="el-icon-more fold-icon" /> </el-popover> </div> </template> <script> export default { name: 'ColumnOperation', props: { customRef: { type: [Number, String], default: 0 }, len: { type: Number, default: 0 // len=0:根据宽度计算显示个数;len>0:则表示默认显示len个按钮 }, placement: { type: String, default: 'left' } }, data() { return { width: '', isFold: false } }, mounted() { this.domInit() }, methods: { domInit() { const children = this.$refs[`operation+${this.customRef}_button`].children // type: Array this.$nextTick(() => { if (this.len) { this.isFold = children.length > this.len const isLen = children.length === this.len ? this.len : this.len - 1 children.forEach((child, ins) => { child.style.display = ins >= isLen ? 'none' : 'inline-block' }) } else { // 获取父容器宽度(包含边线) const offsetWidth = this.$refs[`operation+${this.customRef}`] .offsetWidth // 获取本Dom下内容的宽度 const scrollWidth = this.$refs[`operation+${this.customRef}`] .scrollWidth this.isFold = offsetWidth < scrollWidth if (this.isFold) { // const childrenWidth = children.map(item => item.offsetWidth) // Array.isArray(children)===false const childrenWidth = [] for (let i = 0; i < children.length; i++) { childrenWidth.push(children[i].offsetWidth) } let maxCount = 0 const showMaxIndex = childrenWidth.findIndex((item, ins) => { maxCount = item + maxCount + (ins ? 10 : 0) return maxCount > offsetWidth }) children.forEach((item, index) => { item.style.display = index >= showMaxIndex ? 'none' : 'inline-block' }) maxCount = null // 空变量,释放 } } }) } } } </script> <style lang="scss"> @import '../../styles/variables'; .operation-container { box-sizing: border-box; overflow: hidden; white-space: nowrap; min-width: 60px; display: flex; align-items: center; justify-content: start; .fold-icon { // position: absolute; // right: 12px; // top: calc(50% - 5px); color: $comTheme; cursor: pointer; margin-left: 10px; } } .btns-container { min-width: 60px; // & > * { // margin-right: 5px; // } } </style> ``` ## 总结 看完代码是不是感觉挺少的,嘿嘿... 写这个比业务舒服多了,可以适当的调试一下代码,写业务是不断的“调业务”,重复而且不过脑子... 呜呜呜