100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Element-ui自定义组件:可折叠按钮列表

Element-ui自定义组件:可折叠按钮列表

时间:2021-06-19 13:02:43

相关推荐

Element-ui自定义组件:可折叠按钮列表

功能点

1、工具栏的功能按钮要超宽不换行,宽度不够折叠进”更多“按钮;

2、下拉菜单按钮和纯图标按钮默认不折叠;

3、折叠前后按钮组顺序保持不变。

实现思路

1、默认展开全量按钮,并对其宽度进行缓存;

2、循环计算展开按钮的总宽度 与 容器宽度 的差值,并进行按钮的折叠与释放处理;

3、监听窗口大小改变,不断进行步骤2;

4、难点:区分放大、缩小操作进行分别处理(当然也可以每次遍历全量按钮,这样只要考虑需要折叠的情况,这个比较简单,这里不展开说明)。

演示效果

index.vue

<template><el-container class="page-container"><el-header class="page-header"><h3 class="page-title">内页标题</h3><el-form :inline="true" :model="formInline" class="demo-form-inline"><el-form-item label="审批人"><el-input v-model="formInline.user" placeholder="审批人"></el-input></el-form-item><el-form-item label="活动区域"><el-select v-model="formInline.region" placeholder="活动区域"><el-option label="区域一" value="shanghai"></el-option><el-option label="区域二" value="beijing"></el-option></el-select></el-form-item><el-form-item><el-button type="primary" @click="onSubmit">查询</el-button></el-form-item></el-form></el-header><el-main class="page-body"><div class="table-conatainer"><div class="table-tools"><h4 class="table-title">表格标题</h4><div class="table-actions"><vp-button-list :data="buttonData"></vp-button-list></div></div><div class="table-body"><el-table :data="tableData" border stripe height="100%" max-height="100%"style="width: 100%;position: absolute;"><el-table-column prop="date" label="日期" width="180"></el-table-column><el-table-column prop="name" label="姓名" width="180"></el-table-column><el-table-column prop="address" label="地址"></el-table-column></el-table></div><el-pagination align="right" :current-page="currentPage" :page-sizes="[100, 200, 300, 400]" :page-size="100"layout="total, sizes, prev, pager, next, jumper" :total="400" background></el-pagination></div></el-main></el-container></template><script>export default {components: {VpButtonList: () => import('./vp-button-list.vue')},data() {return {formInline: {user: '',region: ''},buttonData: [{text: '按钮名称1',type: 'primary',},{text: '按钮名称2',type: 'primary',},{text: '按钮名称3',type: 'primary',},{text: '按钮名称4',type: 'primary',},{text: '按钮名称555555555555',type: 'primary',},{text: '按钮名称6',type: 'primary',},{text: '按钮名称777777777777',type: 'primary',},{text: '按钮名称8',type: 'primary',},{text: '按钮名称9999999999999',type: 'primary',},{text: '下拉菜单按钮',children: [{ text: '按钮一' },{ text: '按钮二' }],type: 'primary',},{icon: 'el-icon-d-arrow-left',type: 'primary',},{icon: 'el-icon-d-arrow-right',type: 'primary',}],tableData: [{date: '-05-02',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'},{date: '-05-04',name: '王小虎',address: '上海市普陀区金沙江路 1517 弄'},{date: '-05-01',name: '王小虎',address: '上海市普陀区金沙江路 1519 弄'},{date: '-05-03',name: '王小虎',address: '上海市普陀区金沙江路 1516 弄'}],currentPage: 1,}},methods: {onSubmit() {console.log('submit!');}}}</script><style lang="scss" scoped>.page-container {height: 100vh;.page-header {height: auto !important;.page-title {margin: 0 -20px 16px;padding: 16px;background: #409EFF;color: #fff;}}.page-body {background: #d5d9e4;display: flex;flex-direction: column;.table-conatainer {flex: 1;padding: 16px;background: #fff;display: flex;flex-direction: column;.table-tools {line-height: 40px;&::after {clear: both;content: "";display: block;height: 0;overflow: hidden;visibility: hidden;}.table-title {float: left;}.table-actions {float: right;}+.table-body {margin-top: 12px;}}.table-body {flex: 1;position: relative;}}}}</style>

vp-button-list.vue

<template><div class="vp-button-list"><!-- 展示的按钮 --><template v-for="(value, index) in expandedData"><el-dropdown v-if="value.children" :key="`dropdown-${index}`" :ref="`button-${index}`"><el-button v-bind="value"><template v-if="value.text">{{ value.text }}</template><i class="el-icon-arrow-down el-icon--right"></i></el-button><el-dropdown-menu slot="dropdown"><el-dropdown-item v-for="(val, idx) in value.childlren" :key="`dropdown-item-${idx}`">{{ val.text }}</el-dropdown-item></el-dropdown-menu></el-dropdown><el-button v-else :key="`button-${index}`" v-bind="value" :ref="`button-${index}`"><template v-if="value.text">{{ value.text }}</template></el-button></template><!-- 更多按钮 --><el-dropdown v-if="!rendered || buttonMoreShow" ref="button-more"><el-button v-bind="buttonMore"></el-button><el-dropdown-menu slot="dropdown"><el-dropdown-item v-for="(val, idx) in collapseData" :key="`dropdown-item-${idx}`">{{ val.text }}</el-dropdown-item></el-dropdown-menu></el-dropdown></div></template><script>import { throttle } from 'throttle-debounce';function getMargin(el, containOffsetWidth = true) {const style = el.currentStyle || window.getComputedStyle(el);let styleValue = ['marginLeft', 'marginRight'].map(item => parseInt(style[item]));if (containOffsetWidth) {styleValue.push(el.offsetWidth);}return styleValue.reduce((pre, curr) => pre + curr);}/*** 可折叠的按钮列表* @desc 监听窗口改变自动折叠按钮进“更多”* @author zhengvipin* @date /03/12 01:09*/export default {name: 'VpButtonList',componentName: 'VpButtonList',props: {data: {type: Array,default: () => []},// 组件所在的容器,基于此做宽度自适应计算container: {type: String,default: '.table-tools',require: true},// container下需要减去的占据空间的子类excluded: {type: Array,default: () => ['.table-title']},buttonMore: {type: Object,default: () => ({type: 'danger',icon: 'el-icon-more'})}},data() {return {expandedData: [],// 展开按钮数组collapseData: [],// 折叠按钮数组containerNode: null,// 容器节点excludedMargin: 0,// 可排除的间距actualWidthStack: [],// 展开按钮实际宽度历史栈devicePixelRatioStack: [],// 设备分辨率历史栈rendered: false,// 初始化标识}},computed: {buttonMoreShow() {return this.collapseData.length > 0; // 当折叠数组为空时,不展示“更多”按钮}},methods: {render() {// 1、存储容器domthis.containerNode = this.$el.closest(this.container);if (!this.containerNode) {// 容错:当 container 找不到时,默认把父节点当作容器this.containerNode = this.$el.parentNode;}// 2、计算可排除间距let excludedMargin = 0;if (this.excluded.length > 0) { // 子节点for (let tag of this.excluded) {const tagNode = this.containerNode.querySelector(tag);if (tagNode) {excludedMargin += getMargin(tagNode);}}}excludedMargin += getMargin(this.$el, false); // 组件本身excludedMargin += getMargin(this.$refs['button-more'].$el);// “更多”按钮this.excludedMargin = excludedMargin;// 3、补充按钮宽度let actualWidth = 0;this.expandedData.forEach((item, index) => {let buttonWidth = getMargin(this.$refs[`button-${index}`][0].$el);item.width = buttonWidth;actualWidth += buttonWidth;})// 4、初始化设备像素比队列,用于判断滚动监听时是放大还是缩小this.devicePixelRatioStack.push(window.devicePixelRatio);// 5、初始化可视按钮实际宽度队列,用于计算滚动监听后变动的差值this.actualWidthStack.push(actualWidth);// 6、初始化完毕this.rendered = true;},// todo: 还有个点可以优化,就是当更多按钮不出现时,可视区按钮宽度刚好不超宽,这种情况也要考虑~~~后续再处理~~onResize() {const expectedWidth = this.containerNode.clientWidth - this.excludedMargin;// 展开按钮期望宽度let actualWidth = this.actualWidthStack[this.actualWidthStack.length - 1]; // 展开按钮实际宽度let devicePixelRatio = window.devicePixelRatio;const scaleUp = devicePixelRatio - this.devicePixelRatioStack[this.devicePixelRatioStack.length - 1] >= 0;// 初始加载的时候也是考虑折叠情况let button;if (scaleUp) {// 放大:展开数据从右往左依次折叠按钮console.log('scaleUp');let i = this.expandedData.length - 1;while (actualWidth > expectedWidth) {// 如果超宽就折叠button = this.expandedData[i];// 提前声明,用于跳过特定按钮let { alwaysShow, width } = button;if (!alwaysShow) {// 纯图标按钮和下拉菜单按钮不折叠this.expandedData.splice(i, 1);this.collapseData.unshift(button);actualWidth -= width;}i--;}} else {// 缩小:折叠数组从左往右依次释放按钮console.log('scaleDown');while (this.collapseData.length > 0 && actualWidth < expectedWidth) {// 如果有折叠按钮且宽度没铺满就释放button = this.collapseData[0];// 提前声明,用于超宽回退let { width, order } = button;if (actualWidth + width > expectedWidth) break;this.collapseData.shift();this.expandedData.splice(order, 0, button);// 释放后要对展开数组重新排下序actualWidth += width;}}this.devicePixelRatioStack.push(devicePixelRatio);this.actualWidthStack.push(actualWidth);}},created() {this.expandedData = this.data.map((item, order) => {return {alwaysShow: !!(item.children || (item.icon && !item.text)),...item,order}});// 初始化默认展开所有按钮,用于缓存宽度},mounted() {this.render();this.onResize();this.throttleResizeHandler = throttle(50, this.onResize);// 加了节流,缩放窗口速度过快会有个闪烁的情况,可以酌情考虑加不加window.addEventListener('resize', this.throttleResizeHandler)},beforeDestroy() {window.removeEventListener('resize', this.throttleResizeHandler)}}</script><style lang="scss" scoped>.el-dropdown+.el-button,.el-dropdown+.el-dropdown,.el-button+.el-dropdown {margin-left: 10px;}</style>

PS:如果这篇博客能对您提供一点点的帮助,烦请一键三连,给博主提供更新动力o(* ̄▽ ̄*)ブ。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。