@shijiu/jsview-vue-samples 2.3.151-test.0 → 3.0.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 (228) hide show
  1. package/ABImageAlt/App.vue +114 -0
  2. package/ABImageAlt/Item.vue +133 -0
  3. package/{MetroWidgetDemos/SkeletonDiagram/assets/imageList.json → ABImageAlt/assets/imageList.js} +9 -1
  4. package/ABImageAlt/data.js +17 -0
  5. package/AI_Check_Rules.txt +5 -0
  6. package/AnimPicture/App.vue +20 -10
  7. package/ApicSwitch/App.vue +90 -0
  8. package/ApicSwitch/TabItem.vue +65 -0
  9. package/ApicSwitch/WebpShow.vue +24 -0
  10. package/ApicSwitch/data.js +50 -0
  11. package/Basic/AI_skills_update.md +1 -0
  12. package/Basic/components/div/ColorFormatTest.vue +93 -0
  13. package/Basic/components/div/DivRadius.vue +97 -15
  14. package/Basic/components/div/DivTag3Group.vue +30 -0
  15. package/Basic/components/img/ImageType.vue +65 -0
  16. package/Basic/components/panel/Panel2.vue +13 -1
  17. package/Basic/components/text/TextAlign.vue +7 -1
  18. package/BlobLoadTest/App.vue +201 -0
  19. package/BreakLinesApi/App.vue +82 -0
  20. package/CanvasDrawChart/App.vue +11 -0
  21. package/CanvasDrawChart/Graph1.vue +104 -0
  22. package/CanvasDrawChart/Graph2.vue +115 -0
  23. package/CssPreprocessor/Scss/PanelData.js +1 -1
  24. package/CssPreprocessor/Scss/components/scss-group4/ScssMaps.vue +4 -3
  25. package/CssPreprocessor/Scss/components/scss-group5/ScssImporting.vue +2 -2
  26. package/DemoForOperator/Bounce/FreeMoveBuilder.js +1 -1
  27. package/DemoForOperator/Firework1/App.vue +12 -1
  28. package/DemoForOperator/Firework1/Fireworks.vue +18 -0
  29. package/DemoForOperator/FlipPage/FlipPage/FlipPage.vue +1 -0
  30. package/DemoForOperator/Focus/Alpha/Item.vue +1 -0
  31. package/DemoForOperator/Focus/Light/Item.vue +1 -0
  32. package/DemoForOperator/Focus/Normal/Item.vue +1 -0
  33. package/DemoForOperator/FrameShadow/FrameShadow.vue +1 -1
  34. package/DemoForOperator/Genie/App.vue +20 -6
  35. package/DemoForOperator/Genie/App2.vue +61 -0
  36. package/DemoForOperator/Genie/geniePakcer/GenieImage.vue +298 -0
  37. package/DemoForOperator/Genie/geniePakcer/GenieSlot.vue +292 -0
  38. package/DemoForOperator/Genie/geniePakcer/GenieTools.ts +463 -0
  39. package/DemoForOperator/Jigsaw/JigsawFull.vue +12 -7
  40. package/DemoForOperator/Jigsaw/JigsawSingle.vue +13 -7
  41. package/DemoForOperator/LongChatBox/App.vue +13 -13
  42. package/DemoForOperator/LongChatBox/Bubble.vue +78 -66
  43. package/DemoForOperator/LongChatBox/LongChat.vue +68 -36
  44. package/DemoForOperator/LongChatBox/testData.js +7 -44
  45. package/DemoForOperator/Sound/Bounce/FreeMoveBuilder.js +1 -1
  46. package/DemoForOperator/routeList.js +8 -2
  47. package/DemoHomepage/App.vue +74 -1
  48. package/DemoHomepage/components/BodyFrame.vue +1 -0
  49. package/DemoHomepage/components/TabFrame.vue +1 -1
  50. package/DemoHomepage/router.js +723 -160
  51. package/DemoHomepage/views/Homepage.vue +60 -2
  52. package/DemoHomepage/watchTest.vue +50 -0
  53. package/FilterDemo/AnimatePic.vue +63 -17
  54. package/FilterDemo/App.vue +3 -3
  55. package/FlexCellDemo/AI_skills_update.md +4 -0
  56. package/FlexCellDemo/TestFrame1.vue +12 -2
  57. package/FlexCellDemo/TestFrame2.vue +10 -1
  58. package/FlexCellDemo/TestFrame3.vue +114 -59
  59. package/FpsLimit/App.vue +102 -0
  60. package/FreeMoveChildAttract/App.vue +18 -8
  61. package/FreeMoveLink/App.vue +49 -20
  62. package/Hover/App.vue +144 -0
  63. package/HttpRequestSSE/SSEReader.js +200 -0
  64. package/ImpactStop/App.vue +2 -2
  65. package/Input/FullKeyboard.vue +3 -3
  66. package/Input/InputPanel.vue +63 -3
  67. package/JsvLine/App.vue +53 -38
  68. package/LatexDemo/App.vue +3 -1
  69. package/LatexFormula/App.vue +196 -0
  70. package/LongImage/App.vue +1 -1
  71. package/LongImage/LongImageScroll.vue +100 -47
  72. package/LongImage/Scroll.vue +28 -9
  73. package/LongText/LongTextScroll.vue +1 -0
  74. package/Markdown/App.vue +36 -0
  75. package/Markdown/Bubble.vue +109 -0
  76. package/Markdown/LongChat.vue +206 -0
  77. package/Markdown/Markdown/Markdown.vue +156 -0
  78. package/Markdown/Markdown/index.ts +1 -0
  79. package/Markdown/Markdown/marked/LICENSE.md +45 -0
  80. package/Markdown/Markdown/marked/index.ts +2 -0
  81. package/Markdown/Markdown/marked/marked.d.ts +756 -0
  82. package/Markdown/Markdown/marked/marked.js +71 -0
  83. package/Markdown/Markdown/parser.ts +1365 -0
  84. package/Markdown/data.js +581 -0
  85. package/MetroWidgetDemos/AI_skills_update.md +2 -0
  86. package/MetroWidgetDemos/ListExpand/ChildItem.vue +130 -0
  87. package/MetroWidgetDemos/ListExpand/ExpandItem.vue +375 -0
  88. package/MetroWidgetDemos/ListExpand/ExpandItem1.vue +403 -0
  89. package/MetroWidgetDemos/ListExpand/assets/arrow-down.png +0 -0
  90. package/MetroWidgetDemos/ListExpand/assets/up-arrow.png +0 -0
  91. package/MetroWidgetDemos/ListExpand/components/WidgetListHandler.vue +150 -0
  92. package/MetroWidgetDemos/ListExpand/index.vue +88 -0
  93. package/MetroWidgetDemos/ListExpand/list.js +2421 -0
  94. package/MetroWidgetDemos/RefreshDemo/App.vue +14 -1
  95. package/MetroWidgetDemos/RenderAccelerate/App.vue +142 -0
  96. package/MetroWidgetDemos/RenderAccelerate/AppPage.vue +78 -0
  97. package/MetroWidgetDemos/RenderAccelerate/AppTab.vue +62 -0
  98. package/MetroWidgetDemos/RenderAccelerate/ContentItem.vue +409 -0
  99. package/MetroWidgetDemos/RenderAccelerate/Item.vue +67 -0
  100. package/MetroWidgetDemos/RenderAccelerate/TabItem.vue +100 -0
  101. package/MetroWidgetDemos/RenderAccelerate/ViewSwiper.vue +215 -0
  102. package/MetroWidgetDemos/RenderAccelerate/WidgetItem.vue +107 -0
  103. package/MetroWidgetDemos/SkeletonDiagram/App.vue +35 -8
  104. package/MetroWidgetDemos/SkeletonDiagram/Item.vue +11 -2
  105. package/MetroWidgetDemos/SkeletonDiagram/assets/imageList.js +245 -0
  106. package/MetroWidgetDemos/SkeletonDiagram/data.js +3 -3
  107. package/MetroWidgetDemos/SpatialNav/App.vue +177 -0
  108. package/MetroWidgetDemos/SpatialNav/Buttons.vue +83 -0
  109. package/MetroWidgetDemos/SpatialNav/CustomFocus.vue +57 -0
  110. package/MetroWidgetDemos/{TripleWidget → SpatialNav}/Item.vue +1 -8
  111. package/MetroWidgetDemos/{TripleWidget/WidgetItem.vue → SpatialNav/SimpleFloor.vue} +14 -45
  112. package/MetroWidgetDemos/SpatialNav/StepMw.vue +113 -0
  113. package/MetroWidgetDemos/SpatialNav/TabContent/TabContent.vue +185 -0
  114. package/MetroWidgetDemos/SpatialNav/TripleSection/TripleSection.vue +69 -0
  115. package/MetroWidgetDemos/SpatialNav/TripleSection/WidgetItem.vue +100 -0
  116. package/MetroWidgetDemos/SpatialNav/TvSection/List.vue +75 -0
  117. package/MetroWidgetDemos/SpatialNav/TvSection/TvSection.vue +91 -0
  118. package/MetroWidgetDemos/basic2/App.vue +407 -0
  119. package/MetroWidgetDemos/basic2/Item.vue +68 -0
  120. package/MetroWidgetDemos/direction/App.vue +22 -0
  121. package/MetroWidgetDemos/gazeFocusDiff/App.vue +126 -0
  122. package/MetroWidgetDemos/gazeFocusDiff/Item.vue +87 -0
  123. package/MetroWidgetDemos/minimalUsage/App.vue +66 -0
  124. package/MetroWidgetDemos/minimalUsage/Item.vue +54 -0
  125. package/MetroWidgetDemos/ninePatchFocusPage/App.vue +22 -7
  126. package/MetroWidgetDemos/ninePatchFocusPage/Item.vue +7 -5
  127. package/MetroWidgetDemos/ninePatchFocusPage/focusConstants.js +2 -0
  128. package/MetroWidgetDemos/routeList.js +203 -12
  129. package/MetroWidgetDemos/slideSetting/App.vue +288 -99
  130. package/MetroWidgetDemos/zIndex/App.vue +117 -0
  131. package/MetroWidgetDemos/zIndex/Item.vue +61 -0
  132. package/NinePatchTester/App.vue +24 -31
  133. package/PreDecode/App.vue +140 -0
  134. package/ReactiveTest/App.vue +115 -0
  135. package/ReactiveTest/Item.vue +92 -0
  136. package/ReactiveTest/assets/imageList.js +245 -0
  137. package/ReactiveTest/component/TestSmartDiv.vue +50 -0
  138. package/ReactiveTest/component/TestSmartDivSrcList.vue +74 -0
  139. package/ReactiveTest/component/TestSmartImage.vue +46 -0
  140. package/ReactiveTest/component/TestSmartImageSrcList.vue +90 -0
  141. package/ReactiveTest/component/TestSmartImageStyle.vue +41 -0
  142. package/ReactiveTest/data.js +49 -0
  143. package/ScreenToBlob/App.vue +250 -0
  144. package/SecTorTest/App.vue +9 -3
  145. package/SpringFestival/SpringFestivalScene/FreeMoveBuilder.js +3 -3
  146. package/SyncDecode/App.vue +137 -0
  147. package/TextSizeLimit/App.vue +211 -0
  148. package/TransitPage/App.vue +2 -0
  149. package/assets/logo.png +0 -0
  150. package/package.json +5 -5
  151. package/DemoForOperator/Genie/geniePakcer/Genie.vue +0 -741
  152. package/DemoForOperator/LongChatBox/TextManager.ts +0 -147
  153. package/DemoForOperator/LongChatBox/VirtualList.vue +0 -298
  154. package/DemoForOperator/LongChatBox/utile.js +0 -331
  155. package/DivMetroPerformance/App.vue +0 -157
  156. package/DivMetroPerformance/Item.vue +0 -58
  157. package/DivMetroPerformance/assets/bg.jpg +0 -0
  158. package/DivMetroPerformance/assets/coupon_content.png +0 -0
  159. package/DivMetroPerformance/assets/coupon_left.png +0 -0
  160. package/DivMetroPerformance/assets/coupon_mid.png +0 -0
  161. package/DivMetroPerformance/assets/coupon_right.png +0 -0
  162. package/DivMetroPerformance/assets/focus_border.png +0 -0
  163. package/DivMetroPerformance/assets/holder_logo.png +0 -0
  164. package/DivMetroPerformance/assets/jrbm.png +0 -0
  165. package/DivMetroPerformance/assets/line_left.png +0 -0
  166. package/DivMetroPerformance/assets/line_mid.png +0 -0
  167. package/DivMetroPerformance/assets/line_right.png +0 -0
  168. package/DivMetroPerformance/assets/loading.png +0 -0
  169. package/DivMetroPerformance/assets/logo.png +0 -0
  170. package/DivMetroPerformance/assets/mcjx.png +0 -0
  171. package/DivMetroPerformance/assets/tao.png +0 -0
  172. package/DivMetroPerformance/assets/tmall.png +0 -0
  173. package/DivMetroPerformance/border.png +0 -0
  174. package/DivMetroPerformance/components/ContentItem.vue +0 -384
  175. package/DivMetroPerformance/components/MyTab.vue +0 -129
  176. package/DivMetroPerformance/data.js +0 -124
  177. package/DivMetroPerformance/utils/GridItem.vue +0 -28
  178. package/DivMetroPerformance/utils/GridPlate.vue +0 -85
  179. package/MediaDemo/App.vue +0 -127
  180. package/MediaDemo/assets/audio-poster.png +0 -0
  181. package/MediaDemo/components/Button.vue +0 -69
  182. package/MediaDemo/components/Controllor.vue +0 -286
  183. package/MediaDemo/components/StatusBar.vue +0 -100
  184. package/MediaDemo/components/frames/AudioFrame.vue +0 -39
  185. package/MediaDemo/components/frames/AudioPoster.vue +0 -48
  186. package/MediaDemo/components/frames/MediaFrame.vue +0 -153
  187. package/MediaDemo/components/frames/VideoFrame.vue +0 -39
  188. package/MetroWidgetDemos/TripleWidget/App.vue +0 -87
  189. package/MetroWidgetDemos/TripleWidget/SWidgetItem.vue +0 -99
  190. package/Parkour/App.vue +0 -13
  191. package/Parkour/Common/Context.js +0 -21
  192. package/Parkour/Common/MatchmanInfo.js +0 -62
  193. package/Parkour/Common/Random.js +0 -61
  194. package/Parkour/Common/Sound.js +0 -50
  195. package/Parkour/appConfig/HOW_TO_CONFIG.md +0 -20
  196. package/Parkour/appConfig/app.config.mjs +0 -5
  197. package/Parkour/appConfig/app_sign_private_key_sample.crt +0 -28
  198. package/Parkour/appConfig/app_sign_public_key_sample.pem +0 -9
  199. package/Parkour/appConfig/jsview.config.mjs +0 -39
  200. package/Parkour/assets/Bgimages/bg1.png +0 -0
  201. package/Parkour/assets/Bgimages/bg2.png +0 -0
  202. package/Parkour/assets/Bgimages/bg3.png +0 -0
  203. package/Parkour/assets/Bgimages/bg4.png +0 -0
  204. package/Parkour/assets/Bgimages/bg5.png +0 -0
  205. package/Parkour/assets/audio/jump.mp3 +0 -0
  206. package/Parkour/assets/audio/lose.mp3 +0 -0
  207. package/Parkour/assets/role_skin1/fail.json +0 -44
  208. package/Parkour/assets/role_skin1/fail.png +0 -0
  209. package/Parkour/assets/role_skin1/jump_down.json +0 -20
  210. package/Parkour/assets/role_skin1/jump_down.png +0 -0
  211. package/Parkour/assets/role_skin1/jump_up.json +0 -44
  212. package/Parkour/assets/role_skin1/jump_up.png +0 -0
  213. package/Parkour/assets/role_skin1/roll.json +0 -44
  214. package/Parkour/assets/role_skin1/roll.png +0 -0
  215. package/Parkour/assets/role_skin1/run.json +0 -52
  216. package/Parkour/assets/role_skin1/run.png +0 -0
  217. package/Parkour/components/Backdrop.vue +0 -61
  218. package/Parkour/components/GameSence.vue +0 -602
  219. package/Parkour/components/Matchman.vue +0 -85
  220. package/ThrowMoveDemo/AccelerateDemo.vue +0 -85
  221. package/ThrowMoveDemo/App.vue +0 -104
  222. package/ThrowMoveDemo/LRParabolicDemo.vue +0 -101
  223. package/ThrowMoveDemo/TargetDemo.vue +0 -87
  224. package/ThrowMoveDemo/UDParabolicDemo.vue +0 -92
  225. /package/{AnimPicture/assets → assets}/animated_webp.webp +0 -0
  226. /package/{AnimPicture/assets → assets}/ball_3.webp +0 -0
  227. /package/{AnimPicture/assets → assets}/girl_run.gif +0 -0
  228. /package/{AnimPicture/assets → assets}/quan.webp +0 -0
