「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战」。
前言
大家在做管理后台系统的时候,是否有遇到操作按钮太多(三个以上)的情况呢?如下图
实现思路
- 总体利用插槽
slot+ref实现,但是可分两种方式实现,本组件都结合到一起了。 - 公共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节点隐藏,即可:
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的使用,可点击前往查看
当父级容器宽度小于内容宽度,则需要出现 ··· 按钮,超出父容器宽度的按钮,则隐藏即可,关键如何获取这两个宽度,则需要上面两个方法了,其他说明也在代码中有注释。具体实现如下
注:const childrenWidth = children.map(item => item.offsetWidth) // Array.isArray(children)===false
// 获取父容器宽度(包含边线)
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的配置项 |
<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>
- 其他组件调用
<ColumnOperation>
<el-button type="text" size="small">详情</el-button>
// ...
<el-button type="text" size="small">编辑</el-button>
<el-button type="text" size="small">删除</el-button>
</ColumnOperation>
总结
看完代码是不是感觉挺少的,嘿嘿...
写这个比业务舒服多了,可以适当的调试一下代码,写业务是不断的“调业务”,重复而且不过脑子... 呜呜呜