## 前言
大家在做管理后台系统的时候,是否有遇到操作按钮太多(三个以上)的情况呢?如下图
![](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>
```
## 总结
看完代码是不是感觉挺少的,嘿嘿...
写这个比业务舒服多了,可以适当的调试一下代码,写业务是不断的“调业务”,重复而且不过脑子... 呜呜呜
- 首页
- 2021年
- 基础知识
- 同源策略
- 跨域
- css
- less
- scss
- reset
- 超出文本显示省略号
- 默认滚动条
- 清除浮动
- line-height与vertical-align
- box-sizing
- 动画
- 布局
- JavaScript
- 设计模式
- 深浅拷贝
- 排序
- canvas
- 防抖节流
- 获取屏幕/可视区域宽高
- 正则
- 重绘重排
- rem换算
- 手写算法
- apply、call和bind原理与实现
- this的理解-普通函数、箭头函数
- node
- nodejs
- express
- koa
- egg
- 基于nodeJS的全栈项目
- 小程序
- 常见问题
- ec-canvas之横竖屏切换重绘
- 公众号后台基本配置
- 小程序发布协议更新
- 小程序引入iconfont字体
- Uni-app
- 环境搭建
- 项目搭建
- 数据库
- MySQL数据库安装
- 数据库图形化界面常用命令行
- cmd命令行操作数据库
- Redis安装
- APP
- 控制缩放meta
- GIT
- 常用命令
- vsCode
- 常用插件
- Ajax
- axios-services
- 文章
- 如何让代码更加优雅
- 虚拟滚动
- 网站收藏
- 防抖节流之定时器清除问题
- 号称破解全网会员的脚本
- 资料笔记
- 资料笔记2
- 公司面试题
- 服务器相关
- 前端自动化部署-jenkins
- nginx.conf配置
- https添加证书
- shell基本命令
- 微型ssh-deploy前端部署插件
- webpack
- 深入理解loader
- 深入理解plugin
- webpack注意事项
- vite和webpack区别
- React
- react+antd搭建
- Vue
- vue-cli
- vue.config.js
- 面板分割左右拖动
- vvmily-admin-template
- v-if与v-for那个优先级高?
- 下载excel
- 导入excel
- Echart-China-Map
- vue-xlsx(解析excel)
- 给elementUI的el-table添加骨架
- cdn引入配置
- Vue2.x之defineProperty应用
- 彻底弄懂diff算法的key作用
- 复制模板内容
- 表格操作按钮太多
- element常用组件二次封装
- Vue3.x
- Vue3快速上手(第一天)
- Vue3.x快速上手(第二天)
- Vue3.x快速上手(第三天)
- vue3+element-plus搭建项目
- vue3
- 脚手架
- vvmily-cli
- TS
- ts笔记
- common
- Date
- utils
- axios封装
- 2022年
- HTML
- CSS基础
- JavaScript 基础
- 前端框架Vue
- 计算机网络
- 浏览器相关
- 性能优化
- js手写代码
- 前端安全
- 前端算法
- 前端构建与编译
- 操作系统
- Node.js
- 一些开放问题、智力题