@@ -0,0 +1,130 @@
1
+ <!-- 通用item -->
2
+ <script setup>
3
+ import { JsvMarquee } from 'jsview'
4
+ import { shallowRef, inject } from 'vue'
5
+ const props = defineProps({
6
+ data: Object,
7
+ name: String,
8
+ onAction: Object,
9
+ query: Object,
10
+ onClick: Function,
11
+ onFocus: Function,
12
+ onBlur: Function,
13
+ onItemEdge: Function,
14
+ })
15
+ const focused = shallowRef(false)
16
+ const gazed = shallowRef(false)
17
+ const parentWidget = inject('parentWidget', {})
18
+ const divRef = shallowRef(null)
19
+ // item样式
20
+ const itemStyle = {
21
+ ...props.data.itemStyle,
22
+ }
23
+ // 图片样式
24
+ const imgStyle = {
25
+ ...props.data.imgStyle,
26
+ }
27
+ // 图标样式
28
+ const iconStyle = {
29
+ ...props.data.iconStyle,
30
+ }
31
+ // 文本样式
32
+ const textStyle = {
33
+ ...props.data.textStyle,
34
+ width: props.data.textStyle.padding
35
+ ? props.data.textStyle.width - (props.data.textStyle.padding.left || 0) - (props.data.textStyle.padding.right || 0)
36
+ : props.data.textStyle.width,
37
+ height: props.data.textStyle.padding
38
+ ? props.data.textStyle.height - (props.data.textStyle.padding.top || 0) - (props.data.textStyle.padding.bottom || 0)
39
+ : props.data.textStyle.height,
40
+ left: (props.data.textStyle.left || 0) + (props.data.textStyle.padding?.left || 0),
41
+ top: (props.data.textStyle.top || 0) + (props.data.textStyle.padding?.top || 0),
42
+ }
43
+ // 焦点样式
44
+ const focusStyle = {
45
+ ...itemStyle,
46
+ ...props.data.focusStyle,
47
+ }
48
+ // 焦点图片样式
49
+ const focusImgStyle = {
50
+ ...imgStyle,
51
+ ...props.data.focusImgStyle,
52
+ }
53
+ // 焦点图标样式
54
+ const focusIconStyle = {
55
+ ...iconStyle,
56
+ ...props.data.focusIconStyle,
57
+ }
58
+ // 焦点文本样式
59
+ const focusTextStyle = {
60
+ ...textStyle,
61
+ ...props.data.focusTextStyle
62
+ }
63
+ // 失焦样式
64
+ const blurStyle = {
65
+ ...itemStyle,
66
+ ...props.data.blurStyle,
67
+ }
68
+ // 失焦图片样式
69
+ const blurImgStyle = {
70
+ ...imgStyle,
71
+ ...props.data.blurImgStyle,
72
+ }
73
+ // 失焦图标样式
74
+ const blurIconStyle = {
75
+ ...iconStyle,
76
+ ...props.data.blurIconStyle,
77
+ }
78
+ // 失焦文本样式
79
+ const blurTextStyle = {
80
+ ...textStyle,
81
+ ...props.data.blurTextStyle,
82
+ }
83
+ //在回调中更改自身状态
84
+ const onFocus = () => {
85
+ if (parentWidget.value) {
86
+ parentWidget.value.slideToDiv(divRef.value, true)
87
+ }
88
+ focused.value = true
89
+ if (props.onFocus) {
90
+ props.onFocus(props.data, props.query)
91
+ }
92
+ }
93
+ const onBlur = () => {
94
+ focused.value = false
95
+ if (props.onBlur) {
96
+ props.onBlur(props.data, props.query)
97
+ }
98
+ }
99
+ const onClick = () => {
100
+ if (props.onClick) {
101
+ props.onClick(props.data, props.query)
102
+ }
103
+ }
104
+ // 无论widget是否获焦 item获焦
105
+ const onGaze = () => {
106
+ gazed.value = true
107
+ }
108
+ // 无论widget是否获焦 item失焦
109
+ const onIgnore = () => {
110
+ gazed.value = false
111
+ }
112
+ // 注册回调
113
+ props.onAction.register('onFocus', onFocus)
114
+ props.onAction.register('onBlur', onBlur)
115
+ props.onAction.register('onClick', onClick)
116
+ props.onAction.register('onGaze', onGaze)
117
+ props.onAction.register('onIgnore', onIgnore)
118
+ </script>
119
+ <template>
120
+ <div ref="divRef" :style="focused ? focusStyle : gazed ? blurStyle : itemStyle">
121
+ <div v-if="imgStyle" :style="focused ? focusImgStyle : gazed ? blurImgStyle : imgStyle"></div>
122
+ <div v-if="iconStyle" :style="iconStyle"></div>
123
+ <!-- 正常显示文字 -->
124
+ <div v-if="data.data.textVisible">
125
+ <jsv-marquee v-if="focused" :style="focusTextStyle" :text="data.data.name"></jsv-marquee>
126
+ <div v-else :style="gazed ? blurTextStyle : textStyle">{{ data.data?.name }}</div>
127
+ </div>
128
+ </div>
129
+ </template>
130
+ <style scoped></style>
@@ -0,0 +1,375 @@
1
+ <!-- 通用item -->
2
+ <script setup>
3
+ import { JsvMarquee, getKeyFramesGroup, useFocusHub, EdgeDirection } from 'jsview'
4
+ import { shallowRef, ref, onMounted, nextTick, computed } from 'vue'
5
+ import WidgetListHandler from './components/WidgetListHandler.vue'
6
+ import ExpandItem1 from './ExpandItem1.vue'
7
+
8
+ const props = defineProps({
9
+ data: Object,
10
+ name: {
11
+ type: String,
12
+ default: 'code',
13
+ },
14
+ onAction: Object,
15
+ query: Object,
16
+ onClick: Function,
17
+ onFocus: Function,
18
+ onBlur: Function,
19
+ onItemEdge: Function,
20
+ foldEvent: Function,
21
+ })
22
+
23
+ const focused = shallowRef(false)
24
+ const gazed = shallowRef(false)
25
+
26
+ // item样式
27
+ const itemStyle = {
28
+ ...props.data.itemStyle,
29
+ }
30
+
31
+ // 图片样式
32
+ const imgStyle = {
33
+ ...props.data.imgStyle,
34
+ }
35
+
36
+ // 图标样式
37
+ const iconStyle = {
38
+ ...props.data.iconStyle,
39
+ }
40
+
41
+ // 文本样式
42
+ const textStyle = {
43
+ ...props.data.textStyle,
44
+ width: props.data.textStyle.padding
45
+ ? props.data.textStyle.width - (props.data.textStyle.padding.left || 0) - (props.data.textStyle.padding.right || 0)
46
+ : props.data.textStyle.width,
47
+ height: props.data.textStyle.padding
48
+ ? props.data.textStyle.height - (props.data.textStyle.padding.top || 0) - (props.data.textStyle.padding.bottom || 0)
49
+ : props.data.textStyle.height,
50
+ left: (props.data.textStyle.left || 0) + (props.data.textStyle.padding?.left || 0),
51
+ top: (props.data.textStyle.top || 0) + (props.data.textStyle.padding?.top || 0),
52
+ whiteSpace: 'nowrap',
53
+ textOverflow: 'ellipsis',
54
+ overflow: 'hidden'
55
+ }
56
+
57
+ // 焦点样式
58
+ const focusStyle = {
59
+ ...itemStyle,
60
+ ...props.data.focusStyle,
61
+ }
62
+
63
+ // 焦点图片样式
64
+ const focusImgStyle = {
65
+ ...imgStyle,
66
+ ...props.data.focusImgStyle,
67
+ }
68
+
69
+ // 焦点图标样式
70
+ const focusIconStyle = {
71
+ ...iconStyle,
72
+ ...props.data.focusIconStyle,
73
+ }
74
+
75
+ // 焦点文本样式
76
+ const focusTextStyle = {
77
+ ...textStyle,
78
+ ...props.data.focusTextStyle,
79
+ }
80
+
81
+ // 失焦样式
82
+ const blurStyle = {
83
+ ...itemStyle,
84
+ ...props.data.blurStyle,
85
+ }
86
+
87
+ // 失焦图片样式
88
+ const blurImgStyle = {
89
+ ...imgStyle,
90
+ ...props.data.blurImgStyle,
91
+ }
92
+
93
+ // 失焦图标样式
94
+ const blurIconStyle = {
95
+ ...iconStyle,
96
+ ...props.data.blurIconStyle,
97
+ }
98
+
99
+ // 失焦文本样式
100
+ const blurTextStyle = {
101
+ ...textStyle,
102
+ ...props.data.blurTextStyle,
103
+ }
104
+
105
+ /**
106
+ * 关键代码
107
+ * 焦点快速往复移动时, 复用一个子widget会导致slideToDiv焦点位置的偏移, 因此每次缩放时都创建新的widget
108
+ */
109
+ const duration = 200
110
+ const focusHub = useFocusHub()
111
+ let folded = ref(true)
112
+ const styleShell = getKeyFramesGroup()
113
+ const itemBoxHeight = props.data.itemStyle.height
114
+ const childrenHeight = ref(0)
115
+ const expandChildrenHeight = computed(() => {
116
+ const totalHeight = props.data.expandChildren.length * itemBoxHeight + childrenHeight.value
117
+ return totalHeight
118
+ })
119
+ const widgetRef = shallowRef(null)
120
+ const widgetTop = ref(0)
121
+ let animToken = 1
122
+ const clipAnimStr = ref('')
123
+ const slideAnimStr = ref('')
124
+ const animationCache = {}
125
+
126
+ const getClipAnimation = (from, to, anchor) => {
127
+ animToken++
128
+ const name = 'foldableItemClipAnim' + animToken
129
+ if (animationCache.hasOwnProperty(name)) {
130
+ styleShell.removeRule(name)
131
+ delete animationCache[name]
132
+ }
133
+ const clipAnimStr = `@keyframes ${name} { from { height: ${from}; } to { height: ${to}; } }`
134
+ animationCache[name] = clipAnimStr
135
+ styleShell.insertRule(clipAnimStr)
136
+
137
+ //平移动画
138
+ const anchorPosition = Math.round((to - from) * anchor)
139
+ const slideName = 'foldableItemSlideAnim' + animToken
140
+ if (animationCache.hasOwnProperty(slideName)) {
141
+ styleShell.removeRule(slideName)
142
+ delete animationCache[slideName]
143
+ }
144
+ const slideAnimStr = `@keyframes ${slideName} { from { transform: translate3d(0,${-anchorPosition},0); } to { transform: translate3d(0,0,0); } }`
145
+ animationCache[slideName] = slideAnimStr
146
+ styleShell.insertRule(slideAnimStr)
147
+
148
+ return {
149
+ clip: `${name} ${duration / 1000}s`,
150
+ slide: `${slideName} ${duration / 1000}s`,
151
+ }
152
+ }
153
+
154
+ const getAnchor = (index) => {
155
+ let anchor = 0
156
+ const l = props.data.expandChildren
157
+ if (index <= 0) {
158
+ anchor = 0
159
+ } else if (index > l.length - 1) {
160
+ anchor = 1
161
+ } else {
162
+ let focusMiddle = 0
163
+ for (let i = 0; i <= index - 1; ++i) {
164
+ focusMiddle += l[i].height
165
+ }
166
+ focusMiddle += l[index].height / 2
167
+ const maxHeight = expandChildrenHeight.value + itemBoxHeight
168
+ const scaleRate = maxHeight / itemBoxHeight
169
+ const targetPercent = focusMiddle / maxHeight // 居中目标位置的百分比
170
+ /**
171
+ * anchor计算说明
172
+ * 考虑[0,1]的线段, 以a(0 <= a <= 1)为锚点, 放大n倍(n > 1)
173
+ * 坐标的映射关系为 x -> n(x - a) + a
174
+ * 此处我们想要的是目标焦点的中线对齐0.5, 即targetPercent放大后的位置是0.5
175
+ * 所以方程为 scaleRate * (targetPercent - anchor) + anchor = 0.5
176
+ */
177
+ anchor = (scaleRate * targetPercent - 0.5) / (scaleRate - 1)
178
+ }
179
+ return anchor
180
+ }
181
+
182
+ const foldSubTab = () => {
183
+ if (!folded.value) {
184
+ updateWidgetHeight(itemBoxHeight, function () {
185
+ folded.value = true
186
+ })
187
+ focusHub.returnFocusToParent()
188
+ }
189
+ props.foldEvent()
190
+ }
191
+
192
+ const expand = (type) => {
193
+ if (folded.value && props.data.expandChildren.length > 0) {
194
+ widgetTop.value = itemBoxHeight
195
+ /**
196
+ * 动画未结束时, widgetTop不为0, 此时又获焦那一帧同时设置的widgetTop值未同步到div, slideToDiv获取的就不是展开后item的正确位置
197
+ */
198
+ folded.value = false
199
+ updateWidgetHeight(expandChildrenHeight.value + itemBoxHeight)
200
+ if (!type) {
201
+ nextTick(() => {
202
+ widgetRef.value.setFocusId(0)
203
+ focusHub.setFocus(props.name + '_' + props.query.index)
204
+ })
205
+ }
206
+ }
207
+ props.foldEvent()
208
+ }
209
+
210
+ //在回调中更改自身状态
211
+ const onFocus = () => {
212
+ focused.value = true
213
+ if (!folded.value) {
214
+ focusHub.setFocus(props.name + '_' + props.query.index)
215
+ } else {
216
+ if (props.onFocus) {
217
+ props.onFocus(props.data, props.query)
218
+ }
219
+ }
220
+ }
221
+
222
+ const onBlur = () => {
223
+ focused.value = false
224
+ if (props.onBlur) {
225
+ props.onBlur(props.data, props.query)
226
+ }
227
+ }
228
+
229
+ const onClick = () => {
230
+ if (folded.value) {
231
+ expand()
232
+ } else {
233
+ // foldSubTab()
234
+ }
235
+ if (props.onClick) {
236
+ props.onClick(props.data, props.query)
237
+ }
238
+ }
239
+
240
+ // 无论widget是否获焦 item获焦
241
+ const onGaze = () => {
242
+ }
243
+
244
+ // 无论widget是否获焦 item失焦
245
+ const onIgnore = () => {
246
+ gazed.value = false
247
+ }
248
+
249
+ // 子列表获焦
250
+ const onChildFocus = (data, query) => {
251
+ if (props.onFocus) {
252
+ props.onFocus(data, query)
253
+ }
254
+ }
255
+
256
+ // 子列表按键
257
+ const childKeyDown = (e) => {
258
+ if (e.keyCode === 10000 || e.keyCode === 8 || e.keyCode === 27) {
259
+ foldSubTab()
260
+ return true
261
+ }
262
+ }
263
+
264
+ const onChildEdge = (edgeInfo) => {
265
+ if (edgeInfo.direction === EdgeDirection.top) {
266
+ foldSubTab()
267
+ } else if (edgeInfo.direction === EdgeDirection.bottom) {
268
+ foldSubTab()
269
+ props.onItemEdge(edgeInfo)
270
+ } else {
271
+ props.onItemEdge(edgeInfo)
272
+ }
273
+ }
274
+
275
+ onMounted(() => {
276
+ })
277
+ // 子列表展开高度更新
278
+ const updateExpandHeight = (h) => {
279
+ childrenHeight.value = h
280
+ updateWidgetHeight(expandChildrenHeight.value + itemBoxHeight)
281
+ props.foldEvent()
282
+ }
283
+
284
+ let preHeight = itemBoxHeight;
285
+ const updateWidgetHeight = (h, callback) => {
286
+ const anchor = getAnchor(0)
287
+ //创建动画
288
+ const anim = getClipAnimation(preHeight, h, anchor)
289
+ preHeight = h;
290
+ clipAnimStr.value = anim.clip
291
+ slideAnimStr.value = anim.slide
292
+ props.query.updateItemSize(
293
+ props.query.index,
294
+ {
295
+ width: props.data.itemStyle.width,
296
+ height: h,
297
+ },
298
+ {
299
+ anchor,
300
+ duration: duration,
301
+ onEnd: () => {
302
+ callback && callback()
303
+ console.log('unfold anim end.')
304
+ },
305
+ }
306
+ )
307
+ }
308
+
309
+ // 注册回调
310
+ props.onAction.register('onFocus', onFocus)
311
+ props.onAction.register('onBlur', onBlur)
312
+ props.onAction.register('onClick', onClick)
313
+ props.onAction.register('onGaze', onGaze)
314
+ props.onAction.register('onIgnore', onIgnore)
315
+ </script>
316
+
317
+ <template>
318
+ <div v-if="folded" :style="focused ? focusStyle : gazed ? blurStyle : itemStyle">
319
+ <div v-if="imgStyle" :style="focused ? focusImgStyle : gazed ? blurImgStyle : imgStyle"></div>
320
+ <div v-if="iconStyle" :style="iconStyle"></div>
321
+ <div v-if="data.data.textVisible">
322
+ <jsv-marquee v-if="focused" :style="focusTextStyle" :text="data.data.name"></jsv-marquee>
323
+ <div v-else :style="gazed ? blurTextStyle : textStyle">{{ data.data?.name }}</div>
324
+ </div>
325
+ </div>
326
+ <div
327
+ v-else
328
+ :style="{
329
+ width: data.itemStyle.width,
330
+ height: expandChildrenHeight + itemBoxHeight,
331
+ overflow: 'hidden',
332
+ animation: clipAnimStr,
333
+ }"
334
+ >
335
+ <div :style="blurStyle">
336
+ <div v-if="imgStyle" :style="blurImgStyle"></div>
337
+ <div v-if="iconStyle" :style="blurIconStyle"></div>
338
+ <div v-if="data.data.textVisible">
339
+ <div :style="blurTextStyle">{{ data.data?.name }}</div>
340
+ </div>
341
+ </div>
342
+ <jsv-focus-block
343
+ :style="{
344
+ top: widgetTop,
345
+ width: data.itemStyle.width,
346
+ height: expandChildrenHeight,
347
+ backgroundColor: 'rgba(0, 0, 0, .2)',
348
+ borderRadius: 20,
349
+ animation: slideAnimStr,
350
+ }"
351
+ :onKeyDown="childKeyDown"
352
+ >
353
+ <WidgetListHandler
354
+ ref="widgetRef"
355
+ :layout="{
356
+ left: 0,
357
+ top: 0,
358
+ width: data.itemStyle.width,
359
+ height: expandChildrenHeight,
360
+ }"
361
+ :name="props.name + '_' + props.query.index"
362
+ :data="data.expandChildren"
363
+ :onWidgetFocus="onChildFocus"
364
+ :onEdge="onChildEdge"
365
+ :fullDisplayMode="true"
366
+ >
367
+ <template #item="slotProps">
368
+ <ExpandItem1 v-bind="slotProps" :name="props.name + '_' + props.query.index" :foldEvent="props.foldEvent" :onExpandHeight="updateExpandHeight" />
369
+ </template>
370
+ </WidgetListHandler>
371
+ </jsv-focus-block>
372
+ </div>
373
+ </template>
374
+
375
+ <style scoped></style>