@shijiu/jsview-vue-samples 2.3.0 → 2.3.151-test.0

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.
Files changed (117) hide show
  1. package/DashPath/App.vue +17 -16
  2. package/DashPath/AppForOperator.vue +2 -4
  3. package/DemoForOperator/AnimPic/AnimPic.vue +24 -2
  4. package/DemoForOperator/Banger/Banger/Banger.vue +73 -9
  5. package/DemoForOperator/Blur/Blur.vue +146 -0
  6. package/DemoForOperator/Blur/BlurInOut/BlurInOut.vue +158 -0
  7. package/DemoForOperator/Blur/BlurInOut/StaticBgSlide.vue +162 -0
  8. package/DemoForOperator/Blur/BlurPopup/BlurPopup.vue +113 -0
  9. package/DemoForOperator/BookFlip/App.vue +115 -0
  10. package/DemoForOperator/BookFlip/BookFlip/FlipPage.vue +179 -0
  11. package/DemoForOperator/BookFlip/BookFlip/FlippingBook.vue +310 -0
  12. package/DemoForOperator/BookFlip/BookFlip/flip.glsl +135 -0
  13. package/DemoForOperator/BookFlip/BookPage.vue +82 -0
  14. package/DemoForOperator/Bounce/Bounce.vue +33 -1
  15. package/DemoForOperator/ChunLian/Couplets.vue +44 -1
  16. package/DemoForOperator/ClickSpriteAnim/App.vue +130 -0
  17. package/DemoForOperator/ClickSpriteAnim/Item.vue +74 -0
  18. package/DemoForOperator/DominantColor/App.vue +187 -0
  19. package/DemoForOperator/EpisodeList/EpisodeList/Controller.vue +0 -3
  20. package/DemoForOperator/EpisodeList/EpisodeList/EpisodeList.vue +76 -2
  21. package/DemoForOperator/Firework1/App.vue +1 -1
  22. package/DemoForOperator/Firework1/Fireworks.vue +50 -11
  23. package/DemoForOperator/FlipPage/FlipPage/FlipPage.vue +29 -1
  24. package/DemoForOperator/Focus/Alpha/AlphaFocusBox.vue +27 -2
  25. package/DemoForOperator/Focus/Light/LightFocusBox.vue +42 -1
  26. package/DemoForOperator/Focus/Normal/NormalFocusBox.vue +12 -0
  27. package/DemoForOperator/FrameShadow/App.vue +193 -0
  28. package/DemoForOperator/FrameShadow/FrameShadow.vue +61 -0
  29. package/DemoForOperator/FullscreenIn/App.vue +1 -1
  30. package/DemoForOperator/FullscreenIn/FullscreenPoster.vue +18 -3
  31. package/DemoForOperator/Genie/geniePakcer/Genie.vue +60 -18
  32. package/DemoForOperator/GrayFilter/GrayFilter.vue +21 -0
  33. package/DemoForOperator/Jigsaw/JigsawFull.vue +46 -4
  34. package/DemoForOperator/Jigsaw/JigsawSingle.vue +34 -2
  35. package/DemoForOperator/LongChatBox/App.vue +36 -0
  36. package/DemoForOperator/LongChatBox/Bubble.vue +104 -0
  37. package/DemoForOperator/LongChatBox/LongChat.vue +173 -0
  38. package/DemoForOperator/LongChatBox/TextManager.ts +147 -0
  39. package/DemoForOperator/LongChatBox/VirtualList.vue +298 -0
  40. package/DemoForOperator/LongChatBox/testData.js +51 -0
  41. package/DemoForOperator/LongChatBox/utile.js +331 -0
  42. package/DemoForOperator/Particle/Drop/DropParticle.vue +33 -1
  43. package/DemoForOperator/Particle/Explode/ExplodeParticle.vue +23 -2
  44. package/DemoForOperator/PosterAnim/PosterAnim.js +21 -0
  45. package/DemoForOperator/PosterOverflow/PosterOverflow.vue +16 -0
  46. package/DemoForOperator/Resize/App.vue +157 -0
  47. package/DemoForOperator/Resize/Resize/Item.vue +234 -0
  48. package/DemoForOperator/Resize/Resize/Resize.vue +96 -0
  49. package/DemoForOperator/Ripple/Ripple.vue +16 -1
  50. package/DemoForOperator/ScreenShootScale/App.vue +96 -0
  51. package/DemoForOperator/ScreenShootScale/Back.vue +86 -0
  52. package/DemoForOperator/ScreenShootScale/Front.vue +133 -0
  53. package/DemoForOperator/ScreenShootScale/Item.vue +62 -0
  54. package/DemoForOperator/ScreenShootScale/ScreenShootScale.vue +109 -0
  55. package/DemoForOperator/SmoothSwiper/App.vue +50 -0
  56. package/DemoForOperator/Sound/Bounce/App.vue +56 -0
  57. package/DemoForOperator/Sound/Bounce/Bounce.vue +87 -0
  58. package/DemoForOperator/Sound/Bounce/FreeMoveBuilder.js +146 -0
  59. package/DemoForOperator/Sound/Bounce/bgmusic.mp3 +0 -0
  60. package/DemoForOperator/Sound/Bounce/coin.mp3 +0 -0
  61. package/DemoForOperator/Sound/FocusMove/App.vue +134 -0
  62. package/DemoForOperator/Sound/FocusMove/Item.vue +43 -0
  63. package/DemoForOperator/Sound/FocusMove/move.mp3 +0 -0
  64. package/DemoForOperator/Sound/Rain/App.vue +11 -0
  65. package/DemoForOperator/Sound/Rain/Raining/Rain.vue +69 -0
  66. package/DemoForOperator/Sound/Rain/Raining/RainScene.vue +118 -0
  67. package/DemoForOperator/Sound/Sound/Sound.vue +24 -0
  68. package/DemoForOperator/Sound/Sound/index.js +4 -0
  69. package/DemoForOperator/Sound/Sound/useSound.js +112 -0
  70. package/DemoForOperator/Sprite/Sprite.vue +62 -5
  71. package/DemoForOperator/Stretch/Stretch/Stretch.vue +52 -2
  72. package/DemoForOperator/Swiper/App.vue +101 -0
  73. package/DemoForOperator/Swiper/Item.vue +56 -0
  74. package/DemoForOperator/Swiper/ParallaxSlide.vue +164 -0
  75. package/DemoForOperator/TabContent/TabContent/TabContent.vue +39 -1
  76. package/DemoForOperator/TabContentVertical/App.vue +104 -0
  77. package/DemoForOperator/TabContentVertical/ContentPage.vue +67 -0
  78. package/DemoForOperator/TabContentVertical/Item.vue +94 -0
  79. package/DemoForOperator/TabContentVertical/PageItem.vue +40 -0
  80. package/DemoForOperator/TabContentVertical/TabContent/CreepFocus.vue +160 -0
  81. package/DemoForOperator/TabContentVertical/TabContent/Item.vue +63 -0
  82. package/DemoForOperator/TabContentVertical/TabContent/TabContent.vue +184 -0
  83. package/DemoForOperator/TabContentVertical/TabContent/TabItem.vue +368 -0
  84. package/DemoForOperator/TabContentVertical/TabContent/TabWidget.vue +259 -0
  85. package/DemoForOperator/TabContentVertical/TabContent/Util.js +3 -0
  86. package/DemoForOperator/TabContentVertical/TabContent/ViewSwiper.vue +110 -0
  87. package/DemoForOperator/TabContentVertical/assets/children_science.png +0 -0
  88. package/DemoForOperator/TabContentVertical/assets/documentary.png +0 -0
  89. package/DemoForOperator/TabContentVertical/assets/free.png +0 -0
  90. package/DemoForOperator/TabContentVertical/assets/game.png +0 -0
  91. package/DemoForOperator/TabContentVertical/assets/home_selected.png +0 -0
  92. package/DemoForOperator/TabContentVertical/assets/movie_ticket.png +0 -0
  93. package/DemoForOperator/TabContentVertical/assets/my_account.png +0 -0
  94. package/DemoForOperator/TabContentVertical/assets/opera.png +0 -0
  95. package/DemoForOperator/TabContentVertical/assets/sports.png +0 -0
  96. package/DemoForOperator/TabContentVertical/assets/tv_drama.png +0 -0
  97. package/DemoForOperator/TabContentVertical/assets/variety_show.png +0 -0
  98. package/DemoForOperator/TabContentVertical/assets/vip.png +0 -0
  99. package/DemoForOperator/TabContentVertical/testData.js +76 -0
  100. package/DemoForOperator/Vortex/Vortex/Vortex.vue +26 -0
  101. package/DemoForOperator/routeList.js +118 -1
  102. package/DemoHomepage/components/Item.vue +11 -0
  103. package/DemoHomepage/router.js +75 -1
  104. package/GiftRain/components/SpriteTranslate.vue +68 -48
  105. package/HashHistory/App.vue +2 -2
  106. package/HashHistory/router.js +1 -1
  107. package/MetroWidgetDemos/TripleWidget/App.vue +7 -1
  108. package/MetroWidgetDemos/TripleWidget/Item.vue +16 -2
  109. package/MetroWidgetDemos/TripleWidget/SWidgetItem.vue +7 -1
  110. package/MetroWidgetDemos/TripleWidget/WidgetItem.vue +8 -2
  111. package/MetroWidgetDemos/routeList.js +17 -0
  112. package/PosterPacker/App.vue +2 -2
  113. package/ViewOpacity/App.vue +19 -0
  114. package/package.json +1 -1
  115. package/DashPath/DashPath.vue +0 -118
  116. package/DemoForOperator/ScalePoster/App.vue +0 -4
  117. package/DemoForOperator/ScalePoster/ScalePoster.vue +0 -0
