uview-plus 3.4.27 → 3.4.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +24 -0
- package/components/u-cate-tab/u-cate-tab.vue +20 -14
- package/components/u-image/u-image.vue +7 -4
- package/components/u-index-list/u-index-list.vue +1 -1
- package/components/u-number-box/u-number-box.vue +4 -3
- package/components/u-table/u-table.vue +77 -3
- package/components/u-table2/u-table2.vue +474 -0
- package/components/u-tag/props.js +5 -0
- package/components/u-td/u-td.vue +42 -4
- package/components/u-th/props.js +7 -0
- package/components/u-th/u-th.vue +67 -0
- package/components/u-tr/u-tr.vue +4 -2
- package/index.js +3 -1
- package/package.json +1 -1
package/changelog.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
## 3.4.29(2025-05-15)
|
|
2
|
+
fix: 修复table2横向滚动样式
|
|
3
|
+
|
|
4
|
+
fix: 修复table2组件宽度兼容
|
|
5
|
+
|
|
6
|
+
fix: 修复image显示png图片时默认背景色问题
|
|
7
|
+
|
|
8
|
+
feat: cate-tab新增height参数便于设置组件高度
|
|
9
|
+
|
|
10
|
+
feat: 在index.js种导出digit.js便于使用
|
|
11
|
+
|
|
12
|
+
fix: 修复tag组件缺失iconColor属性
|
|
13
|
+
|
|
14
|
+
fix: 优化index-list的setValueForTouch方法逻辑 #708
|
|
15
|
+
|
|
16
|
+
feat: number-box支持change事件返回变动是点击了增加还是减少按钮
|
|
17
|
+
|
|
18
|
+
fix: 修复table2在小程序下部分情形不显示表格
|
|
19
|
+
|
|
20
|
+
## 3.4.28(2025-05-12)
|
|
21
|
+
feat: 新增table表格组件
|
|
22
|
+
|
|
23
|
+
feat: 新增element-plus风格的table2组件
|
|
24
|
+
|
|
1
25
|
## 3.4.27(2025-05-06)
|
|
2
26
|
fix: 修复card组件props
|
|
3
27
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<view class="u-cate-tab">
|
|
2
|
+
<view class="u-cate-tab" :style="{ height: addUnit(height) }">
|
|
3
3
|
<view class="u-cate-tab__wrap">
|
|
4
4
|
<scroll-view class="u-cate-tab__view u-cate-tab__menu-scroll-view"
|
|
5
5
|
scroll-y scroll-with-animation :scroll-top="scrollTop"
|
|
@@ -41,9 +41,14 @@
|
|
|
41
41
|
</view>
|
|
42
42
|
</template>
|
|
43
43
|
<script>
|
|
44
|
+
import { addUnit } from '../../libs/function/index';
|
|
44
45
|
export default {
|
|
45
46
|
name: 'up-cate-tab',
|
|
46
47
|
props: {
|
|
48
|
+
height: {
|
|
49
|
+
type: String,
|
|
50
|
+
default: '100%'
|
|
51
|
+
},
|
|
47
52
|
tabList: {
|
|
48
53
|
type: Array,
|
|
49
54
|
default: () => {
|
|
@@ -57,7 +62,7 @@
|
|
|
57
62
|
itemKeyName: {
|
|
58
63
|
type: String,
|
|
59
64
|
default: 'name'
|
|
60
|
-
},
|
|
65
|
+
},
|
|
61
66
|
current: {
|
|
62
67
|
type: Number,
|
|
63
68
|
default: 0
|
|
@@ -67,7 +72,7 @@
|
|
|
67
72
|
tabList() {
|
|
68
73
|
this.getMenuItemTop()
|
|
69
74
|
}
|
|
70
|
-
},
|
|
75
|
+
},
|
|
71
76
|
emits: ['update:current'],
|
|
72
77
|
data() {
|
|
73
78
|
return {
|
|
@@ -84,18 +89,19 @@
|
|
|
84
89
|
timer: null, // 定时器
|
|
85
90
|
}
|
|
86
91
|
},
|
|
87
|
-
onMounted() {
|
|
88
|
-
this.innerCurrent = this.current;
|
|
92
|
+
onMounted() {
|
|
93
|
+
this.innerCurrent = this.current;
|
|
89
94
|
this.leftMenuStatus(this.innerCurrent);
|
|
90
95
|
this.getMenuItemTop()
|
|
91
|
-
},
|
|
92
|
-
watch: {
|
|
93
|
-
current(nval) {
|
|
94
|
-
this.innerCurrent = nval;
|
|
95
|
-
this.leftMenuStatus(this.innerCurrent);
|
|
96
|
-
}
|
|
96
|
+
},
|
|
97
|
+
watch: {
|
|
98
|
+
current(nval) {
|
|
99
|
+
this.innerCurrent = nval;
|
|
100
|
+
this.leftMenuStatus(this.innerCurrent);
|
|
101
|
+
}
|
|
97
102
|
},
|
|
98
103
|
methods: {
|
|
104
|
+
addUnit,
|
|
99
105
|
// 点击左边的栏目切换
|
|
100
106
|
async swichMenu(index) {
|
|
101
107
|
if(this.arr.length == 0) {
|
|
@@ -106,7 +112,7 @@
|
|
|
106
112
|
this.$nextTick(function(){
|
|
107
113
|
this.scrollRightTop = this.arr[index];
|
|
108
114
|
this.innerCurrent = index;
|
|
109
|
-
this.leftMenuStatus(index);
|
|
115
|
+
this.leftMenuStatus(index);
|
|
110
116
|
this.$emit('update:current', index);
|
|
111
117
|
})
|
|
112
118
|
},
|
|
@@ -140,14 +146,14 @@
|
|
|
140
146
|
}).observe('#item' + index, res => {
|
|
141
147
|
if (res.intersectionRatio > 0) {
|
|
142
148
|
let id = res.id.substring(4);
|
|
143
|
-
this.leftMenuStatus(id);
|
|
149
|
+
this.leftMenuStatus(id);
|
|
144
150
|
}
|
|
145
151
|
})
|
|
146
152
|
})
|
|
147
153
|
},
|
|
148
154
|
// 设置左边菜单的滚动状态
|
|
149
155
|
async leftMenuStatus(index) {
|
|
150
|
-
this.innerCurrent = index;
|
|
156
|
+
this.innerCurrent = index;
|
|
151
157
|
this.$emit('update:current', index);
|
|
152
158
|
// 如果为0,意味着尚未初始化
|
|
153
159
|
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
|
|
@@ -45,7 +45,10 @@
|
|
|
45
45
|
v-if="showError && isError && !loading"
|
|
46
46
|
class="u-image__error"
|
|
47
47
|
:style="{
|
|
48
|
-
borderRadius: shape == 'circle' ? '50%' : addUnit(radius)
|
|
48
|
+
borderRadius: shape == 'circle' ? '50%' : addUnit(radius),
|
|
49
|
+
backgroundColor: this.bgColor,
|
|
50
|
+
width: addUnit(width),
|
|
51
|
+
height: addUnit(height)
|
|
49
52
|
}"
|
|
50
53
|
>
|
|
51
54
|
<slot name="error">
|
|
@@ -220,9 +223,9 @@
|
|
|
220
223
|
// 移除图片的背景色
|
|
221
224
|
removeBgColor() {
|
|
222
225
|
// 淡入动画过渡完成后,将背景设置为透明色,否则png图片会看到灰色的背景
|
|
223
|
-
this.backgroundStyle = {
|
|
224
|
-
|
|
225
|
-
};
|
|
226
|
+
// this.backgroundStyle = {
|
|
227
|
+
// backgroundColor: this.bgColor || '#ffffff'
|
|
228
|
+
// };
|
|
226
229
|
}
|
|
227
230
|
}
|
|
228
231
|
};
|
|
@@ -419,7 +419,7 @@
|
|
|
419
419
|
return child
|
|
420
420
|
})
|
|
421
421
|
// console.log('this.children[currentIndex].top', children[currentIndex].top)
|
|
422
|
-
if (children[currentIndex]?.top) {
|
|
422
|
+
if (children[currentIndex]?.top || children[currentIndex].top === 0) {
|
|
423
423
|
this.scrollTop = children[currentIndex].top - getPx(customNavHeight)
|
|
424
424
|
}
|
|
425
425
|
// #endif
|
|
@@ -331,8 +331,8 @@
|
|
|
331
331
|
// #endif
|
|
332
332
|
|
|
333
333
|
},
|
|
334
|
-
// 发出change
|
|
335
|
-
emitChange(value) {
|
|
334
|
+
// 发出change事件,type目前只支持点击时有值,手动输入不支持。
|
|
335
|
+
emitChange(value, type = '') {
|
|
336
336
|
// 如果开启了异步变更值,则不修改内部的值,需要用户手动在外部通过v-model变更
|
|
337
337
|
if (!this.asyncChange) {
|
|
338
338
|
this.$nextTick(() => {
|
|
@@ -349,6 +349,7 @@
|
|
|
349
349
|
this.$emit('change', {
|
|
350
350
|
value,
|
|
351
351
|
name: this.name,
|
|
352
|
+
type: type // 当前变更类型
|
|
352
353
|
});
|
|
353
354
|
},
|
|
354
355
|
onChange() {
|
|
@@ -360,7 +361,7 @@
|
|
|
360
361
|
}
|
|
361
362
|
const diff = type === 'minus' ? -this.step : +this.step
|
|
362
363
|
const value = this.format(this.add(+this.currentValue, diff))
|
|
363
|
-
this.emitChange(value)
|
|
364
|
+
this.emitChange(value, type)
|
|
364
365
|
this.$emit(type)
|
|
365
366
|
},
|
|
366
367
|
// 对值扩大后进行四舍五入,再除以扩大因子,避免出现浮点数操作的精度问题
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<view class="u-table">
|
|
3
|
-
|
|
2
|
+
<view class="u-table" :style="[tableStyle]">
|
|
3
|
+
<template v-if="show">
|
|
4
|
+
<slot />
|
|
5
|
+
</template>
|
|
4
6
|
</view>
|
|
5
7
|
</template>
|
|
6
8
|
|
|
@@ -12,14 +14,86 @@
|
|
|
12
14
|
* Table 表格
|
|
13
15
|
* @description 表格组件一般用于展示大量结构化数据的场景 本组件标签类似HTML的table表格,由table、tr、th、td四个组件组成
|
|
14
16
|
* @tutorial https://ijry.github.io/uview-plus/components/table.html
|
|
17
|
+
* @property {String} border-color 表格边框的颜色(默认#e4e7ed)
|
|
18
|
+
* @property {String} bg-color 表格的背景颜色(默认#ffffff)
|
|
19
|
+
* @property {String} align 单元格的内容对齐方式,作用类似css的text-align(默认center)
|
|
20
|
+
* @property {String} padding 单元格的内边距,同css的padding写法(默认10rpx 0)
|
|
21
|
+
* @property {String Number} font-size 单元格字体大小,单位rpx(默认28)
|
|
22
|
+
* @property {String} color 单元格字体颜色(默认#606266)
|
|
23
|
+
* @property {Object} th-style th单元格的样式,对象形式(将th所需参数放在table组件,是为了避免每一个th组件要写一遍)
|
|
24
|
+
* @event {Function} click 点击组件时触发
|
|
25
|
+
* @event {Function} close 点击关闭按钮时触发
|
|
15
26
|
* @example <u-table><u-tr><u-th>学校</u-th </u-tr> <u-tr><u-td>浙江大学</u-td> </u-tr> <u-tr><u-td>清华大学</u-td> </u-tr></u-table>
|
|
16
27
|
*/
|
|
17
28
|
export default {
|
|
18
29
|
name: 'u-table',
|
|
19
30
|
mixins: [mpMixin, mixin, props],
|
|
31
|
+
props: {
|
|
32
|
+
borderColor: {
|
|
33
|
+
type: String,
|
|
34
|
+
default: '#e4e7ed'
|
|
35
|
+
},
|
|
36
|
+
align: {
|
|
37
|
+
type: String,
|
|
38
|
+
default: 'center'
|
|
39
|
+
},
|
|
40
|
+
// td的内边距
|
|
41
|
+
padding: {
|
|
42
|
+
type: String,
|
|
43
|
+
default: '5px 3px'
|
|
44
|
+
},
|
|
45
|
+
// 字体大小
|
|
46
|
+
fontSize: {
|
|
47
|
+
type: [String],
|
|
48
|
+
default: '14px'
|
|
49
|
+
},
|
|
50
|
+
// 字体颜色
|
|
51
|
+
color: {
|
|
52
|
+
type: String,
|
|
53
|
+
default: '#606266'
|
|
54
|
+
},
|
|
55
|
+
// th的自定义样式
|
|
56
|
+
thStyle: {
|
|
57
|
+
type: Object,
|
|
58
|
+
default () {
|
|
59
|
+
return {}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
// table的背景颜色
|
|
63
|
+
bgColor: {
|
|
64
|
+
type: String,
|
|
65
|
+
default: '#ffffff'
|
|
66
|
+
}
|
|
67
|
+
},
|
|
20
68
|
data() {
|
|
21
69
|
return {
|
|
22
|
-
|
|
70
|
+
show: true
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
watch: {
|
|
74
|
+
align() {
|
|
75
|
+
this.change();
|
|
76
|
+
},
|
|
77
|
+
borderColor() {
|
|
78
|
+
this.change();
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
computed: {
|
|
82
|
+
tableStyle() {
|
|
83
|
+
let style = {};
|
|
84
|
+
style.borderLeft = `solid 1px ${this.borderColor}`;
|
|
85
|
+
style.borderTop = `solid 1px ${this.borderColor}`;
|
|
86
|
+
style.backgroundColor = this.bgColor;;
|
|
87
|
+
return style;
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
methods: {
|
|
91
|
+
change() {
|
|
92
|
+
this.show = false;
|
|
93
|
+
this.$nextTick(() => {
|
|
94
|
+
this.show = true;
|
|
95
|
+
});
|
|
96
|
+
// this.$forceUpdate();
|
|
23
97
|
}
|
|
24
98
|
}
|
|
25
99
|
}
|
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view scroll-x class="u-table2" :style="{ height: height ? height + 'px' : 'auto' }">
|
|
3
|
+
<!-- 表头 -->
|
|
4
|
+
<view v-if="showHeader" class="u-table-header" :class="{ 'u-table-sticky': fixedHeader }" :style="{minWidth: scrollWidth}">
|
|
5
|
+
<view class="u-table-row">
|
|
6
|
+
<view v-for="(col, colIndex) in columns" :key="col.key" class="u-table-cell"
|
|
7
|
+
:style="{ width: col.width ? addUnit(col.width) : 'auto', flex: col.width ? 'none' : 1 }" :class="[
|
|
8
|
+
col.align ? 'u-text-' + col.align : '',
|
|
9
|
+
headerCellClassName ? headerCellClassName(col) : '',
|
|
10
|
+
col.fixed === 'left' ? 'u-table-fixed-left' : '',
|
|
11
|
+
col.fixed === 'right' ? 'u-table-fixed-right' : ''
|
|
12
|
+
]" @click="handleHeaderClick(col)">
|
|
13
|
+
{{ col.title }}
|
|
14
|
+
<view v-if="col.sortable">
|
|
15
|
+
{{ getSortIcon(col.key) }}
|
|
16
|
+
</view>
|
|
17
|
+
</view>
|
|
18
|
+
</view>
|
|
19
|
+
</view>
|
|
20
|
+
|
|
21
|
+
<!-- 表体 -->
|
|
22
|
+
<view class="u-table-body" :style="{ minWidth: scrollWidth, maxHeight: maxHeight ? maxHeight + 'px' : 'none' }">
|
|
23
|
+
<template v-if="data && data.length > 0">
|
|
24
|
+
<template v-for="(row, index) in sortedData" :key="row[rowKey] || index">
|
|
25
|
+
<view class="u-table-row" :class="[
|
|
26
|
+
highlightCurrentRow && currentRow === row ? 'u-table-row-highlight' : '',
|
|
27
|
+
rowClassName ? rowClassName(row, index) : '',
|
|
28
|
+
stripe && index % 2 === 1 ? 'u-table-row-zebra' : ''
|
|
29
|
+
]" @click="handleRowClick(row)">
|
|
30
|
+
<view v-for="(col, colIndex) in columns" :key="col.key" class="u-table-cell" :class="[
|
|
31
|
+
col.align ? 'u-text-' + col.align : '',
|
|
32
|
+
cellClassName ? cellClassName(row, col) : '',
|
|
33
|
+
col.fixed === 'left' ? 'u-table-fixed-left' : '',
|
|
34
|
+
col.fixed === 'right' ? 'u-table-fixed-right' : ''
|
|
35
|
+
]" :style="{ width: col.width ? addUnit(col.width) : 'auto', flex: col.width ? 'none' : 1 }">
|
|
36
|
+
<!-- 复选框列 -->
|
|
37
|
+
<view v-if="col.type === 'selection'">
|
|
38
|
+
<checkbox :checked="isSelected(row)" @click.stop="toggleSelect(row)" />
|
|
39
|
+
</view>
|
|
40
|
+
|
|
41
|
+
<!-- 树形结构展开图标 -->
|
|
42
|
+
<view v-else-if="col.type === 'expand'" @click.stop="toggleExpand(row)">
|
|
43
|
+
{{ isExpanded(row) ? '▼' : '▶' }}
|
|
44
|
+
</view>
|
|
45
|
+
|
|
46
|
+
<!-- 默认插槽或文本 -->
|
|
47
|
+
<slot name="cell" :row="row" :col="col">
|
|
48
|
+
<view class="u-table-cell_content">
|
|
49
|
+
{{ row[col.key] }}
|
|
50
|
+
</view>
|
|
51
|
+
</slot>
|
|
52
|
+
</view>
|
|
53
|
+
</view>
|
|
54
|
+
|
|
55
|
+
<!-- 子级渲染 -->
|
|
56
|
+
<template v-if="isExpanded(row) && row[treeProps.children] && row[treeProps.children].length">
|
|
57
|
+
<view v-for="child in row[treeProps.children]" :key="child[rowKey]"
|
|
58
|
+
class="u-table-row u-table-row-child">
|
|
59
|
+
<view v-for="col in columns" :key="col.key" class="u-table-cell"
|
|
60
|
+
:style="{ width: col.width ? addUnit(col.width) : 'auto', paddingLeft: '24px', flex: col.width ? 'none' : 1 }">
|
|
61
|
+
<slot name="cell" :row="child" :col="col">
|
|
62
|
+
<view class="u-table-cell_content">
|
|
63
|
+
{{ child[col.key] }}
|
|
64
|
+
</view>
|
|
65
|
+
</slot>
|
|
66
|
+
</view>
|
|
67
|
+
</view>
|
|
68
|
+
</template>
|
|
69
|
+
</template>
|
|
70
|
+
</template>
|
|
71
|
+
<template v-else>
|
|
72
|
+
<slot name="empty">
|
|
73
|
+
<view class="u-table-empty">{{ emptyText }}</view>
|
|
74
|
+
</slot>
|
|
75
|
+
</template>
|
|
76
|
+
</view>
|
|
77
|
+
</view>
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<script>
|
|
81
|
+
import { ref, watch, computed } from 'vue'
|
|
82
|
+
import { addUnit, sleep } from '../../libs/function/index';
|
|
83
|
+
|
|
84
|
+
export default {
|
|
85
|
+
name: 'u-table2',
|
|
86
|
+
props: {
|
|
87
|
+
data: {
|
|
88
|
+
type: Array,
|
|
89
|
+
required: true,
|
|
90
|
+
default: () => {
|
|
91
|
+
return []
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
columns: {
|
|
95
|
+
type: Array,
|
|
96
|
+
required: true,
|
|
97
|
+
default: () => {
|
|
98
|
+
return []
|
|
99
|
+
},
|
|
100
|
+
validator: cols =>
|
|
101
|
+
cols.every(col =>
|
|
102
|
+
['default', 'selection', 'expand'].includes(col.type || 'default')
|
|
103
|
+
)
|
|
104
|
+
},
|
|
105
|
+
stripe: {
|
|
106
|
+
type: Boolean,
|
|
107
|
+
default: false
|
|
108
|
+
},
|
|
109
|
+
border: {
|
|
110
|
+
type: Boolean,
|
|
111
|
+
default: false
|
|
112
|
+
},
|
|
113
|
+
height: {
|
|
114
|
+
type: [String, Number],
|
|
115
|
+
default: null
|
|
116
|
+
},
|
|
117
|
+
maxHeight: {
|
|
118
|
+
type: [String, Number],
|
|
119
|
+
default: null
|
|
120
|
+
},
|
|
121
|
+
showHeader: {
|
|
122
|
+
type: Boolean,
|
|
123
|
+
default: true
|
|
124
|
+
},
|
|
125
|
+
highlightCurrentRow: {
|
|
126
|
+
type: Boolean,
|
|
127
|
+
default: false
|
|
128
|
+
},
|
|
129
|
+
rowKey: {
|
|
130
|
+
type: String,
|
|
131
|
+
default: 'id'
|
|
132
|
+
},
|
|
133
|
+
currentRowKey: {
|
|
134
|
+
type: [String, Number],
|
|
135
|
+
default: null
|
|
136
|
+
},
|
|
137
|
+
rowStyle: {
|
|
138
|
+
type: Object,
|
|
139
|
+
default: () => ({})
|
|
140
|
+
},
|
|
141
|
+
cellClassName: {
|
|
142
|
+
type: Function,
|
|
143
|
+
default: null
|
|
144
|
+
},
|
|
145
|
+
headerCellClassName: {
|
|
146
|
+
type: Function,
|
|
147
|
+
default: null
|
|
148
|
+
},
|
|
149
|
+
rowClassName: {
|
|
150
|
+
type: Function,
|
|
151
|
+
default: null
|
|
152
|
+
},
|
|
153
|
+
context: {
|
|
154
|
+
type: Object,
|
|
155
|
+
default: null
|
|
156
|
+
},
|
|
157
|
+
showOverflowTooltip: {
|
|
158
|
+
type: Boolean,
|
|
159
|
+
default: false
|
|
160
|
+
},
|
|
161
|
+
lazy: {
|
|
162
|
+
type: Boolean,
|
|
163
|
+
default: false
|
|
164
|
+
},
|
|
165
|
+
load: {
|
|
166
|
+
type: Function,
|
|
167
|
+
default: null
|
|
168
|
+
},
|
|
169
|
+
treeProps: {
|
|
170
|
+
type: Object,
|
|
171
|
+
default: () => ({
|
|
172
|
+
children: 'children',
|
|
173
|
+
hasChildren: 'hasChildren'
|
|
174
|
+
})
|
|
175
|
+
},
|
|
176
|
+
defaultExpandAll: {
|
|
177
|
+
type: Boolean,
|
|
178
|
+
default: false
|
|
179
|
+
},
|
|
180
|
+
expandRowKeys: {
|
|
181
|
+
type: Array,
|
|
182
|
+
default: () => []
|
|
183
|
+
},
|
|
184
|
+
sortOrders: {
|
|
185
|
+
type: Array,
|
|
186
|
+
default: () => ['ascending', 'descending']
|
|
187
|
+
},
|
|
188
|
+
sortable: {
|
|
189
|
+
type: [Boolean, String],
|
|
190
|
+
default: false
|
|
191
|
+
},
|
|
192
|
+
multiSort: {
|
|
193
|
+
type: Boolean,
|
|
194
|
+
default: false
|
|
195
|
+
},
|
|
196
|
+
sortBy: {
|
|
197
|
+
type: String,
|
|
198
|
+
default: null
|
|
199
|
+
},
|
|
200
|
+
sortMethod: {
|
|
201
|
+
type: Function,
|
|
202
|
+
default: null
|
|
203
|
+
},
|
|
204
|
+
filters: {
|
|
205
|
+
type: Object,
|
|
206
|
+
default: () => ({})
|
|
207
|
+
},
|
|
208
|
+
fixedHeader: {
|
|
209
|
+
type: Boolean,
|
|
210
|
+
default: true
|
|
211
|
+
},
|
|
212
|
+
emptyText: {
|
|
213
|
+
type: String,
|
|
214
|
+
default: '暂无数据'
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
emits: [
|
|
218
|
+
'select', 'select-all', 'selection-change',
|
|
219
|
+
'cell-click', 'row-click', 'row-dblclick',
|
|
220
|
+
'header-click', 'sort-change', 'filter-change',
|
|
221
|
+
'current-change', 'expand-change'
|
|
222
|
+
],
|
|
223
|
+
data() {
|
|
224
|
+
return {
|
|
225
|
+
scrollWidth: 'auto'
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
mounted() {
|
|
229
|
+
this.getComponentWidth()
|
|
230
|
+
},
|
|
231
|
+
methods: {
|
|
232
|
+
addUnit,
|
|
233
|
+
// 获取组件的宽度
|
|
234
|
+
async getComponentWidth() {
|
|
235
|
+
// 延时一定时间,以获取dom尺寸
|
|
236
|
+
await sleep(30)
|
|
237
|
+
this.$uGetRect('.u-table-row').then(size => {
|
|
238
|
+
this.scrollWidth = size.width + 'px'
|
|
239
|
+
})
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
setup(props, { emit }) {
|
|
243
|
+
const expandedKeys = ref([...props.expandRowKeys]);
|
|
244
|
+
const selectedRows = ref([]);
|
|
245
|
+
const sortConditions = ref([]);
|
|
246
|
+
|
|
247
|
+
// 当前高亮行
|
|
248
|
+
const currentRow = ref(null);
|
|
249
|
+
|
|
250
|
+
watch(
|
|
251
|
+
() => props.expandRowKeys,
|
|
252
|
+
newVal => {
|
|
253
|
+
expandedKeys.value = [...newVal];
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
watch(
|
|
258
|
+
() => props.currentRowKey,
|
|
259
|
+
newVal => {
|
|
260
|
+
const found = props.data.find(item => item[props.rowKey] === newVal);
|
|
261
|
+
if (found) {
|
|
262
|
+
currentRow.value = found;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
// 过滤后的数据
|
|
268
|
+
const filteredData = computed(() => {
|
|
269
|
+
return props.data.filter(row => {
|
|
270
|
+
return Object.keys(props.filters).every(key => {
|
|
271
|
+
const filter = props.filters[key];
|
|
272
|
+
if (!filter) return true;
|
|
273
|
+
return row[key]?.toString().includes(filter.toString());
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// 排序后的数据
|
|
279
|
+
const sortedData = computed(() => {
|
|
280
|
+
if (!sortConditions.value.length) return filteredData.value;
|
|
281
|
+
|
|
282
|
+
const data = [...filteredData.value];
|
|
283
|
+
|
|
284
|
+
return data.sort((a, b) => {
|
|
285
|
+
for (const condition of sortConditions.value) {
|
|
286
|
+
const { field, order } = condition;
|
|
287
|
+
let valA = a[field];
|
|
288
|
+
let valB = b[field];
|
|
289
|
+
|
|
290
|
+
if (props.sortMethod) {
|
|
291
|
+
const result = props.sortMethod(a, b, field);
|
|
292
|
+
if (result !== 0) return result * (order === 'ascending' ? 1 : -1);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (valA < valB) return order === 'ascending' ? -1 : 1;
|
|
296
|
+
if (valA > valB) return order === 'ascending' ? 1 : -1;
|
|
297
|
+
}
|
|
298
|
+
return 0;
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
function handleRowClick(row) {
|
|
303
|
+
if (props.highlightCurrentRow) {
|
|
304
|
+
const oldRow = currentRow.value;
|
|
305
|
+
currentRow.value = row;
|
|
306
|
+
emit('current-change', row, oldRow);
|
|
307
|
+
}
|
|
308
|
+
emit('row-click', row);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function handleHeaderClick(column) {
|
|
312
|
+
if (!column.sortable) return;
|
|
313
|
+
|
|
314
|
+
const index = sortConditions.value.findIndex(c => c.field === column.key);
|
|
315
|
+
let newOrder = 'ascending';
|
|
316
|
+
|
|
317
|
+
if (index >= 0) {
|
|
318
|
+
if (sortConditions.value[index].order === 'ascending') {
|
|
319
|
+
newOrder = 'descending';
|
|
320
|
+
} else {
|
|
321
|
+
sortConditions.value.splice(index, 1);
|
|
322
|
+
emit('sort-change', sortConditions.value);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (!props.multiSort) {
|
|
328
|
+
sortConditions.value = [{ field: column.key, order: newOrder }];
|
|
329
|
+
} else {
|
|
330
|
+
if (index >= 0) {
|
|
331
|
+
sortConditions.value[index].order = newOrder;
|
|
332
|
+
} else {
|
|
333
|
+
sortConditions.value.push({ field: column.key, order: newOrder });
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
emit('sort-change', sortConditions.value);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function getSortIcon(field) {
|
|
341
|
+
const cond = sortConditions.value.find(c => c.field === field);
|
|
342
|
+
if (!cond) return '';
|
|
343
|
+
return cond.order === 'ascending' ? '↑' : '↓';
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function toggleSelect(row) {
|
|
347
|
+
const index = selectedRows.value.findIndex(r => r[props.rowKey] === row[props.rowKey]);
|
|
348
|
+
if (index >= 0) {
|
|
349
|
+
selectedRows.value.splice(index, 1);
|
|
350
|
+
} else {
|
|
351
|
+
selectedRows.value.push(row);
|
|
352
|
+
}
|
|
353
|
+
emit('selection-change', selectedRows.value);
|
|
354
|
+
emit('select', row);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function isSelected(row) {
|
|
358
|
+
return selectedRows.value.some(r => r[props.rowKey] === row[props.rowKey]);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function toggleExpand(row) {
|
|
362
|
+
const key = row[props.rowKey];
|
|
363
|
+
const index = expandedKeys.value.indexOf(key);
|
|
364
|
+
if (index === -1) {
|
|
365
|
+
expandedKeys.value.push(key);
|
|
366
|
+
} else {
|
|
367
|
+
expandedKeys.value.splice(index, 1);
|
|
368
|
+
}
|
|
369
|
+
emit('expand-change', expandedKeys.value);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function isExpanded(row) {
|
|
373
|
+
return expandedKeys.value.includes(row[props.rowKey]);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
currentRow,
|
|
378
|
+
sortedData,
|
|
379
|
+
expandedKeys,
|
|
380
|
+
selectedRows,
|
|
381
|
+
sortConditions,
|
|
382
|
+
handleRowClick,
|
|
383
|
+
handleHeaderClick,
|
|
384
|
+
getSortIcon,
|
|
385
|
+
toggleSelect,
|
|
386
|
+
isSelected,
|
|
387
|
+
toggleExpand,
|
|
388
|
+
isExpanded
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
</script>
|
|
393
|
+
|
|
394
|
+
<style lang="scss" scoped>
|
|
395
|
+
.u-table2 {
|
|
396
|
+
width: auto;
|
|
397
|
+
overflow: auto;
|
|
398
|
+
white-space: nowrap;
|
|
399
|
+
|
|
400
|
+
.u-table-header {
|
|
401
|
+
min-width: 100% !important;
|
|
402
|
+
width: fit-content;
|
|
403
|
+
background-color: #f5f7fa;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.u-table-body {
|
|
407
|
+
min-width: 100% !important;
|
|
408
|
+
width: fit-content;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.u-table-sticky {
|
|
412
|
+
position: sticky;
|
|
413
|
+
top: 0;
|
|
414
|
+
z-index: 10;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.u-table-row {
|
|
418
|
+
display: flex;
|
|
419
|
+
flex-direction: row;
|
|
420
|
+
align-items: center;
|
|
421
|
+
border-bottom: 1rpx solid #ebeef5;
|
|
422
|
+
overflow: hidden;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.u-table-cell {
|
|
426
|
+
flex: 1;
|
|
427
|
+
display: flex;
|
|
428
|
+
flex-direction: row;
|
|
429
|
+
padding: 5px 4px;
|
|
430
|
+
font-size: 14px;
|
|
431
|
+
white-space: nowrap;
|
|
432
|
+
overflow: hidden;
|
|
433
|
+
text-overflow: ellipsis;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.u-table-fixed-left {
|
|
437
|
+
position: sticky;
|
|
438
|
+
left: 0;
|
|
439
|
+
z-index: 9;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.u-table-fixed-right {
|
|
443
|
+
position: sticky;
|
|
444
|
+
right: 0;
|
|
445
|
+
z-index: 9;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.u-table-row-zebra {
|
|
449
|
+
background-color: #fafafa;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.u-table-row-highlight {
|
|
453
|
+
background-color: #f5f7fa;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.u-table-empty {
|
|
457
|
+
text-align: center;
|
|
458
|
+
padding: 20px;
|
|
459
|
+
color: #999;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.u-text-left {
|
|
463
|
+
text-align: left;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.u-text-center {
|
|
467
|
+
text-align: center;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.u-text-right {
|
|
471
|
+
text-align: right;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
</style>
|
package/components/u-td/u-td.vue
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<view class="u-td">
|
|
3
|
-
|
|
2
|
+
<view class="u-td" :style="[tdStyle]">
|
|
3
|
+
<slot></slot>
|
|
4
4
|
</view>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { props } from './props';
|
|
9
9
|
import { mpMixin } from '../../libs/mixin/mpMixin';
|
|
10
10
|
import { mixin } from '../../libs/mixin/mixin';
|
|
11
|
+
import { addUnit, $parent } from '../../libs/function/index';
|
|
11
12
|
/**
|
|
12
13
|
* Td 表格中的单元格
|
|
13
14
|
* @description
|
|
@@ -19,9 +20,36 @@
|
|
|
19
20
|
export default {
|
|
20
21
|
name: 'u-td',
|
|
21
22
|
mixins: [mpMixin, mixin, props],
|
|
23
|
+
props: {
|
|
24
|
+
// 宽度,百分比或者具体带单位的值,如30%, 200rpx等,一般使用百分比
|
|
25
|
+
width: {
|
|
26
|
+
type: [String],
|
|
27
|
+
default: 'auto'
|
|
28
|
+
}
|
|
29
|
+
},
|
|
22
30
|
data() {
|
|
23
31
|
return {
|
|
24
|
-
|
|
32
|
+
tdStyle: {
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
created() {
|
|
38
|
+
this.parent = false;
|
|
39
|
+
},
|
|
40
|
+
mounted() {
|
|
41
|
+
this.parent = $parent.call(this, 'u-table');
|
|
42
|
+
if (this.parent) {
|
|
43
|
+
// 将父组件的相关参数,合并到本组件
|
|
44
|
+
let style = {};
|
|
45
|
+
if (this.width != "auto") style.flex = `0 0 ${this.width}`;
|
|
46
|
+
style.textAlign = this.parent.align;
|
|
47
|
+
style.fontSize = addUnit(this.parent.fontSize);
|
|
48
|
+
style.padding = this.parent.padding;
|
|
49
|
+
style.borderBottom = `solid 1px ${this.parent.borderColor}`;
|
|
50
|
+
style.borderRight = `solid 1px ${this.parent.borderColor}`;
|
|
51
|
+
style.color = this.parent.color;
|
|
52
|
+
this.tdStyle = style;
|
|
25
53
|
}
|
|
26
54
|
}
|
|
27
55
|
}
|
|
@@ -29,5 +57,15 @@
|
|
|
29
57
|
|
|
30
58
|
<style lang="scss" scoped>
|
|
31
59
|
@import "../../libs/css/components.scss";
|
|
32
|
-
|
|
60
|
+
.u-td {
|
|
61
|
+
@include flex;
|
|
62
|
+
flex-direction: column;
|
|
63
|
+
flex: 1;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
font-size: 14px;
|
|
66
|
+
color: $u-content-color;
|
|
67
|
+
align-self: stretch;
|
|
68
|
+
box-sizing: border-box;
|
|
69
|
+
height: 100%;
|
|
70
|
+
}
|
|
33
71
|
</style>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="u-th" :style="[thStyle]">
|
|
3
|
+
<slot></slot>
|
|
4
|
+
</view>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
import { props } from './props';
|
|
9
|
+
import { mpMixin } from '../../libs/mixin/mpMixin';
|
|
10
|
+
import { mixin } from '../../libs/mixin/mixin';
|
|
11
|
+
import { addUnit, $parent } from '../../libs/function/index';
|
|
12
|
+
/**
|
|
13
|
+
* Td 表格中的单元格
|
|
14
|
+
* @description
|
|
15
|
+
* @tutorial url
|
|
16
|
+
* @property {String | Number}
|
|
17
|
+
* @event {Function}
|
|
18
|
+
* @example
|
|
19
|
+
*/
|
|
20
|
+
export default {
|
|
21
|
+
name: 'u-th',
|
|
22
|
+
mixins: [mpMixin, mixin, props],
|
|
23
|
+
props: {
|
|
24
|
+
// 宽度,百分比或者具体带单位的值,如30%, 200rpx等,一般使用百分比
|
|
25
|
+
width: {
|
|
26
|
+
type: [String],
|
|
27
|
+
default: ''
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
data() {
|
|
31
|
+
return {
|
|
32
|
+
thStyle: {}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
created() {
|
|
36
|
+
this.parent = false;
|
|
37
|
+
},
|
|
38
|
+
mounted() {
|
|
39
|
+
this.parent = $parent.call(this, 'u-table');
|
|
40
|
+
if (this.parent) {
|
|
41
|
+
// 将父组件的相关参数,合并到本组件
|
|
42
|
+
let style = {};
|
|
43
|
+
if (this.width) style.flex = `0 0 ${this.width}`;
|
|
44
|
+
style.textAlign = this.parent.align;
|
|
45
|
+
style.padding = this.parent.padding;
|
|
46
|
+
style.borderBottom = `solid 1px ${this.parent.borderColor}`;
|
|
47
|
+
style.borderRight = `solid 1px ${this.parent.borderColor}`;
|
|
48
|
+
Object.assign(style, this.parent.thStyle);
|
|
49
|
+
this.thStyle = style;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<style lang="scss" scoped>
|
|
56
|
+
@import "../../libs/css/components.scss";
|
|
57
|
+
.u-th {
|
|
58
|
+
@include flex;
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
flex: 1;
|
|
61
|
+
justify-content: center;
|
|
62
|
+
font-size: 28rpx;
|
|
63
|
+
color: $u-main-color;
|
|
64
|
+
font-weight: bold;
|
|
65
|
+
background-color: rgb(245, 246, 248);
|
|
66
|
+
}
|
|
67
|
+
</style>
|
package/components/u-tr/u-tr.vue
CHANGED
package/index.js
CHANGED
|
@@ -19,6 +19,8 @@ import debounce from './libs/function/debounce.js'
|
|
|
19
19
|
import throttle from './libs/function/throttle.js'
|
|
20
20
|
// 浮点计算
|
|
21
21
|
import calc from './libs/function/calc.js'
|
|
22
|
+
// 浮点计算
|
|
23
|
+
import digit from './libs/function/digit.js'
|
|
22
24
|
// 公共文件写入的方法
|
|
23
25
|
import index from './libs/function/index.js'
|
|
24
26
|
|
|
@@ -38,7 +40,7 @@ import http from './libs/function/http.js'
|
|
|
38
40
|
|
|
39
41
|
// 导出
|
|
40
42
|
let themeType = ['primary', 'success', 'error', 'warning', 'info'];
|
|
41
|
-
export { route, http, debounce, throttle, calc, platform, themeType, mixin, mpMixin, props, color, test, zIndex }
|
|
43
|
+
export { route, http, debounce, throttle, calc, digit, platform, themeType, mixin, mpMixin, props, color, test, zIndex }
|
|
42
44
|
export * from './libs/function/index.js'
|
|
43
45
|
export * from './libs/function/colorGradient.js'
|
|
44
46
|
|
package/package.json
CHANGED