cbvirtua 1.0.7 → 1.0.9
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/README.md +270 -0
- package/asy.js +32 -0
- package/package.json +1 -1
- package/pre/index.js +93 -0
- package/style/basic.less +69 -0
- package/style/index.less +125 -0
- package/style/index.tsx +2 -0
- package/style/mixin.less +53 -0
- package/style/rtl.less +68 -0
- package/menu/wzc-option.vue +0 -74
- package/menu/wzc-select.vue +0 -209
- package/vue/ListItem.js +0 -44
- package/vue/ListItem.tsx +0 -64
- package/vue/VList.js +0 -133
- package/vue/VList.tsx +0 -291
- package/vue/ec.css +0 -48
- package/vue/ec.js +0 -78
- package/vue/index.js +0 -4
- package/vue/l.less +0 -69
package/style/rtl.less
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
@import '../../style/themes/index';
|
|
2
|
+
@import '../../style/mixins/index';
|
|
3
|
+
|
|
4
|
+
.@{ant-prefix}-row {
|
|
5
|
+
&-rtl {
|
|
6
|
+
direction: rtl;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// mixin
|
|
11
|
+
.loop-grid-columns(@index, @class) when (@index > 0) {
|
|
12
|
+
.@{ant-prefix}-col@{class}-push-@{index} {
|
|
13
|
+
// reset property in RTL direction
|
|
14
|
+
&.@{ant-prefix}-col-rtl {
|
|
15
|
+
right: percentage((@index / @grid-columns));
|
|
16
|
+
left: auto;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.@{ant-prefix}-col@{class}-pull-@{index} {
|
|
21
|
+
// reset property in RTL direction
|
|
22
|
+
&.@{ant-prefix}-col-rtl {
|
|
23
|
+
right: auto;
|
|
24
|
+
left: percentage((@index / @grid-columns));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.@{ant-prefix}-col@{class}-offset-@{index} {
|
|
29
|
+
// reset property in RTL direction
|
|
30
|
+
&.@{ant-prefix}-col-rtl {
|
|
31
|
+
margin-right: percentage((@index / @grid-columns));
|
|
32
|
+
margin-left: 0;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.loop-grid-columns(@index, @class) when (@index = 0) {
|
|
38
|
+
.@{ant-prefix}-col-push-@{index} {
|
|
39
|
+
// reset property in RTL direction
|
|
40
|
+
&.@{ant-prefix}-col-rtl {
|
|
41
|
+
right: auto;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.@{ant-prefix}-col-pull-@{index} {
|
|
46
|
+
&.@{ant-prefix}-col-rtl {
|
|
47
|
+
left: auto;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.@{ant-prefix}-col@{class}-push-@{index} {
|
|
52
|
+
&.@{ant-prefix}-col-rtl {
|
|
53
|
+
right: auto;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.@{ant-prefix}-col@{class}-pull-@{index} {
|
|
58
|
+
&.@{ant-prefix}-col-rtl {
|
|
59
|
+
left: auto;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.@{ant-prefix}-col@{class}-offset-@{index} {
|
|
64
|
+
&.@{ant-prefix}-col-rtl {
|
|
65
|
+
margin-right: 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
package/menu/wzc-option.vue
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<li class="wzc_option" :style="styleVar" @click="currentSelect">
|
|
3
|
-
<div class="wzc_option_dropdown_item">{{ label }}</div>
|
|
4
|
-
</li>
|
|
5
|
-
</template>
|
|
6
|
-
|
|
7
|
-
<script>
|
|
8
|
-
export default {
|
|
9
|
-
name: "wzc_select",
|
|
10
|
-
components: {},
|
|
11
|
-
props: {
|
|
12
|
-
width: {
|
|
13
|
-
type: Number,
|
|
14
|
-
default: -1,
|
|
15
|
-
},
|
|
16
|
-
height: {
|
|
17
|
-
type: Number,
|
|
18
|
-
default: 34,
|
|
19
|
-
},
|
|
20
|
-
label: {
|
|
21
|
-
type: String,
|
|
22
|
-
},
|
|
23
|
-
optionid: {
|
|
24
|
-
type: String,
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
data() {
|
|
28
|
-
return {};
|
|
29
|
-
},
|
|
30
|
-
created() {},
|
|
31
|
-
mounted() {},
|
|
32
|
-
watch: {},
|
|
33
|
-
computed: {
|
|
34
|
-
styleVar() {
|
|
35
|
-
return {
|
|
36
|
-
"--option-height": this.height + "px",
|
|
37
|
-
"--option-width": this.width == -1? "100%" : this.width + "px",
|
|
38
|
-
};
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
methods: {
|
|
42
|
-
currentSelect() {
|
|
43
|
-
this.$parent.label = this.label;
|
|
44
|
-
this.$parent.optionid = this.optionid;
|
|
45
|
-
this.$parent.isListShow = !this.$parent.isListShow;
|
|
46
|
-
// this.$emit('slot-content', {label: this.label, optionid: this.optionid} );
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
</script>
|
|
51
|
-
<style scoped>
|
|
52
|
-
.wzc_option {
|
|
53
|
-
list-style: none;
|
|
54
|
-
height: var(--option-height);
|
|
55
|
-
width: var(--option-width);
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
.wzc_option:hover {
|
|
59
|
-
color: #409eff;
|
|
60
|
-
font-weight: 700;
|
|
61
|
-
background-color: #f5f7fa;
|
|
62
|
-
}
|
|
63
|
-
.wzc_option_dropdown_item {
|
|
64
|
-
height: 100%;
|
|
65
|
-
width: calc(100% - 30px);
|
|
66
|
-
line-height: var(--option-height);
|
|
67
|
-
cursor: pointer;
|
|
68
|
-
margin: 0 auto;
|
|
69
|
-
overflow: hidden;
|
|
70
|
-
text-overflow: ellipsis;
|
|
71
|
-
white-space: nowrap;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
</style>
|
package/menu/wzc-select.vue
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="wzc_select" :style="styleVar">
|
|
3
|
-
<div class="divSelect" :class="{ 'drop_down': isListShow }" ref="divSelect">
|
|
4
|
-
<div class="divSelectinput" @click="dropDownSelect">
|
|
5
|
-
<!-- 选中后的内容 -->
|
|
6
|
-
<div class="selectinfos" :title="label" :class="{ 'no_select': label == '请选择' }"> {{ label }} </div>
|
|
7
|
-
<!-- 三角形图标 -->
|
|
8
|
-
<i class="imgthree" :class="{ 'is-reverse': isListShow }">
|
|
9
|
-
<svg t="1707138975702" class="icon" viewBox="0 0 1024 1024" version="1.1"
|
|
10
|
-
xmlns="http://www.w3.org/2000/svg" p-id="1444" width="16" height="16">
|
|
11
|
-
<path d="M512 187.24L699.501 512 887 836.76H137L324.5 512z" p-id="1445"></path>
|
|
12
|
-
</svg>
|
|
13
|
-
</i>
|
|
14
|
-
</div>
|
|
15
|
-
</div>
|
|
16
|
-
<!-- 下拉框列表 -->
|
|
17
|
-
<transition name="drop-down">
|
|
18
|
-
<div class="Selectlist" v-show="isListShow" ref="dropDown">
|
|
19
|
-
<div class="select_triangle"></div>
|
|
20
|
-
<ul class="wzc_option_list">
|
|
21
|
-
<slot name="wzc_option"></slot>
|
|
22
|
-
</ul>
|
|
23
|
-
</div>
|
|
24
|
-
</transition>
|
|
25
|
-
</div>
|
|
26
|
-
</template>
|
|
27
|
-
|
|
28
|
-
<script>
|
|
29
|
-
export default {
|
|
30
|
-
name: 'wzc_select',
|
|
31
|
-
components: {},
|
|
32
|
-
props: {
|
|
33
|
-
placeholder: {
|
|
34
|
-
type: String,
|
|
35
|
-
default: '请选择'
|
|
36
|
-
},
|
|
37
|
-
width: {
|
|
38
|
-
type: Number,
|
|
39
|
-
default: 180
|
|
40
|
-
},
|
|
41
|
-
height: {
|
|
42
|
-
type: Number,
|
|
43
|
-
default: 40
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
data() {
|
|
47
|
-
return {
|
|
48
|
-
label: '',
|
|
49
|
-
isListShow: false,
|
|
50
|
-
optionid: ''
|
|
51
|
-
};
|
|
52
|
-
},
|
|
53
|
-
created() {
|
|
54
|
-
this.label = this.placeholder;
|
|
55
|
-
},
|
|
56
|
-
mounted() {
|
|
57
|
-
let _this = this;
|
|
58
|
-
document.addEventListener("click", function (e) {
|
|
59
|
-
if (_this.$refs.divSelect) {
|
|
60
|
-
if (!!_this.$refs.divSelect.contains(e.target) || !!_this.$refs.dropDown.contains(e.target))
|
|
61
|
-
return;
|
|
62
|
-
else
|
|
63
|
-
_this.isListShow = false;
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
},
|
|
67
|
-
computed: {
|
|
68
|
-
styleVar() {
|
|
69
|
-
return {
|
|
70
|
-
'--select-height': this.height + 'px',
|
|
71
|
-
'--select-width': this.width + 'px'
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
methods: {
|
|
76
|
-
dropDownSelect() {
|
|
77
|
-
this.isListShow = !this.isListShow;
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
</script>
|
|
82
|
-
<style scoped>
|
|
83
|
-
.wzc_select {
|
|
84
|
-
border: 1px solid #E6E6E6;
|
|
85
|
-
border-radius: 5px;
|
|
86
|
-
height: var(--select-height);
|
|
87
|
-
width: var(--select-width);
|
|
88
|
-
line-height: var(--select-height);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.divSelect {
|
|
92
|
-
width: 100%;
|
|
93
|
-
height: 100%;
|
|
94
|
-
border-radius: 5px;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.drop_down {
|
|
98
|
-
box-shadow: 0px 0px 6px #709DF7;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
.divSelectinput {
|
|
102
|
-
width: calc(100% - 20px);
|
|
103
|
-
height: 100%;
|
|
104
|
-
margin: 0 5px 0 15px;
|
|
105
|
-
display: flex;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
.selectinfos {
|
|
109
|
-
width: 87.5%;
|
|
110
|
-
cursor: pointer;
|
|
111
|
-
overflow: hidden;
|
|
112
|
-
text-overflow: ellipsis;
|
|
113
|
-
white-space: nowrap;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.no_select {
|
|
117
|
-
color: #D3DCE6;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.imgthree {
|
|
121
|
-
width: 12.5%;
|
|
122
|
-
line-height: var(--select-height);
|
|
123
|
-
text-align: center;
|
|
124
|
-
transform: rotate(180deg);
|
|
125
|
-
transition: all 0.3s;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.imgthree svg {
|
|
129
|
-
width: 1em;
|
|
130
|
-
height: 1em;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
.imgthree:before {
|
|
134
|
-
cursor: pointer;
|
|
135
|
-
color: #D3DCE6;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
.imgthree.is-reverse {
|
|
139
|
-
transform: rotate(0deg);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
.Selectlist {
|
|
143
|
-
margin-top: 10px;
|
|
144
|
-
z-index: 800;
|
|
145
|
-
position: relative;
|
|
146
|
-
background-color: #fff;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
.wzc_option_list {
|
|
150
|
-
border-radius: 5px;
|
|
151
|
-
border: 1px solid #E4E7ED;
|
|
152
|
-
width: 100%;
|
|
153
|
-
padding: 3px 0px;
|
|
154
|
-
box-shadow: 0px 0px 6px #709DF7;
|
|
155
|
-
background-color: #fff;
|
|
156
|
-
margin: 0;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.select_triangle {
|
|
160
|
-
width: 14px;
|
|
161
|
-
height: 7px;
|
|
162
|
-
position: relative;
|
|
163
|
-
left: 15px;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
.select_triangle::before {
|
|
167
|
-
position: absolute;
|
|
168
|
-
content: "";
|
|
169
|
-
left: 0px;
|
|
170
|
-
width: 0;
|
|
171
|
-
height: 0;
|
|
172
|
-
border-top: 0px solid transparent;
|
|
173
|
-
border-left: 9px solid transparent;
|
|
174
|
-
border-right: 9px solid transparent;
|
|
175
|
-
border-bottom: 8px solid #EBEEF5;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.select_triangle::after {
|
|
179
|
-
position: absolute;
|
|
180
|
-
left: 2px;
|
|
181
|
-
top: 2px;
|
|
182
|
-
content: "";
|
|
183
|
-
width: 0;
|
|
184
|
-
height: 0;
|
|
185
|
-
border-top: 0px solid transparent;
|
|
186
|
-
border-left: 7px solid transparent;
|
|
187
|
-
border-right: 7px solid transparent;
|
|
188
|
-
border-bottom: 8px solid #fff;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
.drop-down-enter {
|
|
192
|
-
opacity: 0;
|
|
193
|
-
transform: translate(0px, -80px) scaleY(0.2);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.drop-down-leave-to {
|
|
197
|
-
opacity: 0;
|
|
198
|
-
transform: translate(0px, -80px) scaleY(0.2);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
.drop-down-enter-active {
|
|
202
|
-
transition: all 0.5s ease-in;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.drop-down-leave-active {
|
|
206
|
-
transition: all 0.5s ease;
|
|
207
|
-
}
|
|
208
|
-
</style>
|
|
209
|
-
|
package/vue/ListItem.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "vue/jsx-runtime";
|
|
2
|
-
/** @jsxImportSource vue */
|
|
3
|
-
import { ref, defineComponent, watch } from "vue";
|
|
4
|
-
import { isRTLDocument } from "../core/environment";
|
|
5
|
-
/**
|
|
6
|
-
* @internal
|
|
7
|
-
*/
|
|
8
|
-
export const ListItem = /*#__PURE__*/ defineComponent({
|
|
9
|
-
props: {
|
|
10
|
-
_children: { type: Object, required: true },
|
|
11
|
-
_resizer: { type: Object, required: true },
|
|
12
|
-
_index: { type: Number, required: true },
|
|
13
|
-
_offset: { type: Number, required: true },
|
|
14
|
-
_hide: { type: Boolean },
|
|
15
|
-
_isHorizontal: { type: Boolean },
|
|
16
|
-
_element: { type: String, required: true },
|
|
17
|
-
},
|
|
18
|
-
setup(props) {
|
|
19
|
-
const elementRef = ref();
|
|
20
|
-
// The index may be changed if elements are inserted to or removed from the start of props.children
|
|
21
|
-
watch(() => elementRef.value && props._index, (_, __, onCleanup) => {
|
|
22
|
-
const cleanupObserver = props._resizer(elementRef.value, props._index);
|
|
23
|
-
onCleanup(cleanupObserver);
|
|
24
|
-
}, {
|
|
25
|
-
flush: "post",
|
|
26
|
-
});
|
|
27
|
-
return () => {
|
|
28
|
-
const { _children: children, _offset: offset, _hide: hide, _element: Element, _isHorizontal: isHorizontal, } = props;
|
|
29
|
-
const style = {
|
|
30
|
-
margin: 0,
|
|
31
|
-
padding: 0,
|
|
32
|
-
position: "absolute",
|
|
33
|
-
[isHorizontal ? "height" : "width"]: "100%",
|
|
34
|
-
[isHorizontal ? "top" : "left"]: "0px",
|
|
35
|
-
[isHorizontal ? (isRTLDocument() ? "right" : "left") : "top"]: offset + "px",
|
|
36
|
-
visibility: hide ? "hidden" : "visible",
|
|
37
|
-
};
|
|
38
|
-
if (isHorizontal) {
|
|
39
|
-
style.display = "flex";
|
|
40
|
-
}
|
|
41
|
-
return (_jsx(Element, { ref: elementRef, style: style, children: children }));
|
|
42
|
-
};
|
|
43
|
-
},
|
|
44
|
-
});
|
package/vue/ListItem.tsx
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/** @jsxImportSource vue */
|
|
2
|
-
import { ref, defineComponent, watch, StyleValue, PropType, VNode } from "vue";
|
|
3
|
-
import { ItemResizeObserver } from "../core/resizer";
|
|
4
|
-
import { isRTLDocument } from "../core/environment";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @internal
|
|
8
|
-
*/
|
|
9
|
-
export const ListItem = /*#__PURE__*/ defineComponent({
|
|
10
|
-
props: {
|
|
11
|
-
_children: { type: Object as PropType<VNode>, required: true },
|
|
12
|
-
_resizer: { type: Object as PropType<ItemResizeObserver>, required: true },
|
|
13
|
-
_index: { type: Number, required: true },
|
|
14
|
-
_offset: { type: Number, required: true },
|
|
15
|
-
_hide: { type: Boolean },
|
|
16
|
-
_isHorizontal: { type: Boolean },
|
|
17
|
-
_element: { type: String, required: true },
|
|
18
|
-
},
|
|
19
|
-
setup(props) {
|
|
20
|
-
const elementRef = ref<HTMLDivElement>();
|
|
21
|
-
|
|
22
|
-
// The index may be changed if elements are inserted to or removed from the start of props.children
|
|
23
|
-
watch(
|
|
24
|
-
() => elementRef.value && props._index,
|
|
25
|
-
(_, __, onCleanup) => {
|
|
26
|
-
const cleanupObserver = props._resizer(elementRef.value!, props._index);
|
|
27
|
-
onCleanup(cleanupObserver);
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
flush: "post",
|
|
31
|
-
}
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
return () => {
|
|
35
|
-
const {
|
|
36
|
-
_children: children,
|
|
37
|
-
_offset: offset,
|
|
38
|
-
_hide: hide,
|
|
39
|
-
_element: Element,
|
|
40
|
-
_isHorizontal: isHorizontal,
|
|
41
|
-
} = props as Omit<typeof props, "_element"> & { _element: "div" };
|
|
42
|
-
|
|
43
|
-
const style: StyleValue = {
|
|
44
|
-
margin: 0,
|
|
45
|
-
padding: 0,
|
|
46
|
-
position: "absolute",
|
|
47
|
-
[isHorizontal ? "height" : "width"]: "100%",
|
|
48
|
-
[isHorizontal ? "top" : "left"]: "0px",
|
|
49
|
-
[isHorizontal ? (isRTLDocument() ? "right" : "left") : "top"]:
|
|
50
|
-
offset + "px",
|
|
51
|
-
visibility: hide ? "hidden" : "visible",
|
|
52
|
-
};
|
|
53
|
-
if (isHorizontal) {
|
|
54
|
-
style.display = "flex";
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<Element ref={elementRef} style={style}>
|
|
59
|
-
{children}
|
|
60
|
-
</Element>
|
|
61
|
-
);
|
|
62
|
-
};
|
|
63
|
-
},
|
|
64
|
-
});
|
package/vue/VList.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "vue/jsx-runtime";
|
|
2
|
-
/** @jsxImportSource vue */
|
|
3
|
-
import { ref, onMounted, defineComponent, onUnmounted, watch, } from "vue";
|
|
4
|
-
import { SCROLL_IDLE, UPDATE_SCROLL_STATE, UPDATE_SCROLL_EVENT, UPDATE_SCROLL_END_EVENT, UPDATE_SIZE_STATE, overscanEndIndex, overscanStartIndex, createVirtualStore, ACTION_ITEMS_LENGTH_CHANGE, getScrollSize, getMinContainerSize, } from "../core/store";
|
|
5
|
-
import { createResizer } from "../core/resizer";
|
|
6
|
-
import { createScroller } from "../core/scroller";
|
|
7
|
-
import { ListItem } from "./ListItem";
|
|
8
|
-
import { exists } from "../core/utils";
|
|
9
|
-
const props = {
|
|
10
|
-
/**
|
|
11
|
-
* The data items rendered by this component.
|
|
12
|
-
*/
|
|
13
|
-
data: { type: Array, required: true },
|
|
14
|
-
/**
|
|
15
|
-
* Number of items to render above/below the visible bounds of the list. You can increase to avoid showing blank items in fast scrolling.
|
|
16
|
-
* @defaultValue 4
|
|
17
|
-
*/
|
|
18
|
-
overscan: { type: Number, default: 4 },
|
|
19
|
-
/**
|
|
20
|
-
* Item size hint for unmeasured items. It will help to reduce scroll jump when items are measured if used properly.
|
|
21
|
-
*
|
|
22
|
-
* - If not set, initial item sizes will be automatically estimated from measured sizes. This is recommended for most cases.
|
|
23
|
-
* - If set, you can opt out estimation and use the value as initial item size.
|
|
24
|
-
*/
|
|
25
|
-
itemSize: Number,
|
|
26
|
-
/**
|
|
27
|
-
* While true is set, scroll position will be maintained from the end not usual start when items are added to/removed from start. It's recommended to set false if you add to/remove from mid/end of the list because it can cause unexpected behavior. This prop is useful for reverse infinite scrolling.
|
|
28
|
-
*/
|
|
29
|
-
shift: Boolean,
|
|
30
|
-
/**
|
|
31
|
-
* If true, rendered as a horizontally scrollable list. Otherwise rendered as a vertically scrollable list.
|
|
32
|
-
*/
|
|
33
|
-
horizontal: Boolean,
|
|
34
|
-
};
|
|
35
|
-
export const VList = /*#__PURE__*/ defineComponent({
|
|
36
|
-
props: props,
|
|
37
|
-
emits: ["scroll", "scrollEnd", "rangeChange"],
|
|
38
|
-
setup(props, { emit, expose, slots }) {
|
|
39
|
-
var _a;
|
|
40
|
-
const isHorizontal = props.horizontal;
|
|
41
|
-
const rootRef = ref();
|
|
42
|
-
const store = createVirtualStore(props.data.length, (_a = props.itemSize) !== null && _a !== void 0 ? _a : 40, undefined, undefined, !props.itemSize);
|
|
43
|
-
const resizer = createResizer(store, isHorizontal);
|
|
44
|
-
const scroller = createScroller(store, isHorizontal);
|
|
45
|
-
const rerender = ref(store._getStateVersion());
|
|
46
|
-
const unsubscribeStore = store._subscribe(UPDATE_SCROLL_STATE + UPDATE_SIZE_STATE, () => {
|
|
47
|
-
rerender.value = store._getStateVersion();
|
|
48
|
-
});
|
|
49
|
-
const unsubscribeOnScroll = store._subscribe(UPDATE_SCROLL_EVENT, () => {
|
|
50
|
-
emit("scroll", store._getScrollOffset());
|
|
51
|
-
});
|
|
52
|
-
const unsubscribeOnScrollEnd = store._subscribe(UPDATE_SCROLL_END_EVENT, () => {
|
|
53
|
-
emit("scrollEnd");
|
|
54
|
-
});
|
|
55
|
-
onMounted(() => {
|
|
56
|
-
const root = rootRef.value;
|
|
57
|
-
if (!root)
|
|
58
|
-
return;
|
|
59
|
-
resizer._observeRoot(root);
|
|
60
|
-
scroller._observe(root);
|
|
61
|
-
});
|
|
62
|
-
onUnmounted(() => {
|
|
63
|
-
unsubscribeStore();
|
|
64
|
-
unsubscribeOnScroll();
|
|
65
|
-
unsubscribeOnScrollEnd();
|
|
66
|
-
resizer._dispose();
|
|
67
|
-
scroller._dispose();
|
|
68
|
-
});
|
|
69
|
-
watch(() => props.data.length, (count) => {
|
|
70
|
-
store._update(ACTION_ITEMS_LENGTH_CHANGE, [count, props.shift]);
|
|
71
|
-
});
|
|
72
|
-
watch([rerender, store._getJumpCount], ([, count], [, prevCount]) => {
|
|
73
|
-
if (count === prevCount)
|
|
74
|
-
return;
|
|
75
|
-
const jump = store._flushJump();
|
|
76
|
-
if (!jump)
|
|
77
|
-
return;
|
|
78
|
-
scroller._fixScrollJump(jump);
|
|
79
|
-
}, { flush: "post" });
|
|
80
|
-
watch([rerender, store._getRange], ([, [start, end]], [, [prevStart, prevEnd]]) => {
|
|
81
|
-
if (prevStart === start && prevEnd === end)
|
|
82
|
-
return;
|
|
83
|
-
emit("rangeChange", start, end);
|
|
84
|
-
}, { flush: "post" });
|
|
85
|
-
expose({
|
|
86
|
-
get scrollOffset() {
|
|
87
|
-
return store._getScrollOffset();
|
|
88
|
-
},
|
|
89
|
-
get scrollSize() {
|
|
90
|
-
return getScrollSize(store);
|
|
91
|
-
},
|
|
92
|
-
get viewportSize() {
|
|
93
|
-
return store._getViewportSize();
|
|
94
|
-
},
|
|
95
|
-
scrollToIndex: scroller._scrollToIndex,
|
|
96
|
-
scrollTo: scroller._scrollTo,
|
|
97
|
-
scrollBy: scroller._scrollBy,
|
|
98
|
-
});
|
|
99
|
-
return () => {
|
|
100
|
-
rerender.value;
|
|
101
|
-
const count = props.data.length;
|
|
102
|
-
const [startIndex, endIndex] = store._getRange();
|
|
103
|
-
const scrollDirection = store._getScrollDirection();
|
|
104
|
-
const totalSize = store._getTotalSize();
|
|
105
|
-
// https://github.com/inokawa/virtua/issues/252#issuecomment-1822861368
|
|
106
|
-
const minSize = getMinContainerSize(store);
|
|
107
|
-
const items = [];
|
|
108
|
-
for (let i = overscanStartIndex(startIndex, props.overscan, scrollDirection), j = overscanEndIndex(endIndex, props.overscan, scrollDirection, count); i <= j; i++) {
|
|
109
|
-
const e = slots.default(props.data[i])[0];
|
|
110
|
-
const key = e.key;
|
|
111
|
-
items.push(_jsx(ListItem, { _resizer: resizer._observeItem, _index: i, _offset: store._getItemOffset(i), _hide: store._isUnmeasuredItem(i), _element: "div", _children: e, _isHorizontal: isHorizontal }, exists(key) ? key : "_" + i));
|
|
112
|
-
}
|
|
113
|
-
return (_jsx("div", { ref: rootRef, style: {
|
|
114
|
-
display: isHorizontal ? "inline-block" : "block",
|
|
115
|
-
[isHorizontal ? "overflowX" : "overflowY"]: "auto",
|
|
116
|
-
overflowAnchor: "none",
|
|
117
|
-
contain: "strict",
|
|
118
|
-
width: "100%",
|
|
119
|
-
height: "100%",
|
|
120
|
-
}, children: _jsx("div", { style: {
|
|
121
|
-
// contain: "content",
|
|
122
|
-
overflowAnchor: "none", // opt out browser's scroll anchoring because it will conflict to scroll anchoring of virtualizer
|
|
123
|
-
flex: "none", // flex style on parent can break layout
|
|
124
|
-
position: "relative",
|
|
125
|
-
visibility: "hidden",
|
|
126
|
-
width: isHorizontal ? totalSize + "px" : "100%",
|
|
127
|
-
height: isHorizontal ? "100%" : totalSize + "px",
|
|
128
|
-
[isHorizontal ? "minWidth" : "minHeight"]: minSize + "px",
|
|
129
|
-
pointerEvents: scrollDirection !== SCROLL_IDLE ? "none" : "auto",
|
|
130
|
-
}, children: items }) }));
|
|
131
|
-
};
|
|
132
|
-
},
|
|
133
|
-
});
|