@@ -0,0 +1,104 @@
1
+ <script setup>
2
+ import { TextManager } from "./TextManager";
3
+ import { ref, onBeforeUnmount, onMounted, shallowRef } from "vue";
4
+ import { JsvTextBox } from "@shijiu/jsview-vue";
5
+
6
+ import VirtualList from "./VirtualList.vue";
7
+
8
+ const emit = defineEmits(["sizechange"]);
9
+ const props = defineProps({
10
+ data: Array,
11
+ onDone: Function,
12
+ left: Number,
13
+ visibleRect: Object,
14
+ });
15
+
16
+ const listRef = shallowRef();
17
+
18
+ function onAddLine(line) {
19
+ listRef.value.addItem(line.lineNumber, line);
20
+ }
21
+
22
+ function onLineUpdate(line) {}
23
+
24
+ function onLineUpdateDone(line) {
25
+ listRef.value.itemUpdateDone(line.lineNumber);
26
+ }
27
+
28
+ const textManager = new TextManager(
29
+ props.visibleRect.width,
30
+ onAddLine,
31
+ onLineUpdate,
32
+ onLineUpdateDone
33
+ );
34
+ const textRef = ref("");
35
+ let intervalHandel = -1;
36
+ function start() {
37
+ let currentIndex = 0;
38
+ intervalHandel = setInterval(() => {
39
+ if (currentIndex < props.data.length) {
40
+ textManager.addText(props.data[currentIndex], textRef);
41
+ currentIndex++;
42
+ } else {
43
+ clearInterval(intervalHandel);
44
+ textManager.stopUpdateLineManually();
45
+ props.onDone?.();
46
+ }
47
+ }, 50);
48
+ }
49
+
50
+ onBeforeUnmount(() => {
51
+ clearInterval(intervalHandel);
52
+ });
53
+
54
+ onMounted(() => {
55
+ start();
56
+ });
57
+
58
+ function show() {
59
+ listRef.value?.show();
60
+ }
61
+
62
+ function hide() {
63
+ listRef.value?.hide();
64
+ }
65
+
66
+ function setVisibleRectStart(distance) {
67
+ listRef.value?.setVisibleRectStart(distance);
68
+ }
69
+
70
+ function onSizeChange(height) {
71
+ emit("sizechange", height);
72
+ }
73
+
74
+ defineExpose({
75
+ show,
76
+ hide,
77
+ setVisibleRectStart,
78
+ });
79
+ </script>
80
+
81
+ <template>
82
+ <virtual-list
83
+ :layout="{
84
+ width: visibleRect.width,
85
+ height: visibleRect.height,
86
+ left: left,
87
+ }"
88
+ ref="listRef"
89
+ @sizechange="onSizeChange"
90
+ >
91
+ <template #="{ data }">
92
+ <jsv-text-box
93
+ :enableLatex="true"
94
+ syncDraw="sync"
95
+ :style="{
96
+ width: visibleRect.width,
97
+ ...data.style,
98
+ }"
99
+ >
100
+ {{ data.lineNumber + ":" + String(data.text) }}
101
+ </jsv-text-box>
102
+ </template>
103
+ </virtual-list>
104
+ </template>
@@ -0,0 +1,173 @@
1
+ <script setup>
2
+ import { ref, reactive } from "vue";
3
+ import { testMessage, data1 } from "./testData.js";
4
+ import Bubble from "./Bubble.vue";
5
+
6
+ //可视范围的位置
7
+ let visibleStart = ref(0);
8
+
9
+ //聊天泡泡的消息列表
10
+ let messageList = [];
11
+ let renderList = reactive([]);
12
+ let totalHeight = 0;
13
+
14
+ function createMessageItem(key, data, left, top, width, height) {
15
+ let item = {
16
+ key,
17
+ data,
18
+ left: ref(left),
19
+ top: ref(top),
20
+ width: ref(width),
21
+ height: ref(height),
22
+ ref: null,
23
+ onDone() {},
24
+ onSizeChange(height) {
25
+ this.height.value = height;
26
+ arrangeLayout();
27
+ updateRenderList();
28
+ },
29
+ onRef(ref) {
30
+ this.ref = ref;
31
+ },
32
+ show() {
33
+ this.ref?.show();
34
+ },
35
+ hide() {
36
+ this.ref?.hide();
37
+ },
38
+ };
39
+ item.onDone = item.onDone.bind(item);
40
+ item.onSizeChange = item.onSizeChange.bind(item);
41
+ item.onRef = item.onRef.bind(item);
42
+ item.show = item.show.bind(item);
43
+ item.hide = item.hide.bind(item);
44
+ return item;
45
+ }
46
+
47
+ function arrangeLayout() {
48
+ //更新item的布局
49
+ totalHeight = 0;
50
+ for (let i = 0; i < messageList.length; i++) {
51
+ const item = messageList[i];
52
+ item.top.value = totalHeight;
53
+ totalHeight += item.height.value;
54
+ }
55
+ }
56
+
57
+ function updateRenderList() {
58
+ renderList.length = 0;
59
+ if (autoSlideMode) {
60
+ //自动保持一行模式, 根据总高度和可视范围的高度, 计算出可视范围的开始位置
61
+ visibleStart.value = totalHeight > 600 ? totalHeight - 600 : 0;
62
+ }
63
+ for (let i = 0; i < messageList.length; i++) {
64
+ const item = messageList[i];
65
+ renderList.push(item);
66
+ if (
67
+ item.top.value + item.height.value >= visibleStart.value &&
68
+ item.top.value <= visibleStart.value + 600
69
+ ) {
70
+ //可见的泡泡, 显示
71
+ item.show();
72
+ //此处要设置虚拟列表的可视范围的开始位置, 注意是转化为相对这个item的偏移量
73
+ item.ref?.setVisibleRectStart(visibleStart.value - item.top.value);
74
+ } else {
75
+ //不可见的泡泡, 隐藏
76
+ item.hide();
77
+ }
78
+ }
79
+ }
80
+
81
+ let count = 0;
82
+ function addData() {
83
+ let item;
84
+ const lastItem = messageList[messageList.length - 1];
85
+ if (count++ % 3 == 1) {
86
+ item = createMessageItem(
87
+ count,
88
+ testMessage,
89
+ 200,
90
+ lastItem ? lastItem.top.value + lastItem.height.value : 0,
91
+ 800,
92
+ 100
93
+ );
94
+ } else {
95
+ item = createMessageItem(
96
+ count,
97
+ data1,
98
+ 0,
99
+ lastItem ? lastItem.top.value + lastItem.height.value : 0,
100
+ 800,
101
+ 100
102
+ );
103
+ }
104
+ messageList.push(item);
105
+ updateRenderList();
106
+ }
107
+
108
+ function normalizeSlidePos(pos) {
109
+ return Math.min(Math.max(pos, 0), totalHeight - 600);
110
+ }
111
+
112
+ let autoSlideMode = true;
113
+ const onKeyDown = (ev) => {
114
+ switch (ev.keyCode) {
115
+ case 38:
116
+ autoSlideMode = false;
117
+ visibleStart.value = normalizeSlidePos(visibleStart.value - 100);
118
+ updateRenderList();
119
+ return true;
120
+ case 40:
121
+ visibleStart.value = normalizeSlidePos(visibleStart.value + 100);
122
+ if (visibleStart.value != totalHeight - 600) {
123
+ autoSlideMode = false;
124
+ } else {
125
+ autoSlideMode = true;
126
+ }
127
+ updateRenderList();
128
+ return true;
129
+ case 13:
130
+ addData();
131
+ return true;
132
+ }
133
+ return false;
134
+ };
135
+ </script>
136
+
137
+ <template>
138
+ <jsv-focus-block
139
+ autoFocus
140
+ :onAction="{
141
+ onKeyDown,
142
+ }"
143
+ ></jsv-focus-block>
144
+ <div
145
+ :style="{
146
+ top: -visibleStart,
147
+ }"
148
+ >
149
+ <template v-for="item in renderList">
150
+ <div
151
+ :style="{
152
+ left: item.left,
153
+ top: item.top,
154
+ width: item.width,
155
+ height: item.height,
156
+ // backgroundColor: '#99999999',
157
+ }"
158
+ >
159
+ <bubble
160
+ :data="item.data"
161
+ :onDone="item.onDone"
162
+ :left="0"
163
+ :visibleRect="{
164
+ width: 800,
165
+ height: 600,
166
+ }"
167
+ @sizechange="item.onSizeChange"
168
+ :ref="item.onRef"
169
+ ></bubble>
170
+ </div>
171
+ </template>
172
+ </div>
173
+ </template>
@@ -0,0 +1,147 @@
1
+ /**
2
+ * 处理流式文本的分行
3
+ */
4
+ import {
5
+ TypeTransitionApi,
6
+ StyleTransitionApi2,
7
+ TextTransitionApi,
8
+ } from "./utile";
9
+ import { reactive, ref, Ref, shallowRef, ShallowRef } from "vue";
10
+
11
+ interface Rect {
12
+ left: number;
13
+ top: number;
14
+ width: number;
15
+ height: number;
16
+ }
17
+
18
+ interface LineInfo {
19
+ type: "text" | "horizontalLine";
20
+ text: Ref<string>;
21
+ style: unknown;
22
+ rect: Rect;
23
+ lineNumber: number;
24
+ }
25
+
26
+ export class TextManager {
27
+ public lines: LineInfo[] = [];
28
+ public updatingLine: LineInfo | null = null;
29
+ public currentLineStyle: any = {};
30
+ private textWidth: number = 0;
31
+ private onAddLine: Function = (line: LineInfo) => {};
32
+ private onLineUpdatDone: Function = (line: LineInfo) => {};
33
+ private onLineUpdate: Function = (line: LineInfo) => {};
34
+
35
+ constructor(
36
+ textWidth: number,
37
+ onAddLine: (line: LineInfo) => void,
38
+ onLineUpdate: (line: LineInfo) => void,
39
+ onLineUpdatDone: (line: LineInfo) => void,
40
+ ) {
41
+ this.textWidth = textWidth;
42
+ this.onAddLine = onAddLine;
43
+ this.onLineUpdatDone = onLineUpdatDone;
44
+ this.onLineUpdate = onLineUpdate;
45
+ }
46
+
47
+ public addText(textSlice: string, textRef: Ref<string>) {
48
+ if (!this.updatingLine) {
49
+ const type = TypeTransitionApi(textSlice);
50
+ this.currentLineStyle = StyleTransitionApi2(textSlice);
51
+ let left = 0,
52
+ top = 0;
53
+ if (this.lines.length > 0) {
54
+ const lastLine = this.lines[this.lines.length - 1];
55
+ left = lastLine.rect.left;
56
+ top = lastLine.rect.top + lastLine.rect.height;
57
+ }
58
+ this.updatingLine = this.newLine();
59
+ }
60
+
61
+ // 检查是否有换行符
62
+ if (textSlice.match(/(\r\n|\n|\r)/)) {
63
+ // 将文本按换行符分割
64
+ const parts = textSlice.split(/(\r\n|\n|\r)/);
65
+ // 只处理第一部分(换行符之前的内容)
66
+ if (parts.length > 0 && parts[0]) {
67
+ this.updatingLine.text.value += parts[0];
68
+ }
69
+
70
+ // 完成当前行并添加到lines数组
71
+ this.commitLine();
72
+
73
+ // 如果换行符后还有内容,为下一行创建新的行对象
74
+ if (parts.length > 2 && parts[2]) {
75
+ const nextType = TypeTransitionApi(parts[2]);
76
+ const nextStyle = StyleTransitionApi2(parts[2]);
77
+
78
+ this.updatingLine = this.newLine(parts[2]);
79
+ } else {
80
+ // 如果换行符后没有内容,将updatingLine设为null,等待下一次addText调用
81
+ this.updatingLine = null;
82
+ }
83
+
84
+ textRef.value = this.updatingLine?.text.value ?? "";
85
+ return;
86
+ }
87
+ // 没有换行符,直接添加到当前行
88
+ this.updatingLine.text.value += textSlice;
89
+ if (this.updatingLine.text.value.length > 33) {
90
+ const preText = this.updatingLine.text.value.slice(0, 33);
91
+ const nextText = this.updatingLine.text.value.slice(33);
92
+ this.updatingLine.text.value = preText;
93
+ this.commitLine();
94
+ this.updatingLine = this.newLine(nextText);
95
+ } else {
96
+ this.onLineUpdate(this.updatingLine);
97
+ }
98
+ textRef.value = this.updatingLine?.text.value ?? "";
99
+ }
100
+
101
+ public stopUpdateLineManually() {
102
+ if (this.updatingLine) {
103
+ this.commitLine();
104
+ this.updatingLine = null;
105
+ }
106
+ }
107
+
108
+ public updateLineHeight(height: number) {
109
+ if (this.updatingLine) {
110
+ console.log(
111
+ "ccht updateLineHeight",
112
+ this.updatingLine.lineNumber,
113
+ height
114
+ );
115
+ this.updatingLine.rect.height = height;
116
+ }
117
+ }
118
+
119
+ private commitLine() {
120
+ if (this.updatingLine) {
121
+ //做 markdown 的替换
122
+ this.updatingLine.text.value = TextTransitionApi(
123
+ this.updatingLine.text.value
124
+ );
125
+ this.lines.push(this.updatingLine);
126
+ this.updatingLine = null;
127
+ this.onLineUpdatDone(this.lines[this.lines.length - 1]);
128
+ }
129
+ }
130
+
131
+ private newLine(text: string = "") {
132
+ const line = {
133
+ type: "text" as const,
134
+ text: ref(text),
135
+ style: this.currentLineStyle,
136
+ rect: {
137
+ left: 0,
138
+ top: 0,
139
+ width: 0,
140
+ height: 0,
141
+ },
142
+ lineNumber: this.lines.length,
143
+ };
144
+ this.onAddLine(line);
145
+ return line;
146
+ }
147
+ }
@@ -0,0 +1,298 @@
1
+ <script>
2
+ /**
3
+ * 虚拟列表, 超出可以范围的元素会被隐藏
4
+ */
5
+ let IdToken = 0;
6
+ </script>
7
+ <script setup>
8
+ import { JsvFlexDiv } from "jsview";
9
+ import { ref, shallowRef, reactive, computed } from "vue";
10
+
11
+ const emit = defineEmits(["sizechange"]);
12
+
13
+ const props = defineProps({
14
+ layout: {
15
+ type: Object,
16
+ default: () => ({
17
+ width: 0,
18
+ height: 0,
19
+ left: 0,
20
+ top: 0,
21
+ }),
22
+ },
23
+ initVisibleStart: {
24
+ type: Number,
25
+ default: 0,
26
+ },
27
+ });
28
+ const renderList = reactive([]);
29
+ const visibleStart = ref(props.initVisibleStart);
30
+ const totalContentWidth = ref(props.layout.width);
31
+ const totalContentHeight = ref(0);
32
+ let isVisible = true;
33
+ //默认自动显示最后一行, 外部调用 slideTo 后不再自动移动
34
+ let enableAutoSlide = true;
35
+ let itemList = [];
36
+
37
+ class ItemInfo {
38
+ constructor(customKey, id, customData, tmpTop) {
39
+ this.id = id;
40
+ this.customKey = customKey;
41
+ this.layout = {
42
+ left: 0,
43
+ top: tmpTop,
44
+ width: 0,
45
+ height: 0,
46
+ };
47
+ this.data = customData;
48
+ this.onSize = this._onSize.bind(this);
49
+ this.done = this._done.bind(this);
50
+ this._onSizeCalled = false;
51
+ this._updateDone = false;
52
+ }
53
+
54
+ _onSize(width, height) {
55
+ this.layout.width = width;
56
+ this.layout.height = height;
57
+ onItemSizeUpdate(this.id);
58
+ updateRenderList();
59
+ this._onSizeCalled = true;
60
+ }
61
+
62
+ _done() {
63
+ this._updateDone = true;
64
+ }
65
+
66
+ isStatic() {
67
+ return this._updateDone && this._onSizeCalled;
68
+ }
69
+ }
70
+
71
+ function onItemSizeUpdate(id) {
72
+ //更新itemlayout
73
+ let start = 0;
74
+ for (let i = 0; i < itemList.length; i++) {
75
+ const item = itemList[i];
76
+ if (item.id >= id) {
77
+ item.layout.top = start;
78
+ }
79
+ start += item.layout.height;
80
+ }
81
+ totalContentHeight.value = start;
82
+ emit("sizechange", totalContentHeight.value);
83
+ }
84
+
85
+ const EXTRA_RECT = 100;
86
+ function updateRenderList() {
87
+ renderList.splice(0);
88
+ if (!isVisible) {
89
+ return;
90
+ }
91
+ if (enableAutoSlide) {
92
+ let h = 0;
93
+ for (let i = itemList.length - 1; i >= 0; --i) {
94
+ const item = itemList[i];
95
+ renderList.unshift(item);
96
+ h += item.layout.height;
97
+ if (h >= props.layout.height + EXTRA_RECT) {
98
+ break;
99
+ }
100
+ }
101
+ visibleStart.value = Math.max(
102
+ totalContentHeight.value - props.layout.height,
103
+ 0
104
+ );
105
+ } else {
106
+ for (let i = 0; i < itemList.length; i++) {
107
+ const item = itemList[i];
108
+ if (
109
+ (item.layout.top + item.layout.height >=
110
+ visibleStart.value - EXTRA_RECT &&
111
+ item.layout.top <= visibleStart.value + props.layout.height) ||
112
+ (item.layout.top > visibleStart.value + props.layout.height &&
113
+ !item.isStatic()) // 未更新完高度的需要继续描画, 以获取其size
114
+ ) {
115
+ renderList.push(item);
116
+ }
117
+ }
118
+ }
119
+ }
120
+
121
+ function addItem(key, data) {
122
+ const curLastItemPos =
123
+ itemList.length > 0
124
+ ? itemList[itemList.length - 1].layout.top +
125
+ itemList[itemList.length - 1].layout.height
126
+ : 0;
127
+ const item = new ItemInfo(key, IdToken++, data, curLastItemPos);
128
+ itemList.push(item);
129
+ updateRenderList();
130
+ return item;
131
+ }
132
+
133
+ function itemUpdateDone(key) {
134
+ // 通过key找到对应的item,并调用其done方法
135
+ const item = itemList.find((item) => item.customKey === key);
136
+ if (item) {
137
+ item.done();
138
+ }
139
+ }
140
+
141
+ function totalSizeOnUpdate(width, height) {
142
+ // totalContentHeight.value = height;
143
+ }
144
+
145
+ function slideTo(position) {
146
+ visibleStart.value = position;
147
+ updateRenderList();
148
+ }
149
+
150
+ function goUp(distance) {
151
+ let newPos = Math.max(visibleStart.value - distance, 0);
152
+ if (visibleStart.value != newPos) {
153
+ enableAutoSlide = false;
154
+ }
155
+ slideTo(newPos);
156
+ }
157
+
158
+ function goDown(distance) {
159
+ let newPos;
160
+ if (
161
+ visibleStart.value + distance >=
162
+ totalContentHeight.value - props.layout.height
163
+ ) {
164
+ enableAutoSlide = true;
165
+ newPos = totalContentHeight.value - props.layout.height;
166
+ } else {
167
+ enableAutoSlide = false;
168
+ newPos = visibleStart.value + distance;
169
+ }
170
+ slideTo(newPos);
171
+ }
172
+
173
+ const prePlaceHolderHeight = computed(() => {
174
+ if (renderList.length > 0) {
175
+ return renderList[0].layout.top;
176
+ } else {
177
+ //为0时, jsv-flex-div排版有问题
178
+ return totalContentHeight.value === 0 ? 1 : totalContentHeight.value;
179
+ }
180
+ });
181
+
182
+ const postPlaceHolderHeight = computed(() => {
183
+ if (renderList.length > 0) {
184
+ return (
185
+ totalContentHeight.value -
186
+ renderList[renderList.length - 1].layout.top -
187
+ renderList[renderList.length - 1].layout.height
188
+ );
189
+ } else {
190
+ return 1;
191
+ }
192
+ });
193
+
194
+ /**
195
+ * 获取虚拟列表的总高度
196
+ * @returns
197
+ */
198
+ function getTotalHeight() {
199
+ return totalContentHeight.value;
200
+ }
201
+
202
+ /**
203
+ * 隐藏
204
+ */
205
+ function hide() {
206
+ if (isVisible) {
207
+ isVisible = false;
208
+ updateRenderList();
209
+ }
210
+ }
211
+
212
+ /**
213
+ * 显示
214
+ */
215
+ function show() {
216
+ if (!isVisible) {
217
+ isVisible = true;
218
+ updateRenderList();
219
+ }
220
+ }
221
+
222
+ /**
223
+ * 设置可视范围的开始位置
224
+ * @param pos
225
+ */
226
+ function setVisibleRectStart(pos) {
227
+ const endPos = totalContentHeight.value - props.layout.height;
228
+ let newPos = Math.min(endPos, Math.max(pos, 0));
229
+ if (newPos == visibleStart.value) {
230
+ return;
231
+ }
232
+ if (newPos == endPos) {
233
+ enableAutoSlide = true;
234
+ } else {
235
+ enableAutoSlide = false;
236
+ }
237
+ slideTo(newPos);
238
+ }
239
+
240
+ defineExpose({
241
+ addItem,
242
+ goUp,
243
+ goDown,
244
+ itemUpdateDone,
245
+ getTotalHeight,
246
+ hide,
247
+ show,
248
+ setVisibleRectStart,
249
+ });
250
+ </script>
251
+
252
+ <template>
253
+ <div
254
+ :style="{
255
+ width: props.layout.width,
256
+ height: totalContentHeight,
257
+ }"
258
+ >
259
+ <jsv-flex-div
260
+ key="root"
261
+ :style="{
262
+ flexDirection: 'column',
263
+ width: props.layout.width,
264
+ }"
265
+ :onSized="totalSizeOnUpdate"
266
+ >
267
+ <div
268
+ id="pre-placeholder"
269
+ :style="{
270
+ width: props.layout.width,
271
+ height: prePlaceHolderHeight,
272
+ }"
273
+ ></div>
274
+ <template v-for="item in renderList" :key="item.id">
275
+ <div
276
+ v-if="item.isStatic()"
277
+ :key="item.id"
278
+ :style="{
279
+ width: props.layout.width,
280
+ height: item.layout.height,
281
+ }"
282
+ >
283
+ <slot :data="item.data"></slot>
284
+ </div>
285
+ <jsv-flex-div v-else :onSized="item.onSize" :key="item.id">
286
+ <slot :data="item.data"></slot>
287
+ </jsv-flex-div>
288
+ </template>
289
+ <div
290
+ id="post-placeholder"
291
+ :style="{
292
+ width: props.layout.width,
293
+ height: postPlaceHolderHeight,
294
+ }"
295
+ ></div>
296
+ </jsv-flex-div>
297
+ </div>
298
+ </template>