@shijiu/jsview-vue-samples 2.2.426-test.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 (246) hide show
  1. package/BakeViewDemo/AnimatePic.vue +1 -1
  2. package/Basic/components/text/TextDirection.vue +7 -1
  3. package/BasicFocusControl/components/BaseBlock.vue +65 -18
  4. package/BreakRender/assets/imageList.json +235 -235
  5. package/ColorSpace/App.vue +2 -2
  6. package/CoupletsTest/App.vue +1 -1
  7. package/CoupletsTest/widget/Banger/Banger.vue +3 -3
  8. package/CoupletsTest/widget/Banger/MaroonLoader.vue +5 -5
  9. package/CoupletsTest/widget/Couplets/Couplets.vue +4 -4
  10. package/CoupletsTest/widget/Fireworks/Fireworks.vue +13 -13
  11. package/CustomShader/App.vue +4 -4
  12. package/CustomShader/gaussianBlur.glsl +1 -1
  13. package/DashPath/App.vue +80 -0
  14. package/DashPath/AppForOperator.vue +33 -0
  15. package/DemoForOperator/AnimPic/AnimPic.vue +69 -0
  16. package/DemoForOperator/AnimPic/App.vue +28 -0
  17. package/DemoForOperator/Banger/App.vue +26 -0
  18. package/DemoForOperator/Banger/Banger/Banger.vue +316 -0
  19. package/DemoForOperator/Banger/Banger/Maroon.vue +123 -0
  20. package/DemoForOperator/Banger/Banger/MaroonLoader.vue +78 -0
  21. package/DemoForOperator/Banger/Banger/SpriteDeal.js +30 -0
  22. package/DemoForOperator/Blur/Blur.vue +146 -0
  23. package/DemoForOperator/Blur/BlurInOut/BlurInOut.vue +158 -0
  24. package/DemoForOperator/Blur/BlurInOut/StaticBgSlide.vue +162 -0
  25. package/DemoForOperator/Blur/BlurPopup/BlurPopup.vue +113 -0
  26. package/DemoForOperator/BookFlip/App.vue +115 -0
  27. package/DemoForOperator/BookFlip/BookFlip/FlipPage.vue +179 -0
  28. package/DemoForOperator/BookFlip/BookFlip/FlippingBook.vue +310 -0
  29. package/DemoForOperator/BookFlip/BookFlip/flip.glsl +135 -0
  30. package/DemoForOperator/BookFlip/BookPage.vue +82 -0
  31. package/DemoForOperator/Bounce/App.vue +43 -0
  32. package/DemoForOperator/Bounce/Bounce.vue +81 -0
  33. package/DemoForOperator/Bounce/FreeMoveBuilder.js +139 -0
  34. package/DemoForOperator/ChunLian/App.vue +47 -0
  35. package/DemoForOperator/ChunLian/Couplets.vue +291 -0
  36. package/DemoForOperator/ClickSpriteAnim/App.vue +130 -0
  37. package/DemoForOperator/ClickSpriteAnim/Item.vue +74 -0
  38. package/DemoForOperator/DominantColor/App.vue +187 -0
  39. package/DemoForOperator/EpisodeList/App.vue +80 -0
  40. package/DemoForOperator/EpisodeList/EpisodeList/Controller.vue +110 -0
  41. package/DemoForOperator/EpisodeList/EpisodeList/EpisodeList.vue +250 -0
  42. package/DemoForOperator/EpisodeList/GroupItem.vue +65 -0
  43. package/DemoForOperator/EpisodeList/ListItem.vue +48 -0
  44. package/DemoForOperator/Firework1/App.vue +25 -0
  45. package/DemoForOperator/Firework1/Fireworks.vue +397 -0
  46. package/DemoForOperator/Firework1/SpriteDeal.js +30 -0
  47. package/DemoForOperator/FlipPage/App.vue +75 -0
  48. package/DemoForOperator/FlipPage/FlipPage/FlipPage.vue +178 -0
  49. package/DemoForOperator/FlipPage/FlipPage/flipIn.glsl +41 -0
  50. package/DemoForOperator/FlipPage/FlipPage/flipOut.glsl +41 -0
  51. package/DemoForOperator/Focus/Alpha/AlphaFocusBox.vue +95 -0
  52. package/DemoForOperator/Focus/Alpha/AlphaPage.vue +40 -0
  53. package/DemoForOperator/Focus/Alpha/Item.vue +64 -0
  54. package/DemoForOperator/Focus/App.vue +124 -0
  55. package/DemoForOperator/Focus/CommonPageSetting.js +30 -0
  56. package/DemoForOperator/Focus/Item.vue +46 -0
  57. package/DemoForOperator/Focus/Light/Item.vue +67 -0
  58. package/DemoForOperator/Focus/Light/LightFocusBox.vue +87 -0
  59. package/DemoForOperator/Focus/Light/LightPage.vue +43 -0
  60. package/DemoForOperator/Focus/Light/utils/FrameCanvasStore.ts +68 -0
  61. package/DemoForOperator/Focus/Light/utils/RotateFrame.vue +146 -0
  62. package/DemoForOperator/Focus/Light/utils/circleHaloMask.png +0 -0
  63. package/DemoForOperator/Focus/Normal/Item.vue +64 -0
  64. package/DemoForOperator/Focus/Normal/NormalFocusBox.vue +65 -0
  65. package/DemoForOperator/Focus/Normal/NormalPage.vue +41 -0
  66. package/DemoForOperator/Focus/SwipeLight/Item.vue +73 -0
  67. package/DemoForOperator/Focus/SwipeLight/SwipeLightBox.vue +62 -0
  68. package/DemoForOperator/Focus/SwipeLight/SwipeLightPage.vue +44 -0
  69. package/DemoForOperator/FrameShadow/App.vue +193 -0
  70. package/DemoForOperator/FrameShadow/FrameShadow.vue +61 -0
  71. package/DemoForOperator/FullscreenIn/App.vue +105 -0
  72. package/DemoForOperator/FullscreenIn/FullscreenPoster.vue +56 -0
  73. package/DemoForOperator/FullscreenIn/Item.vue +50 -0
  74. package/DemoForOperator/Genie/App.vue +78 -0
  75. package/DemoForOperator/Genie/geniePakcer/Genie.vue +741 -0
  76. package/DemoForOperator/Genie/geniePakcer/genieBottom.glsl +49 -0
  77. package/DemoForOperator/Genie/geniePakcer/genieLeft.glsl +50 -0
  78. package/DemoForOperator/Genie/geniePakcer/genieRight.glsl +57 -0
  79. package/DemoForOperator/Genie/geniePakcer/genieTop.glsl +50 -0
  80. package/DemoForOperator/GrayFilter/App.vue +51 -0
  81. package/DemoForOperator/GrayFilter/GrayFilter.vue +59 -0
  82. package/DemoForOperator/Jigsaw/App.vue +45 -0
  83. package/DemoForOperator/Jigsaw/JigsawFull.vue +142 -0
  84. package/DemoForOperator/Jigsaw/JigsawSingle.vue +118 -0
  85. package/DemoForOperator/LongChatBox/App.vue +36 -0
  86. package/DemoForOperator/LongChatBox/Bubble.vue +104 -0
  87. package/DemoForOperator/LongChatBox/LongChat.vue +173 -0
  88. package/DemoForOperator/LongChatBox/TextManager.ts +147 -0
  89. package/DemoForOperator/LongChatBox/VirtualList.vue +298 -0
  90. package/DemoForOperator/LongChatBox/testData.js +51 -0
  91. package/DemoForOperator/LongChatBox/utile.js +331 -0
  92. package/DemoForOperator/Particle/App.vue +69 -0
  93. package/DemoForOperator/Particle/Drop/DropParticle.vue +208 -0
  94. package/DemoForOperator/Particle/Explode/ExplodeParticle.vue +120 -0
  95. package/DemoForOperator/PosterAnim/App.vue +125 -0
  96. package/DemoForOperator/PosterAnim/Bounce/BouncePage.vue +54 -0
  97. package/DemoForOperator/PosterAnim/Bounce/Item.vue +85 -0
  98. package/DemoForOperator/PosterAnim/Breath/BreathPage.vue +47 -0
  99. package/DemoForOperator/PosterAnim/Breath/Item.vue +58 -0
  100. package/DemoForOperator/PosterAnim/CommonPageSetting.js +30 -0
  101. package/DemoForOperator/PosterAnim/Item.vue +46 -0
  102. package/DemoForOperator/PosterAnim/PosterAnim.js +79 -0
  103. package/DemoForOperator/PosterAnim/Scale/Item.vue +72 -0
  104. package/DemoForOperator/PosterAnim/Scale/ScalePage.vue +48 -0
  105. package/DemoForOperator/PosterAnim/Shake/Item.vue +85 -0
  106. package/DemoForOperator/PosterAnim/Shake/ShakePage.vue +53 -0
  107. package/DemoForOperator/PosterOverflow/App.vue +116 -0
  108. package/DemoForOperator/PosterOverflow/Item.vue +67 -0
  109. package/DemoForOperator/PosterOverflow/PosterOverflow.vue +39 -0
  110. package/DemoForOperator/Resize/App.vue +157 -0
  111. package/DemoForOperator/Resize/Resize/Item.vue +234 -0
  112. package/DemoForOperator/Resize/Resize/Resize.vue +96 -0
  113. package/DemoForOperator/Ripple/App.vue +54 -0
  114. package/DemoForOperator/Ripple/Ripple.vue +65 -0
  115. package/DemoForOperator/ScreenShootScale/App.vue +96 -0
  116. package/DemoForOperator/ScreenShootScale/Back.vue +86 -0
  117. package/DemoForOperator/ScreenShootScale/Front.vue +133 -0
  118. package/DemoForOperator/ScreenShootScale/Item.vue +62 -0
  119. package/DemoForOperator/ScreenShootScale/ScreenShootScale.vue +109 -0
  120. package/DemoForOperator/SmoothSwiper/App.vue +50 -0
  121. package/DemoForOperator/Sound/Bounce/App.vue +56 -0
  122. package/DemoForOperator/Sound/Bounce/Bounce.vue +87 -0
  123. package/DemoForOperator/Sound/Bounce/FreeMoveBuilder.js +146 -0
  124. package/DemoForOperator/Sound/Bounce/bgmusic.mp3 +0 -0
  125. package/DemoForOperator/Sound/Bounce/coin.mp3 +0 -0
  126. package/DemoForOperator/Sound/FocusMove/App.vue +134 -0
  127. package/DemoForOperator/Sound/FocusMove/Item.vue +43 -0
  128. package/DemoForOperator/Sound/FocusMove/move.mp3 +0 -0
  129. package/DemoForOperator/Sound/Rain/App.vue +11 -0
  130. package/DemoForOperator/Sound/Rain/Raining/Rain.vue +69 -0
  131. package/DemoForOperator/Sound/Rain/Raining/RainScene.vue +118 -0
  132. package/DemoForOperator/Sound/Sound/Sound.vue +24 -0
  133. package/DemoForOperator/Sound/Sound/index.js +4 -0
  134. package/DemoForOperator/Sound/Sound/useSound.js +112 -0
  135. package/DemoForOperator/Sprite/App.vue +33 -0
  136. package/DemoForOperator/Sprite/Sprite.vue +147 -0
  137. package/DemoForOperator/Stretch/App.vue +103 -0
  138. package/DemoForOperator/Stretch/Stretch/Item.vue +192 -0
  139. package/DemoForOperator/Stretch/Stretch/Stretch.vue +218 -0
  140. package/DemoForOperator/Swiper/App.vue +101 -0
  141. package/DemoForOperator/Swiper/Item.vue +56 -0
  142. package/DemoForOperator/Swiper/ParallaxSlide.vue +164 -0
  143. package/DemoForOperator/TabContent/App.vue +89 -0
  144. package/DemoForOperator/TabContent/ContentPage.vue +66 -0
  145. package/DemoForOperator/TabContent/Item.vue +85 -0
  146. package/DemoForOperator/TabContent/PageItem.vue +40 -0
  147. package/DemoForOperator/TabContent/TabContent/CreepFocus.vue +160 -0
  148. package/DemoForOperator/TabContent/TabContent/Item.vue +63 -0
  149. package/DemoForOperator/TabContent/TabContent/TabContent.vue +184 -0
  150. package/DemoForOperator/TabContent/TabContent/TabItem.vue +368 -0
  151. package/DemoForOperator/TabContent/TabContent/TabWidget.vue +243 -0
  152. package/DemoForOperator/TabContent/TabContent/Util.js +3 -0
  153. package/DemoForOperator/TabContent/TabContent/ViewSwiper.vue +110 -0
  154. package/DemoForOperator/TabContent/testData.js +241 -0
  155. package/DemoForOperator/TabContentVertical/App.vue +104 -0
  156. package/DemoForOperator/TabContentVertical/ContentPage.vue +67 -0
  157. package/DemoForOperator/TabContentVertical/Item.vue +94 -0
  158. package/DemoForOperator/TabContentVertical/PageItem.vue +40 -0
  159. package/DemoForOperator/TabContentVertical/TabContent/CreepFocus.vue +160 -0
  160. package/DemoForOperator/TabContentVertical/TabContent/Item.vue +63 -0
  161. package/DemoForOperator/TabContentVertical/TabContent/TabContent.vue +184 -0
  162. package/DemoForOperator/TabContentVertical/TabContent/TabItem.vue +368 -0
  163. package/DemoForOperator/TabContentVertical/TabContent/TabWidget.vue +259 -0
  164. package/DemoForOperator/TabContentVertical/TabContent/Util.js +3 -0
  165. package/DemoForOperator/TabContentVertical/TabContent/ViewSwiper.vue +110 -0
  166. package/DemoForOperator/TabContentVertical/assets/children_science.png +0 -0
  167. package/DemoForOperator/TabContentVertical/assets/documentary.png +0 -0
  168. package/DemoForOperator/TabContentVertical/assets/free.png +0 -0
  169. package/DemoForOperator/TabContentVertical/assets/game.png +0 -0
  170. package/DemoForOperator/TabContentVertical/assets/home_selected.png +0 -0
  171. package/DemoForOperator/TabContentVertical/assets/movie_ticket.png +0 -0
  172. package/DemoForOperator/TabContentVertical/assets/my_account.png +0 -0
  173. package/DemoForOperator/TabContentVertical/assets/opera.png +0 -0
  174. package/DemoForOperator/TabContentVertical/assets/sports.png +0 -0
  175. package/DemoForOperator/TabContentVertical/assets/tv_drama.png +0 -0
  176. package/DemoForOperator/TabContentVertical/assets/variety_show.png +0 -0
  177. package/DemoForOperator/TabContentVertical/assets/vip.png +0 -0
  178. package/DemoForOperator/TabContentVertical/testData.js +76 -0
  179. package/DemoForOperator/Vortex/App.vue +78 -0
  180. package/DemoForOperator/Vortex/Vortex/Vortex.vue +180 -0
  181. package/DemoForOperator/Vortex/Vortex/vortexIn.glsl +38 -0
  182. package/DemoForOperator/Vortex/Vortex/vortexOut.glsl +38 -0
  183. package/DemoForOperator/index.js +6 -0
  184. package/DemoForOperator/routeList.js +259 -0
  185. package/DemoHomepage/App.vue +50 -30
  186. package/DemoHomepage/components/Dialog.vue +1 -0
  187. package/DemoHomepage/components/Item.vue +11 -0
  188. package/DemoHomepage/components/TabFrame.vue +7 -0
  189. package/DemoHomepage/router.js +178 -81
  190. package/DemoHomepage/views/Homepage.vue +7 -2
  191. package/DivMetroPerformance/data.js +3 -3
  192. package/DriftScopeTest/App.vue +1 -1
  193. package/FilterDemo/AnimatePic.vue +1 -1
  194. package/FilterDemo/VideoLayer.vue +2 -2
  195. package/FullScreenFlex/TestFrame2.vue +1 -1
  196. package/GiftRain/App.vue +12 -12
  197. package/GiftRain/components/SpriteTranslate.vue +68 -48
  198. package/HashHistory/App.vue +2 -2
  199. package/HashHistory/router.js +1 -1
  200. package/JsvPreDownloader/App.vue +4 -4
  201. package/MediaDemo/components/frames/AudioFrame.vue +1 -1
  202. package/MediaDemo/components/frames/VideoFrame.vue +1 -1
  203. package/MetroWidgetDemos/MassiveItems/ContentItem.vue +1 -1
  204. package/MetroWidgetDemos/MassiveItems/data.js +1 -1
  205. package/MetroWidgetDemos/PerformanceTest/data.js +3 -3
  206. package/MetroWidgetDemos/RefreshDemo/assets/imageList.json +235 -235
  207. package/MetroWidgetDemos/SkeletonDiagram/assets/imageList.json +235 -235
  208. package/MetroWidgetDemos/TripleWidget/App.vue +7 -1
  209. package/MetroWidgetDemos/TripleWidget/Item.vue +16 -2
  210. package/MetroWidgetDemos/TripleWidget/SWidgetItem.vue +7 -1
  211. package/MetroWidgetDemos/TripleWidget/WidgetItem.vue +8 -2
  212. package/MetroWidgetDemos/focusableItemMetroWidget/WidgetItem.vue +3 -1
  213. package/MetroWidgetDemos/routeList.js +34 -17
  214. package/Poster3d/App.vue +69 -0
  215. package/Poster3d/Poster3d.vue +92 -0
  216. package/PosterPacker/App.vue +5 -5
  217. package/PosterPacker/tools/vortexPacker/Vortex.vue +1 -1
  218. package/QrcodeDemo/App.vue +1 -1
  219. package/Ripple/App.vue +1 -1
  220. package/ScaleDownNeon/App.vue +4 -4
  221. package/SceneTransition/App.vue +2 -2
  222. package/SceneTransition/maskConfig/config2.js +12 -12
  223. package/SceneTransition/maskConfig/config3.js +14 -14
  224. package/SprayView/App.vue +96 -51
  225. package/SpringFestival/App.vue +73 -0
  226. package/SpringFestival/SpringFestivalScene/ChunLian.vue +211 -0
  227. package/SpringFestival/SpringFestivalScene/FreeMoveBuilder.js +139 -0
  228. package/SpringFestival/SpringFestivalScene/LanternAnim.js +60 -0
  229. package/SpringFestival/SpringFestivalScene/Rain.vue +137 -0
  230. package/SpringFestival/SpringFestivalScene/Scene.vue +218 -0
  231. package/SpringFestival/SpringFestivalScene/imageConfig.js +87 -0
  232. package/SpringFestival/SpringFestivalScene/index.js +1 -0
  233. package/Swiper/App.vue +28 -29
  234. package/Swiper/Item.vue +19 -0
  235. package/SwiperTest/App.vue +9 -9
  236. package/TestNativeSharedView/AckEventDefine.ts +82 -0
  237. package/TestNativeSharedView/App.vue +4 -6
  238. package/TestNativeSharedView/JsvDemoTester.js +131 -0
  239. package/TextureAnimation/App.vue +16 -6
  240. package/TextureAnimation/App3.vue +100 -0
  241. package/TextureAnimation/utils/FrameCanvasStore.ts +68 -0
  242. package/TextureAnimation/utils/RotateFrame.vue +146 -0
  243. package/TextureAnimation/utils/circleHaloMask.png +0 -0
  244. package/TombSweepingDayTest/Raining/RainScene.vue +4 -4
  245. package/ViewOpacity/App.vue +21 -2
  246. package/package.json +1 -1
@@ -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>