eoss 0.1.0-alpha.44 → 0.1.0-alpha.45
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/lib/button-group.js +11 -9
- package/lib/button.js +5 -3
- package/lib/cascader.js +3 -3
- package/lib/color-picker.js +6 -3
- package/lib/date-picker.js +5 -3
- package/lib/eoss.common.js +516 -188
- package/lib/index.js +1 -1
- package/lib/input-number.js +6 -2
- package/lib/input.js +148 -87
- package/lib/select.js +212 -11
- package/lib/switch.js +6 -3
- package/lib/table-column.js +10 -1
- package/lib/table.js +64 -22
- package/lib/tag.js +2 -0
- package/lib/theme-chalk/base.css +1 -1
- package/lib/theme-chalk/cascader.css +1 -1
- package/lib/theme-chalk/icons.css +1 -1
- package/lib/theme-chalk/index.css +1 -1
- package/lib/theme-chalk/main.css +1 -1
- package/lib/theme-chalk/pagination.css +1 -1
- package/lib/theme-chalk/select.css +1 -1
- package/lib/theme-chalk/table-column.css +1 -1
- package/lib/theme-chalk/table.css +1 -1
- package/lib/theme-chalk/tag.css +1 -1
- package/lib/time-picker.js +5 -3
- package/lib/time-select.js +5 -3
- package/package.json +1 -1
- package/packages/button/src/button-group.vue +9 -7
- package/packages/button/src/button.vue +7 -5
- package/packages/cascader/src/cascader.vue +1 -1
- package/packages/color-picker/src/color-picker.vue +4 -1
- package/packages/date-picker/src/picker.vue +3 -1
- package/packages/input/src/input.vue +94 -60
- package/packages/input-number/src/input-number.vue +5 -1
- package/packages/select/src/select.vue +182 -12
- package/packages/switch/src/switch.vue +4 -1
- package/packages/table/src/table-column.js +7 -1
- package/packages/table/src/table-header.js +52 -7
- package/packages/table/src/util.js +3 -0
- package/packages/tag/src/tag.vue +2 -0
- package/packages/theme-chalk/src/base.scss +7 -0
- package/packages/theme-chalk/src/icons.scss +13 -1
- package/packages/theme-chalk/src/table.scss +12 -2
- package/packages/theme-chalk/src/tag.scss +303 -242
- package/src/index.js +1 -1
|
@@ -26,46 +26,52 @@
|
|
|
26
26
|
<es-button v-if="prepend" v-bind="prepend"></es-button>
|
|
27
27
|
</slot>
|
|
28
28
|
</div>
|
|
29
|
-
<!--
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
29
|
+
<!-- 只读态:纯文本展示,div 无光标不可聚焦;密码型未点眼预览时打码 -->
|
|
30
|
+
<div class="es-field-readonly" v-if="inputReadonly">
|
|
31
|
+
{{ passwordVisible ? nativeInputValue : maskedInputValue }}
|
|
32
|
+
</div>
|
|
33
|
+
<template v-else>
|
|
34
|
+
<!-- 隐藏的输入框,用于阻止浏览器默认填充密码 -->
|
|
35
|
+
<input
|
|
36
|
+
v-if="type === 'password' || (showPassword && !passwordVisible)"
|
|
37
|
+
type="password"
|
|
38
|
+
class="es-input__hidden"
|
|
39
|
+
style="
|
|
40
|
+
position: absolute;
|
|
41
|
+
top: -9999px;
|
|
42
|
+
left: -9999px;
|
|
43
|
+
width: 0;
|
|
44
|
+
height: 0;
|
|
45
|
+
opacity: 0;
|
|
46
|
+
"
|
|
47
|
+
autocomplete="off"
|
|
48
|
+
/>
|
|
49
|
+
<input
|
|
50
|
+
:tabindex="tabindex"
|
|
51
|
+
v-if="type !== 'textarea'"
|
|
52
|
+
class="es-input__inner"
|
|
53
|
+
:class="{ 'is-round': round }"
|
|
54
|
+
:style="innerStyle"
|
|
55
|
+
v-bind="$attrs"
|
|
56
|
+
:type="showPassword ? (passwordVisible ? 'text' : 'password') : type"
|
|
57
|
+
:disabled="inputDisabled"
|
|
58
|
+
:readonly="nativeReadonly"
|
|
59
|
+
:autocomplete="
|
|
60
|
+
type === 'password' || (showPassword && !passwordVisible)
|
|
61
|
+
? 'new-password'
|
|
62
|
+
: autoComplete || autocomplete
|
|
63
|
+
"
|
|
64
|
+
ref="input"
|
|
65
|
+
@compositionstart="handleCompositionStart"
|
|
66
|
+
@compositionupdate="handleCompositionUpdate"
|
|
67
|
+
@compositionend="handleCompositionEnd"
|
|
68
|
+
@input="handleInput"
|
|
69
|
+
@focus="handleFocus"
|
|
70
|
+
@blur="handleBlur"
|
|
71
|
+
@change="handleChange"
|
|
72
|
+
:aria-label="label"
|
|
73
|
+
/>
|
|
74
|
+
</template>
|
|
69
75
|
<!-- 前置内容 -->
|
|
70
76
|
<span
|
|
71
77
|
class="es-input__prefix"
|
|
@@ -129,26 +135,35 @@
|
|
|
129
135
|
</slot>
|
|
130
136
|
</div>
|
|
131
137
|
</template>
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
138
|
+
<template v-else>
|
|
139
|
+
<div
|
|
140
|
+
class="es-field-readonly es-field-readonly--textarea"
|
|
141
|
+
v-if="inputReadonly"
|
|
142
|
+
style="white-space: pre-wrap; word-break: break-all"
|
|
143
|
+
>
|
|
144
|
+
{{ nativeInputValue }}
|
|
145
|
+
</div>
|
|
146
|
+
<textarea
|
|
147
|
+
v-else
|
|
148
|
+
:tabindex="tabindex"
|
|
149
|
+
class="es-textarea__inner"
|
|
150
|
+
@compositionstart="handleCompositionStart"
|
|
151
|
+
@compositionupdate="handleCompositionUpdate"
|
|
152
|
+
@compositionend="handleCompositionEnd"
|
|
153
|
+
@input="handleInput"
|
|
154
|
+
ref="textarea"
|
|
155
|
+
v-bind="$attrs"
|
|
156
|
+
:disabled="inputDisabled"
|
|
157
|
+
:readonly="nativeReadonly"
|
|
158
|
+
:autocomplete="autoComplete || autocomplete"
|
|
159
|
+
:style="textareaStyle"
|
|
160
|
+
@focus="handleFocus"
|
|
161
|
+
@blur="handleBlur"
|
|
162
|
+
@change="handleChange"
|
|
163
|
+
:aria-label="label"
|
|
164
|
+
>
|
|
165
|
+
</textarea>
|
|
166
|
+
</template>
|
|
152
167
|
<span
|
|
153
168
|
v-if="isWordLimitVisible && type === 'textarea'"
|
|
154
169
|
class="es-input__count"
|
|
@@ -260,6 +275,14 @@ export default {
|
|
|
260
275
|
* @default false
|
|
261
276
|
*/
|
|
262
277
|
readonly: Boolean,
|
|
278
|
+
/**
|
|
279
|
+
* 仅绑定原生 input 的 readonly 属性(行为标志,供 select/cascader/picker 内部使用)
|
|
280
|
+
* @type {Boolean}
|
|
281
|
+
* @default false
|
|
282
|
+
* @description 这些复合组件给内部 es-input 传的 readonly 是"禁止打字但保留输入框结构"
|
|
283
|
+
* 的行为标志(普通态也常为 true),若走 readonly 会命中只读 div 分支导致布局破坏
|
|
284
|
+
*/
|
|
285
|
+
nativeReadonly: Boolean,
|
|
263
286
|
/**
|
|
264
287
|
* 输入框类型
|
|
265
288
|
* @type {String}
|
|
@@ -442,6 +465,17 @@ export default {
|
|
|
442
465
|
? ''
|
|
443
466
|
: String(this.value);
|
|
444
467
|
},
|
|
468
|
+
// 只读 div 用:密码型(含 showPassword 未点眼预览)按原生表现打码,
|
|
469
|
+
// div 无法应用 type="password",直接以掩码字符回显
|
|
470
|
+
maskedInputValue() {
|
|
471
|
+
if (
|
|
472
|
+
this.type !== 'password' &&
|
|
473
|
+
!(this.showPassword && !this.passwordVisible)
|
|
474
|
+
) {
|
|
475
|
+
return this.nativeInputValue;
|
|
476
|
+
}
|
|
477
|
+
return '*'.repeat(this.nativeInputValue.length);
|
|
478
|
+
},
|
|
445
479
|
showClear() {
|
|
446
480
|
return (
|
|
447
481
|
this.clearable &&
|
|
@@ -464,7 +464,10 @@ export default {
|
|
|
464
464
|
}
|
|
465
465
|
},
|
|
466
466
|
mounted() {
|
|
467
|
-
|
|
467
|
+
// 只读态下内部 es-input 被 v-if 移除,ref 不存在,需与 updated 同样防护
|
|
468
|
+
if (!this.$refs || !this.$refs.input) return;
|
|
469
|
+
const innerInput = this.$refs.input.$refs.input;
|
|
470
|
+
if (!innerInput) return;
|
|
468
471
|
innerInput.setAttribute('role', 'spinbutton');
|
|
469
472
|
innerInput.setAttribute('aria-valuemax', this.max);
|
|
470
473
|
innerInput.setAttribute('aria-valuemin', this.min);
|
|
@@ -474,6 +477,7 @@ export default {
|
|
|
474
477
|
updated() {
|
|
475
478
|
if (!this.$refs || !this.$refs.input) return;
|
|
476
479
|
const innerInput = this.$refs.input.$refs.input;
|
|
480
|
+
if (!innerInput) return;
|
|
477
481
|
innerInput.setAttribute('aria-valuenow', this.currentValue);
|
|
478
482
|
}
|
|
479
483
|
};
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
:autocomplete="autocomplete"
|
|
110
110
|
:size="selectSize"
|
|
111
111
|
:disabled="selectDisabled"
|
|
112
|
-
:readonly="inputReadonly"
|
|
112
|
+
:native-readonly="inputReadonly"
|
|
113
113
|
:validate-event="false"
|
|
114
114
|
:class="{ 'is-focus': visible }"
|
|
115
115
|
:tabindex="tabindex"
|
|
@@ -162,11 +162,17 @@
|
|
|
162
162
|
v-show="visible && emptyText !== false"
|
|
163
163
|
>
|
|
164
164
|
<es-scrollbar
|
|
165
|
+
v-loading="isLoading"
|
|
165
166
|
tag="ul"
|
|
166
167
|
wrap-class="es-select-dropdown__wrap"
|
|
167
168
|
view-class="es-select-dropdown__list"
|
|
168
169
|
ref="scrollbar"
|
|
169
170
|
:listener="true"
|
|
171
|
+
:infinite-scroll="innerInfiniteScroll"
|
|
172
|
+
:infinite-scroll-disabled="innerInfiniteScrollDisabled"
|
|
173
|
+
:infinite-scroll-distance="infiniteScrollDistance"
|
|
174
|
+
:infinite-scroll-delay="infiniteScrollDelay"
|
|
175
|
+
:infinite-scroll-immediate="infiniteScrollImmediate"
|
|
170
176
|
:class="{
|
|
171
177
|
'is-empty': !allowCreate && query && filteredOptionsCount === 0
|
|
172
178
|
}"
|
|
@@ -233,6 +239,13 @@
|
|
|
233
239
|
></es-option>
|
|
234
240
|
</template>
|
|
235
241
|
</slot>
|
|
242
|
+
<!-- 懒加载:续拉到底后提示没有更多数据 -->
|
|
243
|
+
<div
|
|
244
|
+
v-if="lazyEnabled && lazyFinished"
|
|
245
|
+
class="es-select-dropdown__finished"
|
|
246
|
+
>
|
|
247
|
+
没有更多数据了
|
|
248
|
+
</div>
|
|
236
249
|
</es-scrollbar>
|
|
237
250
|
<template
|
|
238
251
|
v-if="
|
|
@@ -696,7 +709,70 @@ export default {
|
|
|
696
709
|
* 选项值的键名
|
|
697
710
|
* @type {String}
|
|
698
711
|
*/
|
|
699
|
-
valueKey: String
|
|
712
|
+
valueKey: String,
|
|
713
|
+
/**
|
|
714
|
+
* 无限滚动回调:下拉列表滚动到底部时触发,用于分页加载更多选项
|
|
715
|
+
* @type {Function}
|
|
716
|
+
* @description 选项数据由外部接口分页提供时,在回调中请求下一页并追加到 data;
|
|
717
|
+
* 没有更多数据时由外部置 infiniteScrollDisabled 为 true 停止触发
|
|
718
|
+
*/
|
|
719
|
+
infiniteScroll: Function,
|
|
720
|
+
/**
|
|
721
|
+
* 是否禁用无限滚动
|
|
722
|
+
* @type {Boolean}
|
|
723
|
+
* @default false
|
|
724
|
+
*/
|
|
725
|
+
infiniteScrollDisabled: Boolean,
|
|
726
|
+
/**
|
|
727
|
+
* 距底部多少 px 时触发无限滚动
|
|
728
|
+
* @type {Number}
|
|
729
|
+
* @default 0
|
|
730
|
+
*/
|
|
731
|
+
infiniteScrollDistance: {
|
|
732
|
+
type: Number,
|
|
733
|
+
default: 0
|
|
734
|
+
},
|
|
735
|
+
/**
|
|
736
|
+
* 无限滚动回调的节流间隔(ms),透传给内部 es-scrollbar
|
|
737
|
+
* @type {Number}
|
|
738
|
+
* @default 200
|
|
739
|
+
*/
|
|
740
|
+
infiniteScrollDelay: {
|
|
741
|
+
type: Number,
|
|
742
|
+
default: 200
|
|
743
|
+
},
|
|
744
|
+
/**
|
|
745
|
+
* 是否挂载后立即触发一次回调
|
|
746
|
+
* @type {Boolean}
|
|
747
|
+
* @default false
|
|
748
|
+
* @description 与 es-scrollbar 默认值(true)不同:下拉的滚动条随 select 一起挂载,
|
|
749
|
+
* 默认 true 会导致下拉尚未打开就自动请求首页,故这里默认关闭
|
|
750
|
+
*/
|
|
751
|
+
infiniteScrollImmediate: {
|
|
752
|
+
type: Boolean,
|
|
753
|
+
default: false
|
|
754
|
+
},
|
|
755
|
+
/**
|
|
756
|
+
* 是否开启选项懒加载(分页加载)
|
|
757
|
+
* @type {Boolean}
|
|
758
|
+
* @default false
|
|
759
|
+
* @description 对 tree 为 false 的平铺 ul 列表生效,两种数据来源均支持:
|
|
760
|
+
* 1. url 取数:初始化请求第一页,下拉滚动到底部时自动续拉下一页并追加(内部复用无限滚动),
|
|
761
|
+
* 请求期间列表显示 loading;某页返回条数小于 pageSize 视为加载完毕停止触发
|
|
762
|
+
* 2. data 外部传入(未配置 url):本地分页,先渲染前 pageSize 条,
|
|
763
|
+
* 滚动到底部时同步切片追加下一页;data 变化时重置回第一页
|
|
764
|
+
*/
|
|
765
|
+
lazy: Boolean,
|
|
766
|
+
/**
|
|
767
|
+
* 懒加载每页条数(url 取数时作为请求参数 pageNum/pageSize 随 param 一起 POST 给 url;
|
|
768
|
+
* data 本地懒加载时作为每页切片条数)
|
|
769
|
+
* @type {Number}
|
|
770
|
+
* @default 50
|
|
771
|
+
*/
|
|
772
|
+
pageSize: {
|
|
773
|
+
type: Number,
|
|
774
|
+
default: 20
|
|
775
|
+
}
|
|
700
776
|
},
|
|
701
777
|
|
|
702
778
|
computed: {
|
|
@@ -708,6 +784,25 @@ export default {
|
|
|
708
784
|
actualValueKey() {
|
|
709
785
|
return this.valueKey || (this.sysCode ? 'cciValue' : 'value');
|
|
710
786
|
},
|
|
787
|
+
// 懒加载生效条件:开启 lazy、非树形(平铺 ul 列表)、有数据来源(url 取数或 data 传入)
|
|
788
|
+
lazyEnabled() {
|
|
789
|
+
return this.lazy && !this.tree && (!!this.url || this.data.length > 0);
|
|
790
|
+
},
|
|
791
|
+
// 本地懒加载:未配置 url、由外部 data 传入时的分页切片模式
|
|
792
|
+
localLazyEnabled() {
|
|
793
|
+
return this.lazyEnabled && !this.url;
|
|
794
|
+
},
|
|
795
|
+
// 无限滚动回调:懒加载模式走内部分页续拉,否则透传外部 infiniteScroll
|
|
796
|
+
innerInfiniteScroll() {
|
|
797
|
+
return this.lazyEnabled ? this.loadMoreOptions : this.infiniteScroll;
|
|
798
|
+
},
|
|
799
|
+
// 无限滚动禁用:外部禁用,或懒加载中/已加载完时避免重复触发
|
|
800
|
+
innerInfiniteScrollDisabled() {
|
|
801
|
+
return (
|
|
802
|
+
this.infiniteScrollDisabled ||
|
|
803
|
+
(this.lazyEnabled && (this.isLoading || this.lazyFinished))
|
|
804
|
+
);
|
|
805
|
+
},
|
|
711
806
|
model: {
|
|
712
807
|
get() {
|
|
713
808
|
if (this.multiple) {
|
|
@@ -856,7 +951,14 @@ export default {
|
|
|
856
951
|
watch: {
|
|
857
952
|
data: {
|
|
858
953
|
handler(val) {
|
|
859
|
-
this.
|
|
954
|
+
if (this.localLazyEnabled) {
|
|
955
|
+
// 本地懒加载:数据变化时重置回第一页重新切片
|
|
956
|
+
this.lazyPageNum = 1;
|
|
957
|
+
this.lazyFinished = false;
|
|
958
|
+
this.applyLocalLazySlice();
|
|
959
|
+
} else {
|
|
960
|
+
this.results = val;
|
|
961
|
+
}
|
|
860
962
|
},
|
|
861
963
|
deep: true
|
|
862
964
|
},
|
|
@@ -1047,7 +1149,12 @@ export default {
|
|
|
1047
1149
|
isDestroy: false,
|
|
1048
1150
|
innerStyle: {},
|
|
1049
1151
|
results: this.data,
|
|
1050
|
-
|
|
1152
|
+
// 懒加载分页状态:已加载到的页码 / 是否已加载完
|
|
1153
|
+
lazyPageNum: 1,
|
|
1154
|
+
lazyFinished: false,
|
|
1155
|
+
_propsCache: new Map(),
|
|
1156
|
+
// 是否请求中(驱动 es-scrollbar 上的 v-loading)
|
|
1157
|
+
isLoading: false
|
|
1051
1158
|
};
|
|
1052
1159
|
},
|
|
1053
1160
|
|
|
@@ -1075,6 +1182,10 @@ export default {
|
|
|
1075
1182
|
|
|
1076
1183
|
this.$on('handleOptionClick', this.handleOptionSelect);
|
|
1077
1184
|
this.$on('setSelected', this.setSelected);
|
|
1185
|
+
// 本地懒加载:初始只渲染 data 的第一页切片
|
|
1186
|
+
if (this.localLazyEnabled) {
|
|
1187
|
+
this.applyLocalLazySlice();
|
|
1188
|
+
}
|
|
1078
1189
|
this.debouncedGetData();
|
|
1079
1190
|
},
|
|
1080
1191
|
|
|
@@ -1178,21 +1289,80 @@ export default {
|
|
|
1178
1289
|
* @param {Object} options - 配置选项
|
|
1179
1290
|
* @param {String} options.url - 接口地址
|
|
1180
1291
|
* @param {Object} options.params - 接口参数
|
|
1292
|
+
* @param {Boolean} options.append - 懒加载续拉下一页并追加(仅 lazyEnabled 时生效)
|
|
1181
1293
|
*/
|
|
1182
|
-
getData({ url, params = {} }) {
|
|
1294
|
+
getData({ url, params = {}, append = false } = {}) {
|
|
1183
1295
|
url = url || this.url;
|
|
1184
1296
|
params = { ...this.param, ...params };
|
|
1185
|
-
url
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1297
|
+
if (!url) return;
|
|
1298
|
+
if (this.lazyEnabled) {
|
|
1299
|
+
if (append) {
|
|
1300
|
+
// 续拉下一页
|
|
1301
|
+
this.isLoading = true;
|
|
1302
|
+
params = {
|
|
1303
|
+
...params,
|
|
1304
|
+
pageNum: this.lazyPageNum + 1,
|
|
1305
|
+
pageSize: this.pageSize
|
|
1306
|
+
};
|
|
1307
|
+
} else {
|
|
1308
|
+
// 初始化/参数变化/远程搜索:重置分页请求第一页
|
|
1309
|
+
this.lazyPageNum = 1;
|
|
1310
|
+
this.lazyFinished = false;
|
|
1311
|
+
params = { ...params, pageNum: 1, pageSize: this.pageSize };
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
ajax({
|
|
1315
|
+
url,
|
|
1316
|
+
method: 'POST',
|
|
1317
|
+
data: params
|
|
1318
|
+
})
|
|
1319
|
+
.then((res) => {
|
|
1191
1320
|
if (res.rCode === 0) {
|
|
1192
|
-
|
|
1321
|
+
const rows = res.results || [];
|
|
1322
|
+
if (this.lazyEnabled && append) {
|
|
1323
|
+
this.results = this.results.concat(rows);
|
|
1324
|
+
this.lazyPageNum += 1;
|
|
1325
|
+
} else {
|
|
1326
|
+
this.results = rows;
|
|
1327
|
+
}
|
|
1328
|
+
// 续拉时返回条数不足一页视为已加载完,停止触发并提示没有更多
|
|
1329
|
+
// (首页不足一页属正常小数据量,不显示提示)
|
|
1330
|
+
if (this.lazyEnabled && append && rows.length < this.pageSize) {
|
|
1331
|
+
this.lazyFinished = true;
|
|
1332
|
+
}
|
|
1193
1333
|
}
|
|
1334
|
+
this.isLoading = false;
|
|
1335
|
+
})
|
|
1336
|
+
.catch(() => {
|
|
1337
|
+
this.isLoading = false;
|
|
1194
1338
|
});
|
|
1195
1339
|
},
|
|
1340
|
+
/**
|
|
1341
|
+
* 懒加载:滚动到底部时加载下一页(由内部无限滚动触发,带防重入守卫)
|
|
1342
|
+
* 本地懒加载为同步切片追加,url 懒加载为异步续拉请求
|
|
1343
|
+
*/
|
|
1344
|
+
loadMoreOptions() {
|
|
1345
|
+
if (!this.lazyEnabled || this.isLoading || this.lazyFinished) return;
|
|
1346
|
+
if (this.localLazyEnabled) {
|
|
1347
|
+
this.lazyPageNum += 1;
|
|
1348
|
+
this.applyLocalLazySlice();
|
|
1349
|
+
} else {
|
|
1350
|
+
this.getData({ append: true });
|
|
1351
|
+
}
|
|
1352
|
+
},
|
|
1353
|
+
/**
|
|
1354
|
+
* 本地懒加载:按当前 lazyPageNum 对 data 做切片渲染(0 ~ pageNum*pageSize),
|
|
1355
|
+
* 翻过页且切到末尾时置 lazyFinished 停止触发并显示没有更多提示
|
|
1356
|
+
* (首页即覆盖全量属正常小数据量,不置位不提示)
|
|
1357
|
+
*/
|
|
1358
|
+
applyLocalLazySlice() {
|
|
1359
|
+
const list = this.data || [];
|
|
1360
|
+
const end = this.lazyPageNum * this.pageSize;
|
|
1361
|
+
this.results = list.slice(0, end);
|
|
1362
|
+
if (this.lazyPageNum > 1 && end >= list.length) {
|
|
1363
|
+
this.lazyFinished = true;
|
|
1364
|
+
}
|
|
1365
|
+
},
|
|
1196
1366
|
handleComposition(event) {
|
|
1197
1367
|
const text = event.target.value;
|
|
1198
1368
|
if (event.type === 'compositionend') {
|
|
@@ -361,7 +361,10 @@ export default {
|
|
|
361
361
|
if (this.activeColor || this.inactiveColor) {
|
|
362
362
|
this.setBackgroundColor();
|
|
363
363
|
}
|
|
364
|
-
|
|
364
|
+
// 只读态下内部 input 被 v-if 移除,需防护
|
|
365
|
+
if (this.$refs.input) {
|
|
366
|
+
this.$refs.input.checked = this.checked;
|
|
367
|
+
}
|
|
365
368
|
}
|
|
366
369
|
};
|
|
367
370
|
</script>
|
|
@@ -30,7 +30,13 @@ export default {
|
|
|
30
30
|
labelKey: String,
|
|
31
31
|
valueKey: String,
|
|
32
32
|
icon: String,
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* 表头按钮配置
|
|
35
|
+
* @type {String|Object|Array}
|
|
36
|
+
* @description String 渲染文字按钮;Object 渲染图标按钮(icon/type/class/nativeType/event);
|
|
37
|
+
* Array 渲染多个按钮,每项结构同 String/Object,Object 项的 event 回调签名为 ('', column, $event)
|
|
38
|
+
*/
|
|
39
|
+
button: [String, Object, Array],
|
|
34
40
|
className: String,
|
|
35
41
|
labelClassName: String,
|
|
36
42
|
property: String,
|
|
@@ -723,28 +723,73 @@ export default {
|
|
|
723
723
|
* @param {Function} h - Vue渲染函数
|
|
724
724
|
* @param {Object} column - 列配置
|
|
725
725
|
* @returns {VNode|null} 渲染结果
|
|
726
|
+
* @description button 支持 String(文字按钮)/ Object(图标按钮)/
|
|
727
|
+
* Array(多个按钮,每项结构同 String/Object,Object 项可配置各自的 event 回调)
|
|
726
728
|
*/
|
|
727
729
|
_renderColumnButton(h, column) {
|
|
728
730
|
if (!column.button) return null;
|
|
729
731
|
|
|
730
|
-
|
|
732
|
+
// 数组配置:渲染多个按钮
|
|
733
|
+
if (Array.isArray(column.button)) {
|
|
734
|
+
if (!column.button.length) return null;
|
|
735
|
+
return (
|
|
736
|
+
<span class="es-table__column-buttons">
|
|
737
|
+
{column.button.map((item, index) =>
|
|
738
|
+
this._renderOneHeaderButton(h, column, item, index)
|
|
739
|
+
)}
|
|
740
|
+
</span>
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
return this._renderOneHeaderButton(h, column, column.button, 0);
|
|
745
|
+
},
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* 渲染单个表头按钮
|
|
749
|
+
* @private
|
|
750
|
+
* @param {Function} h - Vue渲染函数
|
|
751
|
+
* @param {Object} column - 列配置
|
|
752
|
+
* @param {String|Object} button - 按钮配置
|
|
753
|
+
* @param {number} index - 数组配置时的序号(用作 key)
|
|
754
|
+
* @returns {VNode|null} 渲染结果
|
|
755
|
+
*/
|
|
756
|
+
_renderOneHeaderButton(h, column, button, index) {
|
|
757
|
+
if (!button) return null;
|
|
758
|
+
|
|
759
|
+
// 数组配置的按钮优先执行各自的 event 回调,其余走原表头点击链路
|
|
760
|
+
const onClick = ($event) => {
|
|
761
|
+
if (
|
|
762
|
+
Array.isArray(column.button) &&
|
|
763
|
+
typeof button === 'object' &&
|
|
764
|
+
typeof button.event === 'function'
|
|
765
|
+
) {
|
|
766
|
+
$event.stopPropagation();
|
|
767
|
+
button.event('', column, $event);
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
this.handleHeaderClick($event, column);
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
if (typeof button === 'string') {
|
|
731
774
|
return (
|
|
732
775
|
<es-button
|
|
776
|
+
key={index}
|
|
733
777
|
size="mini"
|
|
734
778
|
native-type="button"
|
|
735
|
-
on-click={
|
|
736
|
-
>{
|
|
779
|
+
on-click={onClick}
|
|
780
|
+
>{button}
|
|
737
781
|
</es-button>
|
|
738
782
|
);
|
|
739
783
|
}
|
|
740
784
|
|
|
741
785
|
return (
|
|
742
786
|
<es-button
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
787
|
+
key={index}
|
|
788
|
+
class={[button.icon || column.icon, button.class]}
|
|
789
|
+
type={button.type}
|
|
790
|
+
native-type={button.nativeType || 'button'}
|
|
746
791
|
size="mini"
|
|
747
|
-
on-click={
|
|
792
|
+
on-click={onClick}
|
|
748
793
|
>
|
|
749
794
|
</es-button>
|
|
750
795
|
);
|
|
@@ -1013,11 +1013,13 @@ export function renderDom(h, { type, data, optionData, config = {}, events = {}
|
|
|
1013
1013
|
}
|
|
1014
1014
|
});
|
|
1015
1015
|
case 'handle':
|
|
1016
|
+
console.log('handle', data);
|
|
1016
1017
|
// const contents = events.filter((item) => item.rules && typeof item.rules === 'function' ? item.rules(data.row) : true);
|
|
1017
1018
|
return h('es-button-group', {
|
|
1018
1019
|
class: className,
|
|
1019
1020
|
props: {
|
|
1020
1021
|
data: data.row,
|
|
1022
|
+
rowData: data,
|
|
1021
1023
|
size: 'mini',
|
|
1022
1024
|
type: 'text',
|
|
1023
1025
|
stop: true,
|
|
@@ -1030,6 +1032,7 @@ export function renderDom(h, { type, data, optionData, config = {}, events = {}
|
|
|
1030
1032
|
class: className,
|
|
1031
1033
|
props: {
|
|
1032
1034
|
param: data.row,
|
|
1035
|
+
rowData: data,
|
|
1033
1036
|
size: 'mini',
|
|
1034
1037
|
stop: true,
|
|
1035
1038
|
...configs
|
package/packages/tag/src/tag.vue
CHANGED
|
@@ -5,8 +5,20 @@
|
|
|
5
5
|
color: transparent;
|
|
6
6
|
}
|
|
7
7
|
@include when(readonly) {
|
|
8
|
-
.es-
|
|
8
|
+
.es-field-readonly {
|
|
9
|
+
position: relative;
|
|
9
10
|
z-index: -1;
|
|
11
|
+
color: transparent;
|
|
12
|
+
&::before {
|
|
13
|
+
content: '';
|
|
14
|
+
position: absolute;
|
|
15
|
+
top: 0;
|
|
16
|
+
left: 0;
|
|
17
|
+
right: 0;
|
|
18
|
+
bottom: 0;
|
|
19
|
+
background-color: #fff;
|
|
20
|
+
border-radius: 6px;
|
|
21
|
+
}
|
|
10
22
|
}
|
|
11
23
|
}
|
|
12
24
|
@include when(focused) {
|
|
@@ -169,11 +169,10 @@
|
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
th.es-table__cell
|
|
172
|
+
th.es-table__cell,
|
|
173
173
|
td.es-table__cell {
|
|
174
174
|
border-bottom: $--table-border;
|
|
175
175
|
}
|
|
176
|
-
|
|
177
176
|
th.es-table__cell.is-sortable {
|
|
178
177
|
cursor: pointer;
|
|
179
178
|
}
|
|
@@ -638,4 +637,15 @@
|
|
|
638
637
|
margin-right: 3px;
|
|
639
638
|
}
|
|
640
639
|
}
|
|
640
|
+
|
|
641
|
+
// 表头 button 配置为数组时的多按钮容器:按钮间留间距、整体与标题垂直对齐
|
|
642
|
+
.es-table__column-buttons {
|
|
643
|
+
display: inline-flex;
|
|
644
|
+
align-items: center;
|
|
645
|
+
vertical-align: middle;
|
|
646
|
+
|
|
647
|
+
.es-button + .es-button {
|
|
648
|
+
margin-left: 5px;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
641
651
|
}
|