## 前言
大家在做管理后臺系統的時候,是否有遇到操作按鈕太多(三個以上)的情況呢?如下圖

## 實現思路
* 總體利用插槽 `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`的使用,可[點擊前往](http://www.hmoore.net/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
- 一些開放問題、智力題