1. 程式人生 > 其它 >基於@vueuse/core + @vue/composition-api 實現多行元素展開/摺疊功能

基於@vueuse/core + @vue/composition-api 實現多行元素展開/摺疊功能

列表查詢是很常見的功能,複雜的系統模組會有很多查詢條件,預設只展示第一行查詢條件是個不錯的方案。

產品的方案是百變的,可能會讓你一行展示固定數目的查詢元件,也可能是根據螢幕寬度動態確定數量。

這個時候就很有必要來一個專門處理展開/摺疊功能的元件,專注於展開/摺疊功能。內部佈局用css控制就行了。

實現方案靈感來至於https://segmentfault.com/a/1190000040030723

基於vue2+ @vueuse/core + @vue/composition-api 實現

廢話不多說,直接上程式碼

  1 <template>
  2   <!-- 摺疊容器
  3        'is-collapse': isCollapse 根據isCollapse判斷是否應用摺疊樣式
4 --> 5 <div 6 ref="containerEl" 7 class="collapse-container" 8 :class="{ 9 'is-collapse': isCollapse, 10 'collapse-right-bottom': collapseInRightBottom 11 }" 12 > 13 <!-- 通過控制max-height來達到摺疊/展開的效果 --> 14 <div class="collapse-el" :class="isExpand ? 'expand' : ''"> 15
<!-- 利用css使摺疊組始終在最右側 --> 16 <div class="right-group box-row box-center-end"> 17 <slot name="prefix"></slot> 18 <div @click="isExpand = !isExpand"> 19 <slot v-if="isCollapse" name="collapse" v-bind="{ isExpand }"> 20 <el-button type="text" class="expand-btn"> 21
{{ isExpand ? '收起' : '展開' }} 22 <i 23 :class="isExpand ? 'el-icon-arrow-up' : 'el-icon-arrow-down'" 24 ></i> 25 </el-button> 26 </slot> 27 </div> 28 <slot name="suffix"></slot> 29 </div> 30 31 <!-- 摺疊面板 --> 32 <div ref="collapsePanel" class="panel-el"> 33 <slot></slot> 34 </div> 35 </div> 36 </div> 37 </template> 38 <script> 39 import { defineComponent, ref } from '@vue/composition-api'; 40 import { useElementSize, useCssVar } from '@vueuse/core'; 41 42 import { find } from 'lodash'; 43 /** 44 * 45 */ 46 export default defineComponent({ 47 name: 'UxCollapse', 48 props: { 49 // 是否預設展開 50 defaultExpand: { 51 type: Boolean, 52 default: false 53 }, 54 // 摺疊容器是否始終在右下角 55 collapseInRightBottom: { 56 type: Boolean, 57 default: true 58 } 59 }, 60 setup() { 61 // 動態獲取collapsePanel的高度 62 // 要監聽的元素必須是ref引用的元素 63 const collapsePanel = ref(null); 64 const { height } = useElementSize(collapsePanel); 65 66 // 支援js設定var變數 67 // var變數設定元素位置,必須是ref引用的元素 68 const containerEl = ref(null); 69 const maxHeight = useCssVar('--max-height', containerEl); 70 return { 71 collapsePanel, 72 height, 73 containerEl, 74 maxHeight 75 }; 76 }, 77 data() { 78 return { 79 // 是否開啟摺疊/展開功能(自動計算獲取) 80 isCollapse: false, 81 // 摺疊面板是否展開(isCollapse為true時生效) 82 isExpand: false 83 }; 84 }, 85 86 watch: { 87 height() { 88 // console.log('height', v); 89 // 高度變化時,重新計算是否開啟摺疊功能 90 this.adjustLayout(); 91 }, 92 isExpand(v) { 93 // 丟擲事件 94 this.$emit('expandchange', v); 95 } 96 }, 97 98 methods: { 99 /** 100 * @description 計算是否開啟摺疊/展開功能 101 */ 102 adjustLayout() { 103 const me = this; 104 me.$nextTick(() => { 105 // 獲取容器dom 106 const el = me.$el; 107 if (el) { 108 // 延遲執行保證獲取到子元素 109 setTimeout(() => { 110 // 獲取摺疊面對dom 111 const collapsePanel = me.$refs.collapsePanel; 112 const children = collapsePanel.children; 113 // 如果摺疊面板有子元素 114 if (children.length) { 115 // 獲取第一個元素的offsetTop 116 const firstOffsetTop = collapsePanel.firstChild.offsetTop; 117 // 獲取下一行第一個元素 118 const nextRowChild = find(children, (item) => { 119 return item.offsetTop > firstOffsetTop; 120 }); 121 // 如果找不到下一行第一個元素,說明無需摺疊 122 this.isCollapse = !!nextRowChild; 123 if (nextRowChild) { 124 // 用下一行第一個元素的offsetTop減去第一個元素的offsetTop就是每一行的高 125 const maxHeight = nextRowChild.offsetTop - firstOffsetTop; 126 // 設定css變數 127 this.maxHeight = maxHeight + 'px'; 128 // 設定預設展開狀態 129 this.isExpand = this.defaultExpand; 130 } 131 } 132 }); 133 } 134 }); 135 } 136 } 137 }); 138 </script> 139 <style scoped lang="scss"> 140 @import '~@/assets/sass/all.scss'; 141 142 // 開啟摺疊/展開功能後容器樣式 143 .is-collapse { 144 // flex佈局高度計算才能使用百分百 145 display: flex; 146 // 收起/展開按鈕 147 .expand-btn { 148 padding: 0; 149 } 150 } 151 .collapse-right-bottom { 152 .collapse-el { 153 // 偽類動態設定高度實現將摺疊組擠到最下方的效果 154 &::before { 155 content: ''; 156 height: calc(100% - var(--max-height)); 157 float: right; 158 } 159 } 160 } 161 162 // 摺疊容器 163 ::v-deep.collapse-container { 164 --max-height: none; 165 width: 100%; 166 .collapse-el { 167 width: 100%; 168 overflow: hidden; 169 // 通過設定最大高度來實現摺疊時只顯示一行的效果 170 max-height: var(--max-height); 171 &.expand { 172 // 展開狀態取消最大高度限制,實現展開效果 173 max-height: none; 174 } 175 } 176 .right-group { 177 line-height: var(--max-height); 178 // 保證摺疊組始終在最右方 179 float: right; 180 clear: both; 181 } 182 } 183 184 // 面板預設佈局 185 ::v-deep.panel-el { 186 .item-el { 187 display: inline-block; 188 } 189 } 190 </style>

用法如下:

 1 <uxCollapse>
 2   <div class="item-el">
 3     <el-form-item label="建單日期">
 4       <el-input></el-input>
 5     </el-form-item>
 6   </div>
 7   <div class="item-el">
 8     <el-form-item label="建單日期">
 9       <el-input></el-input>
10     </el-form-item>
11   </div>
12   <div class="item-el">
13     <el-form-item label="建單日期">
14       <el-input></el-input>
15     </el-form-item>
16   </div>
17   <div class="item-el">
18     <el-form-item label="建單日期">
19       <el-input></el-input>
20     </el-form-item>
21   </div>
22   <div class="item-el">
23     <el-form-item label="建單日期">
24       <el-input></el-input>
25     </el-form-item>
26   </div>
27   <div class="item-el">
28     <el-form-item label="建單日期">
29       <el-input></el-input>
30     </el-form-item>
31   </div>
32   <div class="item-el">
33     <el-form-item label="建單日期">
34       <el-input></el-input>
35     </el-form-item>
36   </div>
37 </uxCollapse>

每個子元素使用 display: inline-block; 佈局即可,通過css可靈活控制內部佈局。