@shijiu/jsview-vue 1.9.650 → 1.9.719

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 (157) hide show
  1. package/package.json +7 -18
  2. package/samples/AnimPicture/App.vue +5 -5
  3. package/samples/Basic/components/div/DivLayout.vue +1 -1
  4. package/samples/Basic/components/text/TextOverflow.vue +10 -5
  5. package/samples/BasicFocusControl/components/BaseBlock.vue +2 -2
  6. package/samples/Collision/App.vue +452 -0
  7. package/samples/DemoHomepage/components/BodyFrame.vue +2 -0
  8. package/samples/DemoHomepage/router.js +21 -1
  9. package/samples/DemoHomepage/views/Homepage.vue +3 -7
  10. package/samples/FilterDemo/App.vue +1 -1
  11. package/samples/FlipCard/App.vue +2 -2
  12. package/samples/FlipCard/FlipCard.vue +2 -2
  13. package/samples/GridDemo/App.vue +3 -3
  14. package/samples/GridDemo/ButtonBlock.vue +2 -2
  15. package/samples/GridDemo/FocusItem.vue +2 -2
  16. package/samples/GridDemo/Item.vue +1 -1
  17. package/samples/HashHistory/App.vue +10 -3
  18. package/samples/HashHistory/components/Item.vue +1 -1
  19. package/samples/ImpactStop/App.vue +435 -0
  20. package/samples/Input/App.vue +8 -17
  21. package/samples/Input/InputPanel.vue +19 -12
  22. package/samples/LongImage/Button.vue +1 -1
  23. package/samples/LongImage/ButtonItem.vue +1 -1
  24. package/samples/LongImage/LongImageScroll.vue +2 -2
  25. package/samples/LongText/App.vue +1 -1
  26. package/samples/LongText/Button.vue +1 -1
  27. package/samples/LongText/ButtonItem.vue +1 -1
  28. package/samples/LongText/LongTextScroll.vue +3 -3
  29. package/samples/Marquee/App.vue +176 -40
  30. package/samples/Marquee/longText.js +14 -0
  31. package/samples/MetroWidgetDemos/Advanced/App.vue +5 -6
  32. package/samples/MetroWidgetDemos/Advanced/ButtonItem.vue +3 -3
  33. package/samples/MetroWidgetDemos/Advanced/Buttons.vue +5 -5
  34. package/samples/MetroWidgetDemos/Advanced/Mixed.vue +4 -4
  35. package/samples/MetroWidgetDemos/Advanced/widgets/Item.vue +83 -0
  36. package/samples/MetroWidgetDemos/Advanced/widgets/WidgetItem.vue +89 -0
  37. package/samples/MetroWidgetDemos/Advanced/{Widgets.vue → widgets/Widgets.vue} +56 -11
  38. package/samples/MetroWidgetDemos/Advanced/widgets/focus1.png +0 -0
  39. package/samples/MetroWidgetDemos/Item.vue +20 -2
  40. package/samples/MetroWidgetDemos/PerformanceTest/App.vue +4 -4
  41. package/samples/MetroWidgetDemos/PerformanceTest/components/ContentItem.vue +1 -1
  42. package/samples/MetroWidgetDemos/PerformanceTest/components/MyTab.vue +1 -1
  43. package/samples/MetroWidgetDemos/PingPong/App.vue +3 -3
  44. package/samples/MetroWidgetDemos/PingPong/AppPage.vue +17 -2
  45. package/samples/MetroWidgetDemos/PingPong/AppTab.vue +3 -10
  46. package/samples/MetroWidgetDemos/PingPong/{Item.vue → TabItem.vue} +3 -11
  47. package/samples/MetroWidgetDemos/PingPong/ViewSwiper.vue +2 -2
  48. package/samples/MetroWidgetDemos/Simple/AbsoluteTemplate.vue +2 -2
  49. package/samples/MetroWidgetDemos/Simple/App.vue +2 -2
  50. package/samples/MetroWidgetDemos/Simple/RelativeTemplate.vue +6 -6
  51. package/samples/MetroWidgetDemos/WidgetItem.vue +2 -2
  52. package/samples/MetroWidgetDemos/data.js +2 -1
  53. package/samples/NinePatchDemo/App.vue +2 -2
  54. package/samples/NinePatchDemo/Item.vue +1 -1
  55. package/samples/Preload/App.vue +17 -12
  56. package/samples/Preload/Item.vue +1 -1
  57. package/samples/QrcodeDemo/App.vue +1 -1
  58. package/samples/ScaleDownNeon/App.vue +107 -0
  59. package/samples/SoundPool/App.vue +1 -1
  60. package/samples/TextBox/App.vue +9 -82
  61. package/samples/TextBox/RenderCenter.vue +40 -16
  62. package/samples/TextBox/RenderLeft.vue +48 -19
  63. package/samples/TextBox/RenderOneLine.vue +30 -49
  64. package/samples/TextBox/RenderRight.vue +40 -16
  65. package/samples/TextShadowDemo/App.vue +11 -17
  66. package/samples/TextureAnimation/App2.vue +43 -15
  67. package/samples/TextureAnimation/assets/light.png +0 -0
  68. package/samples/TextureAnimation/assets/light2.png +0 -0
  69. package/samples/TextureSize/App.vue +3 -3
  70. package/samples/TouchSample/MetroWidgetHorizontal.vue +1 -1
  71. package/samples/TouchSample/MetroWidgetVertical.vue +1 -1
  72. package/samples/TransitPage/App.vue +1 -1
  73. package/samples/VideoDemo/App.vue +8 -8
  74. package/samples/VideoDemo/components/Button.vue +1 -1
  75. package/samples/VisibleSensorDemo/App.vue +94 -27
  76. package/tsconfig.json +6 -6
  77. package/utils/JsViewEngineWidget/JsvFocusBlock.vue +55 -59
  78. package/utils/JsViewEngineWidget/JsvFocusManager.js +1 -1
  79. package/utils/JsViewEngineWidget/MetroWidget/Const.js +11 -0
  80. package/utils/JsViewEngineWidget/MetroWidget/MetroWidget.vue +226 -107
  81. package/utils/JsViewEngineWidget/TemplateParser.js +227 -178
  82. package/utils/JsViewEngineWidget/WidgetCommon.js +13 -5
  83. package/utils/JsViewEngineWidget/index.js +3 -2
  84. package/utils/JsViewPlugin/BrowserPluginLoader.js +1 -1
  85. package/utils/JsViewPlugin/JsvPlayer/JsvMedia.js +95 -12
  86. package/utils/JsViewPlugin/JsvPlayer/JsvPlayer.vue +23 -2
  87. package/utils/JsViewPlugin/JsvPlayer/JsvPlayerBrowser.vue +1 -1
  88. package/utils/JsViewPlugin/JsvPlayer/index.js +22 -1
  89. package/utils/JsViewPlugin/JsvPlayer/version.js +4 -4
  90. package/utils/JsViewVueTools/JsvImpactTracer.js +113 -0
  91. package/utils/JsViewVueTools/JsvStyleClass.js +1 -1
  92. package/utils/JsViewVueTools/index.js +2 -1
  93. package/utils/JsViewVueWidget/BrowserDebugWidget/BrowserPreload.vue +11 -1
  94. package/utils/JsViewVueWidget/BrowserDebugWidget/BrowserSpray.vue +1 -1
  95. package/utils/JsViewVueWidget/BrowserDebugWidget/BrowserTextureAnim.vue +7 -9
  96. package/utils/JsViewVueWidget/JsvActorMove/ActorControlBase.js +1 -1
  97. package/utils/JsViewVueWidget/JsvActorMove/JsvActorMove.vue +3 -3
  98. package/utils/JsViewVueWidget/JsvActorMove/JsvActorMoveControl.js +1 -1
  99. package/utils/JsViewVueWidget/JsvApic/JsvApic.vue +5 -5
  100. package/utils/JsViewVueWidget/JsvFilterView.vue +1 -1
  101. package/utils/JsViewVueWidget/JsvGrid.vue +3 -11
  102. package/utils/JsViewVueWidget/JsvInput/Cursor.vue +5 -3
  103. package/utils/JsViewVueWidget/JsvInput/JsvInput.vue +15 -14
  104. package/utils/JsViewVueWidget/JsvMarquee.vue +180 -207
  105. package/utils/JsViewVueWidget/JsvMaskClipDiv.vue +2 -2
  106. package/utils/JsViewVueWidget/JsvNativeSharedDiv.vue +35 -27
  107. package/utils/JsViewVueWidget/JsvNinePatch.vue +1 -2
  108. package/utils/JsViewVueWidget/JsvPreload/JsvPreload.vue +38 -42
  109. package/utils/JsViewVueWidget/JsvQrcode/JsvQrcode.vue +1 -1
  110. package/utils/JsViewVueWidget/JsvSpray/JsvSpray.vue +1 -1
  111. package/utils/JsViewVueWidget/JsvSwiper/JsvSwiper.vue +24 -8
  112. package/utils/JsViewVueWidget/JsvSwiper3D/JsvSwiper.vue +23 -3
  113. package/utils/JsViewVueWidget/JsvTextBox.vue +20 -86
  114. package/utils/JsViewVueWidget/JsvTextureAnim/JsvTextureAnim.vue +2 -9
  115. package/utils/JsViewVueWidget/JsvTouchContainer.vue +6 -7
  116. package/utils/JsViewVueWidget/JsvTransparentDiv.vue +1 -1
  117. package/utils/JsViewVueWidget/JsvVisibleSensor/JsvVisibleSensor.vue +6 -6
  118. package/utils/JsViewVueWidget/index.js +8 -8
  119. package/utils/JsViewVueWidget/utils/index.js +8 -0
  120. package/utils/JsViewVueWidget/utils/text.js +19 -0
  121. package/dom/bin/jsview-browser-debug-dom.min.js +0 -1
  122. package/dom/bin/jsview-dom.min.js +0 -1
  123. package/dom/bin/jsview-forge-define.min.js +0 -1
  124. package/dom/browser-root-style.css +0 -21
  125. package/dom/jsv-browser-debug-dom.js +0 -8
  126. package/dom/jsv-dom.js +0 -6
  127. package/dom/jsv-forge-define.js +0 -6
  128. package/dom/target_core_revision.mjs +0 -15
  129. package/loader/header_script_loader.js +0 -134
  130. package/loader/jsview-main.js +0 -42
  131. package/loader/jsview.config.default.js +0 -37
  132. package/loader/jsview.default.config.js +0 -37
  133. package/loader/loader.js +0 -179
  134. package/loader/loader_webkit.js +0 -40
  135. package/patches/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js +0 -17609
  136. package/patches/node_modules/@vue/compiler-sfc/dist/jsview-css-to-js.js +0 -335
  137. package/patches/node_modules/@vue/compiler-sfc/dist/jsview-style-format.js +0 -446
  138. package/patches/node_modules/@vue/compiler-sfc/dist/jsview-style-types.js +0 -91
  139. package/patches/node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js +0 -8038
  140. package/patches/node_modules/@vue/runtime-dom/dist/runtime-dom.esm-bundler.js +0 -1700
  141. package/patches/node_modules/postcss-js/objectifier.js +0 -90
  142. package/patches/node_modules/vite/dist/node/chunks/dep-0fc8e132.js +0 -63147
  143. package/patches/node_modules/vite/dist/node/jsview.vite.config.js +0 -53
  144. package/patches/node_modules/vue-router/dist/vue-router.mjs +0 -3595
  145. package/scripts/common.js +0 -58
  146. package/scripts/jsview-install-local-packages.js +0 -73
  147. package/scripts/jsview-jsmap-serve.js +0 -105
  148. package/scripts/jsview-post-build.js +0 -183
  149. package/scripts/jsview-post-install.js +0 -102
  150. package/scripts/jsview-run-android.js +0 -67
  151. package/utils/JsViewEngineWidget/MetroPage.js +0 -2128
  152. package/utils/JsViewEngineWidget/SimpleWidget/ContentView.vue +0 -51
  153. package/utils/JsViewEngineWidget/SimpleWidget/Dispatcher.js +0 -19
  154. package/utils/JsViewEngineWidget/SimpleWidget/DivWrapper.vue +0 -53
  155. package/utils/JsViewEngineWidget/SimpleWidget/ItemView.vue +0 -142
  156. package/utils/JsViewEngineWidget/SimpleWidget/RootView.vue +0 -140
  157. package/utils/JsViewEngineWidget/SimpleWidget/SimpleWidget.vue +0 -1629
@@ -1,1629 +0,0 @@
1
- <!--
2
- * @Author: ChenChanghua
3
- * @Date: 2021-09-22 16:08:58
4
- * @LastEditors: ChenChanghua
5
- * @LastEditTime: 2022-02-28 18:14:29
6
- * @Description: file content
7
- -->
8
-
9
- <!--
10
- * 【界面概述】
11
- * 展示SimpleWidget控件的用法
12
- *
13
- * 【控件介绍】
14
- * SimpleWidget:
15
- * props:
16
- * top {int} 控件的y,默认为0
17
- * left {int} 控件的x, 默认为0
18
- * width {int} (必选)控件的宽
19
- * height {int} (必选)控件的高
20
- * layoutType {String} 布局的类型, 目前支持 "relative"(默认)|"absolute", relative为自动布局,
21
- absolute为依据measures中给的top, left布局
22
- *
23
- * name {string} 用于设置焦点的名称
24
- * padding {object} 控件内边距, 默认为{left: 0, right: 0, top: 0, bottom: 0}
25
- * direction {enum} (必选)控件方向 HORIZONTAL/VERTICAL
26
- * loopFocus {boolean} 焦点到边界后自动转到下一行,默认false
27
- * initFocusId {int} 初始焦点,默认为0
28
- * slideSetting {SlideSetting} 页面滑动的设置, 目前SlideSetting有三个子类, 具体见 WidgetCommon 中的说明
29
- WholePageSlide
30
- @description 整页滚动的设置类
31
- @constructor {Object} {speed, easing, boundProtect}
32
- SeamlessSlide
33
- @description 平滑滚动的设置类
34
- @constructor {Object} {startPercent, endPercent, speed, easing, boundProtect}
35
- FixPositionSlide
36
- @description 固定位置滚动的设置类
37
- @constructor {Object} {fixPercent, speed, easing, boundProtect}
38
- * itemConfig {Function (item) => {takeOverSlide: true}} 返回item的配置信息
39
-
40
- * data {array} (必选)数据列表
41
- * measures {function} (必选)返回item的模板信息的回调,
42
- * @params item {object} data中的数据
43
- * @return 模板信息,
44
- {
45
- left: 绝对布局时的left,
46
- top: 绝对布局时的top,
47
- width: item的宽,
48
- height: item的高,
49
- focusable: item是否可以获得焦点,
50
- marginBottom: item的下方margin,
51
- marginRight: item的右方margin,
52
- findNextAnchor: 自定义上下左右四条边寻找临近item的基准位置,值为0-1 {left: 0.5, right: 0.5, top: 0.5, bottom: 0.5}
53
- }
54
- *
55
- * onFocus {function} 控件获取焦点的回调
56
- * onBlur {function} 控件失去焦点的回调
57
- * onEdge {function} 焦点移动到边缘时的回调
58
- * @params {object} edgeInfo {
59
- "direction": {EdgeDirection}边缘方向,
60
- "rect": 到达边缘时的区域{x: 0, y: 0, width: 0,height: 0}
61
- }
62
- *
63
- * enableTouch {boolean} 支持触控
64
- * loadAll {boolean} 加载不显示的view,触控场景使用
65
- * flingPageWidth {}
66
- * flingPageEdge {}
67
- * methods:
68
- getFocusBlockRef 获取此SimpleWidget的 jsv-focus-block句柄,可以使用requestFocus完成获焦
69
-
70
- slideTo
71
- @description 滚动到指定位置
72
- @params {int} position 滚动目标位置
73
- @params {boolean} doAnim 是否做动画
74
- slideToItem
75
- @description 滚动到指定item
76
- @params {int} index 目标item的index, 注意与item的id区别, id是可获焦item的序号
77
- @params {boolean} doAnim 是否做动画
78
- setEnterFocusId
79
- @description 设置落焦时的焦点
80
- @params {int} id 落焦时的焦点id
81
- setEnterFocusRect
82
- @description 设置落焦时的焦点查找去区域
83
- @params {Object} rectInfo 焦点移入时的区域,SimpleWidget 将会根据此区域寻找最近的item
84
- {
85
- direction: {EdgeDirection}
86
- rect: {
87
- x: {int},
88
- y: {int},
89
- width: {int},
90
- height: {int}
91
- }
92
- }
93
- setFocusId
94
- @description 设置焦点
95
- @params {int} id 焦点id
96
- @params {boolean} needSlide 是否需要滚动
97
- @params {boolean} doAnim 滚动时是否做动画
98
-
99
- * 【技巧说明】
100
- * Q: 插槽props如何使用?
101
- * A: data: 当前item的数据
102
- * query: 获取一些额外信息的对象
103
- {
104
- id: {int} item的id,
105
- position: {Function} (index : int) => {left: 0, top: 0, width: 0, height: 0}
106
- 获取 item 相对 SimpleWidget 左上角坐标
107
- templatePosition: {Function} (index : int) => {left: 0, top: 0, width: 0, height: 0}
108
- 获取 item 的布局坐标, 一般用于自定义滚动
109
- absolutePosition: {Function} (index : int) => {left: 0, top: 0, width: 0, height: 0}
110
- 获取 item 的绝对坐标, 一般用于控制焦点
111
- getCurrentFocusId: {Function} () => {id: 0, index: 0}
112
- 获取当前焦点信息,id 为在可获得焦点元素列表中的索引,index 为在所有元素列表中的索引
113
- slideTo: {Function} (targetPosition : int, doAnim : Boolean) => void
114
- 滚动到指定位置,注意这个位置是 item 的布局坐标,另外当某些item需要接管滚动时,itemConfig中takeOverSlide要为true。
115
- }
116
- * onEdge: 若单元格内另有可接管按键的控件(如SimpleWidget),该控件到达边缘需要通知SimpleWidget时的回调
117
- * onAction: 单元格内控件需要通过onAction.register方法向SimpleWidget注册 item 的回调,回调函数有
118
- onFocus, onBlur, onClick, onWidgetEdge
119
- *
120
- * Q: 如何进行布局,定制每个格的尺寸?
121
- * A: 首先选定一个布局的方式,一列列地横向布局(HROIZONTAL)还是一行行地纵向(VERTICAL)布局,设置给属性direction
122
- * 然后将单元格尺寸反馈器(函数)设置到measures中,进行布局时,组件会回调measures函数获得每个单元格的尺寸,
123
- * 当一列放满单元格后(如果是纵向布局,则是一行放满后),自动换列去布局下一列。
124
- *
125
- * Q: 单元格的普通状态,焦点状态,失焦状态如何渲染?
126
- * A: 在单元的空间中通过往onAction注册的onFocus,onBlur控制显示
127
- *
128
- * Q: 控件中的导航处理(上下左右,OK键)需要什么响应的开发?
129
- * A: 上下左右键已经由控件接管,不需要开发者而外处理,上下左右键会触发翻页时间,翻页的形式由属性slideStyle来定制。
130
- * 另外,通过OnClick属性可以注册按键回调函数,来处理用户的OK键动作。
131
- *
132
- * Q: 边缘格获取焦点放大后显示不全?
133
- * A: 设置padding,注意item的排布范围是控件的宽高减去对应的padding
134
- *
135
- * Q: 焦点怎么移出控件?
136
- * A: 当焦点移动到控件边缘时,会调用onEdge回调。在回调中通过参数传递的值来决定焦点转移的行为
137
- *
138
- * Q: item内是可获焦的元素时该如何处理?
139
- * A: 焦点处理: item内的元素需要在注册的onFocus和onBlue回调中管理焦点. 即在onFocus时把焦点设置到内部的可获焦节点;
140
- onBlur时将焦点给回父SimpleWidget, 注意此时是焦点树上的子节点往父节点切换, 此时为了把子节点blur掉,
141
- requestFocus函数需要传递一个false参数
142
- -->
143
- <script>
144
- import { ref, reactive } from "vue";
145
- import RootView from "./RootView.vue";
146
- import Forge from "../ForgeDefine";
147
- import { TemplateParser } from "../TemplateParser";
148
- import { SingleRangeModel } from "../RangeModel";
149
- import Dispatcher from "./Dispatcher";
150
- import {
151
- EdgeDirection,
152
- VERTICAL,
153
- HORIZONTAL,
154
- SlideSetting,
155
- SeamlessSlide,
156
- getPositionRelativeToView,
157
- } from "../WidgetCommon";
158
-
159
- let emptyFunc = () => {};
160
- // randomColor() {
161
- // let randomColor = Math.round(Math.random() * 2 ** 24).toString(16);
162
- // return (
163
- // "#" + new Array(6 - randomColor.length).fill("0").join("") + randomColor
164
- // );
165
- // },
166
- const _getPadding = function (padding) {
167
- let result = {
168
- left: 0,
169
- right: 0,
170
- top: 0,
171
- bottom: 0,
172
- };
173
-
174
- if (typeof padding !== "undefined" && padding !== null) {
175
- Object.assign(result, padding);
176
- }
177
- return result;
178
- };
179
-
180
- const _AddTemplateItem = function (
181
- data,
182
- measure_func,
183
- template_parser,
184
- start_index
185
- ) {
186
- for (let i = start_index; i < data.length; i++) {
187
- let block_item = measure_func(data[i]);
188
- template_parser.ParseTemplateItem(block_item, data[i]);
189
- }
190
- template_parser.CalculateNeighborWhenAddStop();
191
- };
192
-
193
- const _getTemplateParser = function (
194
- width,
195
- height,
196
- direction,
197
- padding,
198
- support_history_path,
199
- layout_type
200
- ) {
201
- let fixed_padding = _getPadding(padding);
202
- let line_max =
203
- direction === VERTICAL
204
- ? width - fixed_padding.left - fixed_padding.right
205
- : height - fixed_padding.top - fixed_padding.bottom;
206
- return new TemplateParser(
207
- direction,
208
- line_max,
209
- layout_type,
210
- width,
211
- height,
212
- support_history_path
213
- );
214
- };
215
-
216
- // direction key 是 vertical 的值
217
- const directionFreeKeyMap = {
218
- pos: {
219
- true: "yPos",
220
- false: "xPos",
221
- },
222
- size: {
223
- true: "height",
224
- false: "width",
225
- },
226
- neighbor: {
227
- true: {
228
- 1: "bottom",
229
- "-1": "top",
230
- },
231
- false: {
232
- 1: "bottom",
233
- "-1": "top",
234
- },
235
- },
236
- margin: {
237
- true: "marginBottom",
238
- false: "marginRight",
239
- },
240
- center: {
241
- true: "centerYPos",
242
- false: "centerXPos",
243
- },
244
- };
245
-
246
- const defaultSlideSetting = new SeamlessSlide(0.2, 0.8);
247
- const SimpleWidget = {
248
- components: { RootView },
249
- props: {
250
- padding: {
251
- type: Object,
252
- default() {
253
- return {
254
- top: 0,
255
- left: 0,
256
- right: 0,
257
- bottom: 0,
258
- };
259
- },
260
- },
261
- direction: {
262
- type: Symbol,
263
- default: HORIZONTAL,
264
- },
265
- height: {
266
- type: Number,
267
- required: true,
268
- },
269
- width: {
270
- type: Number,
271
- required: true,
272
- },
273
- slideBoundary: {
274
- validator(value) {
275
- return !isNaN(value) && value < 0.5;
276
- },
277
- default: 0.2,
278
- },
279
- onClick: {
280
- type: Function,
281
- default: emptyFunc,
282
- },
283
- loopFocus: {
284
- type: Boolean,
285
- default: false,
286
- },
287
- onEdge: {
288
- type: Function,
289
- default: emptyFunc,
290
- },
291
- onFocus: {
292
- type: Function,
293
- default: emptyFunc,
294
- },
295
- onBlur: {
296
- type: Function,
297
- default: emptyFunc,
298
- },
299
- loadAll: {
300
- type: Boolean,
301
- default: false,
302
- },
303
- enableTouch: {
304
- type: Boolean,
305
- default: false,
306
- },
307
- flingPageWidth: {
308
- type: Number,
309
- default: -1,
310
- },
311
- flingPageEdge: {
312
- type: Number,
313
- default: 1 / 4,
314
- },
315
- dispatcher: {
316
- type: Object,
317
- },
318
- measures: {
319
- type: Function,
320
- required: true,
321
- },
322
- baseAnchor: {
323
- type: Object,
324
- },
325
- initFocusId: {
326
- type: Number,
327
- default: 0,
328
- },
329
- data: {
330
- type: Array,
331
- },
332
- left: {
333
- type: Number,
334
- default: 0,
335
- },
336
- top: {
337
- type: Number,
338
- default: 0,
339
- },
340
- name: {
341
- type: String,
342
- },
343
- supportHistoryPath: {
344
- type: Boolean,
345
- default: true,
346
- },
347
- itemConfig: {
348
- type: Function,
349
- },
350
- onFocusChange: {
351
- type: Function,
352
- },
353
- slideSetting: {
354
- type: SlideSetting,
355
- default: defaultSlideSetting,
356
- },
357
- layoutType: {
358
- type: String,
359
- default: "relative",
360
- },
361
- enableItemRenderBreak: {
362
- type: Boolean,
363
- default: false,
364
- },
365
- provideData: {
366
- type: Function,
367
- },
368
- },
369
- watch: {
370
- data: function (value, oldValue) {
371
- console.log("watch data change ", value, oldValue);
372
- },
373
- },
374
- setup(props) {
375
- return {
376
- token: ref(0),
377
- templateParser: null,
378
- innerData: [],
379
- dataList: [],
380
-
381
- enterFocusId: -1,
382
- enterFocusRect: null,
383
- focusId: 0,
384
- preFocusId: -1,
385
- preEdgeRect: null,
386
- isFocus: false,
387
- perAnchor: null,
388
- rootElement: null,
389
-
390
- visibleStart: 0,
391
- visibleRange: 0,
392
- visibleRangeWithPadding: 0,
393
-
394
- visibleItemIndexList: [],
395
- needHideItemIndexList: [],
396
-
397
- visibleRangeSearchBaseItem: 0,
398
-
399
- touchContainerW: 0,
400
- touchContainerH: 0,
401
- touchListener: null,
402
- innerPadding: null,
403
- slidePile: null,
404
- dragDirection: Forge.DragSetting.DIRECTION_HORIZONTAL,
405
- vertical: props.direction == VERTICAL,
406
- preAnchorItemIndex: -1,
407
- wholePageHeadItem: {},
408
- };
409
- },
410
- methods: {
411
- //供外部获取SimpleWidget内部状态
412
- _injectHandler() {
413
- return {
414
- getPosition: this._getPosition,
415
- getTemplatePosition: this._getTemplatePosition,
416
- getAbsolutePosition: this._getAbsolutePosition,
417
- registerItemFunc: this._registerItemFunc,
418
- getCurrentFocusId: this._getCurrentId,
419
- isFocus: this._isFocus,
420
- customerSlide: this.slideTo,
421
- updateMounted: this._updateMounted,
422
- registerItemRef: this._registerItemRef,
423
- onFocusChange: this._onFocusChange,
424
- };
425
- },
426
-
427
- _onFocusChange(id) {
428
- this.onFocusChange?.(id);
429
- },
430
-
431
- _isFocus() {
432
- return this.isFocus;
433
- },
434
-
435
- _getCurrentId() {
436
- return {
437
- id: this.focusId,
438
- index: this.templateParser.FocusIdToIndex(this.focusId),
439
- };
440
- },
441
-
442
- _registerItemFunc(index, handlerObj) {
443
- this.innerData[index].itemHandler = handlerObj;
444
- },
445
-
446
- _registerItemRef(index, itemRef) {
447
- this.innerData[index].itemRef = itemRef;
448
- },
449
-
450
- _updateMounted(index, mounted) {
451
- if (index >= this.innerData.length) {
452
- console.warn("sw updateMounted error: over range");
453
- return;
454
- }
455
- this.innerData[index].mounted = mounted;
456
- },
457
-
458
- _getPosition(index) {
459
- let item = this.templateParser.GetItem(index);
460
- let x_offset = this.direction === VERTICAL ? 0 : -this.visibleStart;
461
- let y_offset = this.direction === VERTICAL ? -this.visibleStart : 0;
462
- return {
463
- left: item.xPos + x_offset,
464
- top: item.yPos + y_offset,
465
- width: item.width,
466
- height: item.height,
467
- };
468
- },
469
-
470
- _getTemplatePosition(index) {
471
- let item = this.templateParser.GetItem(index);
472
- return {
473
- left: item.xPos,
474
- top: item.yPos,
475
- width: item.width,
476
- height: item.height,
477
- };
478
- },
479
-
480
- _getAbsolutePosition(index, targetEle) {
481
- return getPositionRelativeToView(
482
- this.innerData[index].itemRef?.getDivElement(),
483
- targetEle
484
- );
485
- },
486
-
487
- _dispatchEvent(event) {
488
- switch (event.type) {
489
- case Dispatcher.Type.setEnterFocusId:
490
- this.setEnterFocusId(event.data);
491
- break;
492
- case Dispatcher.Type.setEnterFocusRect:
493
- this.setEnterFocusRect(event.data);
494
- break;
495
- case Dispatcher.Type.updateItem:
496
- break;
497
- case Dispatcher.Type.slideToItem:
498
- if (event.data) {
499
- this.slideToItem(event.data?.id, event.data?.doAnim);
500
- }
501
- break;
502
- case Dispatcher.Type.setFocusId:
503
- this.setFocusId(
504
- event.data?.id,
505
- event.data?.needSlide,
506
- event.data?.doAnim
507
- );
508
- break;
509
- default:
510
- break;
511
- }
512
- },
513
-
514
- setFocusId(id, needSlide = true, doAnim = false) {
515
- let next_focus_item = this.templateParser.GetItemById(id);
516
- if (next_focus_item) {
517
- if (needSlide) {
518
- this.slideToItem(this.templateParser.FocusIdToIndex(id), doAnim);
519
- }
520
-
521
- const cur_focus_item = this.templateParser.GetItemById(this.focusId);
522
- this.preFocusId = this.focusId;
523
- this.focusId = next_focus_item.id;
524
-
525
- let x_off_set = cur_focus_item.xPos - next_focus_item.xPos;
526
- let y_off_set = cur_focus_item.yPos - next_focus_item.yPos;
527
- this.preEdgeRect = {
528
- direction: null,
529
- rect: {
530
- x: x_off_set,
531
- y: y_off_set,
532
- width: cur_focus_item.width,
533
- height: cur_focus_item.height,
534
- },
535
- };
536
- this._updateBlurItem();
537
- this._updateFocusItem();
538
- if (this.isFocus) {
539
- this.innerData[
540
- this.templateParser.FocusIdToIndex(this.preFocusId)
541
- ].itemHandler.onBlur?.();
542
- }
543
- if (
544
- this.isFocus &&
545
- this.innerData[this.templateParser.FocusIdToIndex(this.focusId)]
546
- .mounted
547
- ) {
548
- this.innerData[
549
- this.templateParser.FocusIdToIndex(this.focusId)
550
- ].itemHandler.onFocus?.(this.preEdgeRect);
551
- }
552
- }
553
- },
554
-
555
- setEnterFocusId(id) {
556
- this.enterFocusId = id;
557
- },
558
-
559
- setEnterFocusRect(rect) {
560
- this.enterFocusRect = rect;
561
- },
562
-
563
- slideTo(position, doAnim) {
564
- if (
565
- typeof position !== "undefined" &&
566
- position != null &&
567
- this.visibleStart !== position
568
- ) {
569
- this.visibleStart = position;
570
- let animObj = null;
571
- if (doAnim) {
572
- animObj = {
573
- easing: this.slideSetting.Easing,
574
- onstart: null,
575
- speed: this.slideSetting.Speed,
576
- onend: this._onSlideEnd,
577
- };
578
- }
579
- this.visibleRangeSearchBaseItem = this.focusId;
580
- this._updateVisibleList(
581
- this.focusId,
582
- this.visibleStart,
583
- this.visibleStart + this.visibleRangeWithPadding - 1
584
- );
585
- this._slideTo(this.visibleStart, animObj);
586
- }
587
- },
588
-
589
- slideToItem(index, doAnim) {
590
- const targetItem = this.templateParser.GetItem(index);
591
- if (targetItem) {
592
- const direction = index - this.preAnchorItemIndex > 0 ? 1 : -1;
593
- const visible_start = this._calculateVisibleStart(
594
- targetItem,
595
- direction
596
- );
597
- this.slideTo(visible_start, doAnim);
598
- }
599
- },
600
-
601
- freshData(force_update) {
602
- //由于data不支持reactive, 因此数据的更新只通过provideData
603
- if (!this.provideData) {
604
- console.error("freshData: provideData is null.");
605
- return;
606
- }
607
- let new_list = this.provideData();
608
- let new_index = 0;
609
- let template_list = this.templateParser.GetTemplate().List;
610
- if (!force_update) {
611
- for (new_index = 0; new_index < new_list.length; ++new_index) {
612
- let already_add = false;
613
- for (let j = 0; j < template_list.length; ++j) {
614
- if (new_list[new_index] === template_list[j].data) {
615
- already_add = true;
616
- break;
617
- }
618
- }
619
- if (!already_add) {
620
- break;
621
- }
622
- }
623
- }
624
- let need_update_content = false;
625
- if (new_index === template_list.length) {
626
- //原始数据都在
627
- if (new_index !== new_list.length) {
628
- //增加数据
629
- need_update_content = true;
630
- _AddTemplateItem(
631
- new_list,
632
- this.measures,
633
- this.templateParser,
634
- new_index
635
- );
636
- } else {
637
- //数据没变
638
- }
639
- } else {
640
- //数据更改
641
- need_update_content = true;
642
- let template_parser = _getTemplateParser(
643
- this.width,
644
- this.height,
645
- this.direction,
646
- this.padding,
647
- this.supportHistoryPath,
648
- this.layoutType
649
- );
650
- _AddTemplateItem(new_list, this.measures, template_parser, 0);
651
- this.templateParser = template_parser;
652
- }
653
- if (need_update_content) {
654
- let template_list = this.templateParser.GetTemplate().List;
655
- let last_item = template_list[template_list.length - 1];
656
- this.touchListener = this._getTouchListener();
657
- this.innerPadding = _getPadding(this.padding);
658
- this.touchContainerW =
659
- this.direction === VERTICAL
660
- ? this.width
661
- : last_item.xPos + last_item.width;
662
- this.touchContainerH =
663
- this.direction === VERTICAL
664
- ? last_item.yPos + last_item.height
665
- : this.height;
666
- this.slidePile = new Forge.RectArea(
667
- 0,
668
- 0,
669
- this.width - this.innerPadding.left - this.innerPadding.right,
670
- this.height - this.innerPadding.top - this.innerPadding.bottom
671
- );
672
- this.dragDirection =
673
- this.direction === VERTICAL
674
- ? Forge.DragSetting.DIRECTION_VERTICAL
675
- : Forge.DragSetting.DIRECTION_HORIZONTAL;
676
- this.innerData = template_list.map((item, index) => {
677
- return {
678
- data: item,
679
- index: index,
680
- controller: reactive({
681
- visible: false,
682
- zIndex: 0,
683
- }),
684
- mounted: false,
685
- itemRef: null,
686
- //之前的update时itemView不一定会重新create,因此注册的函数可以重复使用。若create了则会覆盖。
687
- itemHandler: this.innerData[index]
688
- ? { ...this.innerData[index].itemHandler }
689
- : {},
690
- itemConfig: this.itemConfig?.(item.data),
691
- };
692
- });
693
- this.token++;
694
- }
695
- if (this.focusId >= new_list.length) {
696
- this.focusId = 0;
697
- this.preFocusId = -1;
698
- this.visibleRangeSearchBaseItem = 0;
699
- if (this.visibleStart !== 0) {
700
- this.visibleStart = 0;
701
- this._slideTo(0, null);
702
- }
703
- }
704
- //重新获取可视itemlist
705
- this.visibleItemIndexList = this._getVisibleItemIndexList(
706
- this.visibleRangeSearchBaseItem,
707
- this.visibleStart,
708
- this.visibleStart + this.visibleRange - 1
709
- );
710
- if (
711
- this.isFocus &&
712
- this.innerData[this.templateParser.FocusIdToIndex(this.focusId)].mounted
713
- ) {
714
- this._updateFocusItem();
715
- this.innerData[
716
- this.templateParser.FocusIdToIndex(this.focusId)
717
- ].itemHandler.onFocus?.(null);
718
- }
719
- },
720
-
721
- _getVisibleItemIndexList(id, start, end) {
722
- // 扩展可视范围,避免快速滚动时闪烁
723
- let s = start - 100 > 0 ? start - 100 : 0;
724
- let e = end + 100;
725
- let visible_info = this.templateParser.GetVisibleItemList(s, e, id);
726
- let start_index = visible_info.visibleStart;
727
- let end_index = visible_info.visibleEnd;
728
-
729
- let index_list = new Array(end_index - start_index + 1);
730
- for (let i = start_index; i <= end_index; i++) {
731
- index_list[i - start_index] = i;
732
- }
733
- return index_list;
734
- },
735
-
736
- _calculateNearestItemByRect(visible_item_index_list, enter_rect_info) {
737
- let edge_direction = enter_rect_info.direction;
738
- let rect = enter_rect_info.rect;
739
- var direction = "";
740
- var point = { x: 0, y: 0 };
741
- switch (edge_direction) {
742
- case EdgeDirection.left:
743
- direction = "left";
744
- point.x = rect.x;
745
- point.y = rect.y + rect.height / 4;
746
- break;
747
- case EdgeDirection.right:
748
- direction = "right";
749
- point.x = rect.x + rect.width;
750
- point.y = rect.y + rect.height / 4;
751
- break;
752
- case EdgeDirection.top:
753
- direction = "up";
754
- point.x = rect.x + rect.width / 4;
755
- point.y = rect.y;
756
- break;
757
- case EdgeDirection.bottom:
758
- direction = "down";
759
- point.x = rect.x + rect.width / 4;
760
- point.y = rect.y + rect.height;
761
- break;
762
- default:
763
- break;
764
- }
765
-
766
- var src_x_range = new SingleRangeModel(point.x, point.x);
767
- var src_y_range = new SingleRangeModel(point.y, point.y);
768
-
769
- var min_distance_item = null;
770
- var min_distance = -1;
771
- var min_direction_weighted = 0;
772
- var distance = 0;
773
- var direction_weighted = 0; // 根据进入方向决定的权值,用于保证
774
-
775
- let key_pos = this.direction === VERTICAL ? "yPos" : "xPos";
776
- let key_width = this.direction === VERTICAL ? "height" : "width";
777
- for (let index of visible_item_index_list) {
778
- let item = this.templateParser.GetItem(index);
779
- if (!item.focusable) continue;
780
- let full_show =
781
- item[key_pos] >= this.visibleStart &&
782
- item[key_pos] + item[key_width] - 1 <=
783
- this.visibleStart + this.visibleRange - 1;
784
- if (full_show) {
785
- let x_pos =
786
- this.direction === VERTICAL
787
- ? item.xPos
788
- : item.xPos - this.visibleStart;
789
- let y_pos =
790
- this.direction === VERTICAL
791
- ? item.yPos - this.visibleStart
792
- : item.yPos;
793
- var target_x_range = new SingleRangeModel(
794
- x_pos,
795
- x_pos + item.width - 1
796
- );
797
- var target_y_range = new SingleRangeModel(
798
- y_pos,
799
- y_pos + item.height - 1
800
- );
801
- switch (direction) {
802
- case "left":
803
- if (point.x < x_pos + item.width - 1) {
804
- // 这个点在item左侧,不可能左移到item
805
- continue;
806
- }
807
- if (point.y < y_pos) {
808
- //1.该点在其上,计算point和item右上角的距离
809
- distance =
810
- Math.pow(point.x - (x_pos + item.width - 1), 2) +
811
- Math.pow(y_pos - point.y, 2);
812
- } else if (src_y_range.IsInterAct(target_y_range)) {
813
- //2.该点在其中,计算point和item右边框的垂直距离
814
- distance = Math.pow(point.x - (x_pos + item.width - 1), 2);
815
- } else if (point.y > y_pos + item.height - 1) {
816
- //3.该点在其下,计算point到item右下角的距离
817
- distance =
818
- Math.pow(point.x - (x_pos + item.width - 1), 2) +
819
- Math.pow(point.y - (y_pos + item.height - 1), 2);
820
- }
821
- // point与item右边框的距离作为权值
822
- direction_weighted = Math.abs(point.x - (x_pos + item.width - 1));
823
- break;
824
- case "right":
825
- if (point.x > x_pos) {
826
- // 这个点在item右侧,不可能右移到item
827
- continue;
828
- }
829
- if (point.y < y_pos) {
830
- //1.该点在其上, 计算point和item左上角的距离
831
- distance =
832
- Math.pow(x_pos - point.x, 2) + Math.pow(y_pos - point.y, 2);
833
- } else if (src_y_range.IsInterAct(target_y_range)) {
834
- //2.该点在其中,计算point和item左边框的垂直距离
835
- distance = Math.pow(x_pos - point.x, 2);
836
- //(x2-x1)^2
837
- } else if (point.y > y_pos + item.height - 1) {
838
- //3.该点在其下,计算point和item左下角的距离
839
- distance =
840
- Math.pow(x_pos - point.x, 2) +
841
- Math.pow(point.y - (y_pos + item.height - 1), 2);
842
- }
843
- // point与item左边框的距离作为权值
844
- direction_weighted = Math.abs(point.x - x_pos);
845
- break;
846
- case "up":
847
- if (point.y < y_pos + item.height - 1) {
848
- // 这个点在item上侧,不可能上移到item
849
- continue;
850
- }
851
- if (point.x < x_pos) {
852
- //1.该点在其前,计算point和item右下角的距离
853
- distance =
854
- Math.pow(point.x - x_pos, 2) +
855
- Math.pow(point.y - (y_pos + item.height - 1), 2);
856
- } else if (src_x_range.IsInterAct(target_x_range)) {
857
- //2.该点在其中,计算point和item下边框的垂直距离
858
- distance = Math.pow(point.y - (y_pos + item.height - 1), 2);
859
- } else if (point.x > x_pos + item.width - 1) {
860
- //3.该点在其后,计算point和item左下角的距离
861
- distance =
862
- Math.pow(point.x - (x_pos + item.width - 1), 2) +
863
- Math.pow(point.y - (y_pos + item.height - 1), 2);
864
- }
865
- // point与item下边框的距离作为权值
866
- direction_weighted = Math.abs(
867
- point.y - (y_pos + item.height - 1)
868
- );
869
- break;
870
- case "down":
871
- if (point.y > y_pos) {
872
- // 这个点在item下侧,不可能下移到item
873
- continue;
874
- }
875
- if (point.x < x_pos) {
876
- //1.该点在其前,计算point和item右上角的距离
877
- distance =
878
- Math.pow(point.x - x_pos, 2) + Math.pow(y_pos - point.y, 2);
879
- } else if (src_x_range.IsInterAct(target_x_range)) {
880
- //2.该点在其中,计算point和item上边框的垂直距离
881
- distance = Math.pow(y_pos - point.y, 2);
882
- } else if (point.x > x_pos + item.width - 1) {
883
- //3.该点在其后,计算point和item左上角的距离
884
- distance =
885
- Math.pow(point.x - (x_pos + item.width - 1), 2) +
886
- Math.pow(y_pos - point.y, 2);
887
- }
888
- // point与item上边框的距离作为权值
889
- direction_weighted = Math.abs(point.y - y_pos);
890
- break;
891
- default:
892
- console.log("direction is error:" + direction);
893
- break;
894
- }
895
- if (min_distance < 0) {
896
- // 设置首个找到的项目
897
- min_distance = distance;
898
- min_direction_weighted = direction_weighted;
899
- min_distance_item = item;
900
- } else {
901
- if (
902
- min_direction_weighted > direction_weighted ||
903
- (min_direction_weighted === direction_weighted &&
904
- min_distance > distance)
905
- ) {
906
- // 先进行权值比较,在权值相等时,再比较距离
907
- min_distance = distance;
908
- min_direction_weighted = direction_weighted;
909
- min_distance_item = item;
910
- }
911
- }
912
- }
913
- }
914
-
915
- if (min_distance_item) {
916
- return min_distance_item.id;
917
- } else {
918
- return 0;
919
- }
920
- },
921
-
922
- _updateItemVisibility(item_index_list, visibility) {
923
- for (let index of item_index_list) {
924
- this.innerData[index].controller.visible = visibility;
925
- }
926
- },
927
-
928
- _onClick(index) {
929
- return this.innerData[index].itemHandler.onClick?.();
930
- },
931
-
932
- onKeyDown(ev) {
933
- let horizontal_direction = 0;
934
- let vertical_direction = 0;
935
- switch (ev.keyCode) {
936
- case 37:
937
- horizontal_direction = -1;
938
- this._moveToNext(horizontal_direction, vertical_direction);
939
- break;
940
- case 38:
941
- vertical_direction = -1;
942
- this._moveToNext(horizontal_direction, vertical_direction);
943
- break;
944
- case 39:
945
- horizontal_direction = 1;
946
- this._moveToNext(horizontal_direction, vertical_direction);
947
- break;
948
- case 40:
949
- vertical_direction = 1;
950
- this._moveToNext(horizontal_direction, vertical_direction);
951
- break;
952
- case 13:
953
- this._onClick(this.templateParser.FocusIdToIndex(this.focusId));
954
- break;
955
- default:
956
- //只接受上下左右确定键
957
- return false;
958
- }
959
- return true;
960
- },
961
-
962
- _updateVisibleList(baseItemId, cur_visible_start, cur_visible_end) {
963
- let pre_visible_list = this.visibleItemIndexList;
964
- this.visibleItemIndexList = this._getVisibleItemIndexList(
965
- baseItemId,
966
- cur_visible_start,
967
- cur_visible_end
968
- );
969
- for (let index of pre_visible_list) {
970
- if (
971
- this.visibleItemIndexList.indexOf(index) < 0 &&
972
- this.needHideItemIndexList.indexOf(index) < 0
973
- ) {
974
- this.needHideItemIndexList.push(index);
975
- }
976
- }
977
- for (let index of this.visibleItemIndexList) {
978
- let i = this.needHideItemIndexList.indexOf(index);
979
- if (i >= 0) {
980
- this.needHideItemIndexList.splice(i, 1);
981
- }
982
- }
983
-
984
- this.visibleStart = cur_visible_start;
985
- //可见的item设置visibility
986
- this._updateItemVisibility(this.visibleItemIndexList, true);
987
- },
988
-
989
- _slideTo(target, animObj) {
990
- if (this.direction === HORIZONTAL) {
991
- this.rootElement.updatePosition(-target, 0, animObj);
992
- } else {
993
- this.rootElement.updatePosition(0, -target, animObj);
994
- }
995
- },
996
-
997
- _moveToNext(horizontal_direction, vertical_direction, item_edge_rect) {
998
- let cur_focus_item = this.templateParser.GetItemById(this.focusId);
999
- let next_item_id = this.templateParser.GetNextItem(
1000
- this.focusId,
1001
- vertical_direction,
1002
- horizontal_direction,
1003
- this.loopFocus
1004
- );
1005
- if (next_item_id >= 0) {
1006
- this.preFocusId = this.focusId;
1007
- let next_focus_item = this.templateParser.GetItemById(next_item_id);
1008
- this.focusId = next_focus_item.id;
1009
- let direction =
1010
- this.direction === VERTICAL
1011
- ? vertical_direction
1012
- : horizontal_direction;
1013
-
1014
- let cur_visible_start = this._calculateVisibleStart(
1015
- next_focus_item,
1016
- direction
1017
- );
1018
- if (
1019
- !this.innerData[this.templateParser.FocusIdToIndex(next_item_id)]
1020
- .itemConfig?.takeOverSlide &&
1021
- this.visibleStart !== cur_visible_start
1022
- ) {
1023
- this.visibleStart = cur_visible_start;
1024
- let animObj = {
1025
- easing: "",
1026
- onstart: null,
1027
- speed: this.slideSetting.Speed,
1028
- onend: this._onSlideEnd,
1029
- };
1030
- this._slideTo(this.visibleStart, animObj);
1031
- this.visibleRangeSearchBaseItem = next_item_id;
1032
- this._updateVisibleList(
1033
- next_item_id,
1034
- cur_visible_start,
1035
- cur_visible_start + this.visibleRangeWithPadding - 1
1036
- );
1037
- } else {
1038
- // 无滚动, 通知父滚动
1039
- }
1040
-
1041
- let rect;
1042
- let x_off_set = cur_focus_item.xPos - next_focus_item.xPos;
1043
- let y_off_set = cur_focus_item.yPos - next_focus_item.yPos;
1044
- if (item_edge_rect) {
1045
- item_edge_rect.rect.x += x_off_set;
1046
- item_edge_rect.rect.y += y_off_set;
1047
- rect = item_edge_rect;
1048
- } else {
1049
- rect = {
1050
- direction: null,
1051
- rect: {
1052
- x: x_off_set,
1053
- y: y_off_set,
1054
- width: cur_focus_item.width,
1055
- height: cur_focus_item.height,
1056
- },
1057
- };
1058
- }
1059
- this.preEdgeRect = rect;
1060
- this._updateBlurItem();
1061
- this._updateFocusItem();
1062
- if (this.isFocus) {
1063
- this.innerData[
1064
- this.templateParser.FocusIdToIndex(this.preFocusId)
1065
- ].itemHandler.onBlur?.();
1066
- }
1067
-
1068
- if (
1069
- this.isFocus &&
1070
- this.innerData[this.templateParser.FocusIdToIndex(this.focusId)]
1071
- .mounted
1072
- ) {
1073
- this.innerData[
1074
- this.templateParser.FocusIdToIndex(this.focusId)
1075
- ].itemHandler.onFocus?.(this.preEdgeRect);
1076
- }
1077
- } else {
1078
- let x_off_set = this.direction === VERTICAL ? 0 : this.visibleStart;
1079
- let y_off_set = this.direction === VERTICAL ? this.visibleStart : 0;
1080
- let edge;
1081
- if (horizontal_direction === 1) {
1082
- edge = EdgeDirection.right;
1083
- }
1084
- if (horizontal_direction === -1) {
1085
- edge = EdgeDirection.left;
1086
- }
1087
- if (vertical_direction === 1) {
1088
- edge = EdgeDirection.bottom;
1089
- }
1090
- if (vertical_direction === -1) {
1091
- edge = EdgeDirection.top;
1092
- }
1093
- let rect = {
1094
- x: cur_focus_item.xPos - x_off_set,
1095
- y: cur_focus_item.yPos - y_off_set,
1096
- width: cur_focus_item.width,
1097
- height: cur_focus_item.height,
1098
- };
1099
- if (this.onEdge) {
1100
- this.onEdge({ direction: edge, rect: rect });
1101
- }
1102
- this.innerData[
1103
- this.templateParser.FocusIdToIndex(this.focusId)
1104
- ].itemHandler.reachEdge?.({
1105
- direction: edge,
1106
- });
1107
- }
1108
- },
1109
-
1110
- _adjustToValidPosition(visible_start, adjust_end) {
1111
- //TODO 优化
1112
- let last_item = this.templateParser.GetItem(-1);
1113
- let pos_key = directionFreeKeyMap.pos[this.direction === VERTICAL];
1114
- let size_key = directionFreeKeyMap.size[this.direction === VERTICAL];
1115
- let padding = _getPadding(this.padding);
1116
-
1117
- let padding_offset =
1118
- this.direction === VERTICAL
1119
- ? padding["bottom"] + padding["top"]
1120
- : padding["right"] + padding["left"];
1121
- let visible_range =
1122
- (this.direction === VERTICAL ? this.height : this.width) -
1123
- padding_offset;
1124
-
1125
- let last_position = last_item[pos_key] + last_item[size_key];
1126
- let last_item_off_set = last_position - visible_range;
1127
- last_item_off_set = last_item_off_set < 0 ? 0 : last_item_off_set;
1128
- if (adjust_end && visible_start > last_item_off_set) {
1129
- return last_item_off_set;
1130
- } else if (visible_start < 0) {
1131
- return 0;
1132
- } else {
1133
- return visible_start;
1134
- }
1135
- },
1136
-
1137
- _getPageHeadItem(start, end, visible_start, pos_key) {
1138
- if (start != end) {
1139
- const center = Math.floor((start + end) / 2);
1140
- if (this.templateParser.GetItem(center)[pos_key] >= visible_start) {
1141
- return this._getPageHeadItem(start, center, visible_start, pos_key);
1142
- } else {
1143
- return this._getPageHeadItem(center + 1, end, visible_start, pos_key);
1144
- }
1145
- } else {
1146
- return start;
1147
- }
1148
- },
1149
-
1150
- _findNearestPageHeadItem(num) {
1151
- let max_page = -1;
1152
- for (let i in this.wholePageHeadItem) {
1153
- if (i < num && i > max_page) {
1154
- max_page = i;
1155
- }
1156
- }
1157
- if (max_page >= 0) {
1158
- return this.wholePageHeadItem[max_page];
1159
- } else {
1160
- return 0;
1161
- }
1162
- },
1163
-
1164
- _calculateVisibleStart(target_item, direction) {
1165
- if (!target_item) {
1166
- console.error(
1167
- "SimpleWidget: _calculateVisibleStart target item is null"
1168
- );
1169
- return 0;
1170
- }
1171
- this.preAnchorItemIndex = target_item.index;
1172
- let pos_key = directionFreeKeyMap.pos[this.vertical];
1173
- let size_key = directionFreeKeyMap.size[this.vertical];
1174
- let center_key = directionFreeKeyMap.center[this.vertical];
1175
- let new_visible_start = this.visibleStart;
1176
-
1177
- let page_start_index;
1178
- let page_num;
1179
- switch (this.slideSetting.Type) {
1180
- case SlideSetting.Type.FIX_POSITION:
1181
- //FIX_POSITION 模式会将当前 item 的中心固定到指定位置
1182
- new_visible_start = Math.ceil(
1183
- target_item[center_key] -
1184
- this.visibleRange * this.slideSetting.FixPercent
1185
- );
1186
- break;
1187
- case SlideSetting.Type.WHOLE_PAGE:
1188
- page_num = Math.floor(target_item[pos_key] / this.visibleRange);
1189
- if (typeof this.wholePageHeadItem[page_num] !== "undefined") {
1190
- page_start_index = this.wholePageHeadItem[page_num];
1191
- } else {
1192
- new_visible_start = page_num * this.visibleRange;
1193
- page_start_index = this._getPageHeadItem(
1194
- this._findNearestPageHeadItem(page_num),
1195
- target_item.index,
1196
- new_visible_start,
1197
- pos_key
1198
- );
1199
- this.wholePageHeadItem[page_num] = page_start_index;
1200
- }
1201
- new_visible_start =
1202
- this.templateParser.GetItem(page_start_index)[pos_key];
1203
- break;
1204
- case SlideSetting.Type.SEAMLESS:
1205
- if (direction > 0) {
1206
- if (
1207
- target_item[pos_key] + target_item[size_key] >
1208
- this.visibleStart +
1209
- this.visibleRange * this.slideSetting.EndPercent
1210
- ) {
1211
- new_visible_start =
1212
- target_item[pos_key] +
1213
- target_item[size_key] -
1214
- this.visibleRange * this.slideSetting.EndPercent;
1215
- }
1216
- } else if (direction < 0) {
1217
- if (
1218
- target_item[pos_key] <
1219
- this.visibleStart +
1220
- this.visibleRange * this.slideSetting.StartPercent
1221
- ) {
1222
- new_visible_start =
1223
- target_item[pos_key] -
1224
- this.visibleRange * this.slideSetting.StartPercent;
1225
- }
1226
- } else {
1227
- //不是沿widget方向的移动
1228
- if (target_item[pos_key] < this.visibleStart) {
1229
- new_visible_start =
1230
- target_item[pos_key] -
1231
- this.visibleRange * this.slideSetting.StartPercent;
1232
- } else if (
1233
- target_item[pos_key] + target_item[size_key] >
1234
- this.visibleStart + this.visibleRange
1235
- ) {
1236
- new_visible_start =
1237
- target_item[pos_key] +
1238
- target_item[size_key] -
1239
- this.visibleRange * this.slideSetting.EndPercent;
1240
- }
1241
- }
1242
- break;
1243
- default:
1244
- console.error(
1245
- "SimpleWidget: undefined slide type",
1246
- this.slideSetting.Type
1247
- );
1248
- }
1249
-
1250
- if (
1251
- (this.slideSetting.BoundaryProtect & SlideSetting.START_PROTECT) >
1252
- 0
1253
- ) {
1254
- let boundary = 0;
1255
- if (!this.templateParser.GetItem(0).focusable) {
1256
- //首个元素是占位符
1257
- boundary = this.templateParser.GetItem(0)[size_key];
1258
- }
1259
- new_visible_start =
1260
- new_visible_start < boundary ? 0 : new_visible_start;
1261
- }
1262
- if ((this.slideSetting.BoundaryProtect & SlideSetting.END_PROTECT) > 0) {
1263
- let last_item = this.templateParser.GetItem(-1);
1264
- let last_visible_start =
1265
- last_item[pos_key] + last_item[size_key] - this.visibleRange - 1;
1266
- last_visible_start = last_visible_start < 0 ? 0 : last_visible_start;
1267
- let boundary = last_visible_start;
1268
- if (!last_item.focusable) {
1269
- //最后个元素是占位符
1270
- boundary = last_item[pos_key] - this.visibleRange;
1271
- }
1272
- new_visible_start =
1273
- new_visible_start > boundary ? last_visible_start : new_visible_start;
1274
- }
1275
- return new_visible_start;
1276
- },
1277
-
1278
- _onFocusableItemEdge(edge_info) {
1279
- let horizontal_direction = 0;
1280
- let vertical_direction = 0;
1281
- switch (edge_info.direction) {
1282
- case EdgeDirection.left:
1283
- horizontal_direction = -1;
1284
- break;
1285
- case EdgeDirection.right:
1286
- horizontal_direction = 1;
1287
- break;
1288
- case EdgeDirection.top:
1289
- vertical_direction = -1;
1290
- break;
1291
- case EdgeDirection.bottom:
1292
- vertical_direction = 1;
1293
- break;
1294
- default:
1295
- break;
1296
- }
1297
- this._moveToNext(horizontal_direction, vertical_direction, edge_info);
1298
- },
1299
-
1300
- _ifValidEnterRect(rect_info) {
1301
- return rect_info && rect_info.direction && rect_info.rect;
1302
- },
1303
-
1304
- _setZIndex(index, z_index) {
1305
- this.innerData[index].controller.zIndex = z_index;
1306
- },
1307
-
1308
- _onFocus() {
1309
- let focus_id =
1310
- typeof this.enterFocusId !== "undefined" &&
1311
- this.enterFocusId >= 0 &&
1312
- this.enterFocusId < this.templateParser.GetTemplate().List.length
1313
- ? this.enterFocusId
1314
- : this.focusId;
1315
- focus_id = this._ifValidEnterRect(this.enterFocusRect)
1316
- ? this._calculateNearestItemByRect(
1317
- this.visibleItemIndexList,
1318
- this.enterFocusRect
1319
- )
1320
- : focus_id;
1321
-
1322
- this.isFocus = true;
1323
- this.focusId = focus_id;
1324
- this.preFocusId = -1;
1325
- this.enterFocusId = -1;
1326
- this.enterFocusRect = null;
1327
- this._updateFocusItem();
1328
-
1329
- if (
1330
- this.isFocus &&
1331
- this.innerData[this.templateParser.FocusIdToIndex(this.focusId)].mounted
1332
- ) {
1333
- this.innerData[
1334
- this.templateParser.FocusIdToIndex(this.focusId)
1335
- ].itemHandler.onFocus?.(this.preEdgeRect);
1336
- }
1337
-
1338
- if (this.onFocus) {
1339
- this.onFocus();
1340
- }
1341
- },
1342
-
1343
- _onBlur() {
1344
- this.isFocus = false;
1345
- this.enterFocusId = -1;
1346
- this.enterFocusRect = null;
1347
-
1348
- this.preFocusId = this.focusId;
1349
- this.preEdgeRect = null;
1350
- this._updateBlurItem();
1351
- this.innerData[
1352
- this.templateParser.FocusIdToIndex(this.preFocusId)
1353
- ].itemHandler.onBlur?.();
1354
-
1355
- if (this.onBlur) {
1356
- this.onBlur();
1357
- }
1358
- },
1359
-
1360
- _applyHideItemIndexList() {
1361
- this._updateItemVisibility(this.needHideItemIndexList, false);
1362
- this.needHideItemIndexList = [];
1363
- },
1364
-
1365
- _onSlideEnd(event) {
1366
- if (event && event.stopPropagation) {
1367
- event.stopPropagation();
1368
- }
1369
- this._applyHideItemIndexList();
1370
- },
1371
-
1372
- _onContentUpdate() {
1373
- this._updateItemVisibility(this.visibleItemIndexList, true);
1374
- this._updateFocusItem();
1375
- },
1376
-
1377
- _updateFocusItem() {
1378
- this._setZIndex(
1379
- this.templateParser.FocusIdToIndex(this.focusId),
1380
- this.innerData.length
1381
- );
1382
- },
1383
-
1384
- _updateBlurItem() {
1385
- this._setZIndex(this.templateParser.FocusIdToIndex(this.preFocusId), 0);
1386
- },
1387
-
1388
- _updateFocusByDragInfo(viewX, viewY) {
1389
- let enterFocusRect = null;
1390
- //模拟最小区域作为输入区域
1391
- if (this.direction === VERTICAL) {
1392
- enterFocusRect = {
1393
- direction: EdgeDirection.top,
1394
- rect: {
1395
- x: this.left - viewX,
1396
- y: this.top - viewY,
1397
- width: 10,
1398
- height: 10,
1399
- },
1400
- };
1401
- } else {
1402
- enterFocusRect = {
1403
- direction: EdgeDirection.left,
1404
- rect: {
1405
- x: this.left - viewX,
1406
- y: this.top - viewY,
1407
- width: 10,
1408
- height: 10,
1409
- },
1410
- };
1411
- }
1412
- this.focusId = this._calculateNearestItemByRect(
1413
- this.visibleItemIndexList,
1414
- enterFocusRect
1415
- );
1416
- },
1417
-
1418
- _registerRootView(ele) {
1419
- this.rootElement = ele;
1420
- },
1421
-
1422
- _tryReoprtVisibleEvent(msg) {
1423
- if (typeof msg.viewY != "undefined" && typeof msg.viewX != "undefined") {
1424
- if (this.direction === VERTICAL) {
1425
- this.visibleStart = -msg.viewY;
1426
- } else {
1427
- this.visibleStart = -msg.viewX;
1428
- }
1429
- if (this.visibleStart < 0) {
1430
- this.visibleStart = 0;
1431
- }
1432
- }
1433
-
1434
- let cur_visible_start =
1435
- this.visibleStart - this.visibleRangeWithPadding * 2;
1436
- let cur_visible_end =
1437
- this.visibleStart + this.visibleRangeWithPadding * 3 - 1;
1438
- let baseItemId = this.visibleRangeSearchBaseItem
1439
- ? this.visibleRangeSearchBaseItem
1440
- : 0;
1441
- this._updateVisibleList(baseItemId, cur_visible_start, cur_visible_end);
1442
- },
1443
-
1444
- _getTouchListener() {
1445
- if (!this.enableTouch) {
1446
- return null;
1447
- }
1448
- let callback = {
1449
- OnDragStart: (msg) => {
1450
- // console.log("SimpleWidget Container OnDragStart:", msg);
1451
- //删除焦点
1452
- Promise.resolve().then(() => {
1453
- this._tryReoprtVisibleEvent(msg);
1454
- Forge.sRenderBridge.InstantPerformSwap();
1455
- });
1456
- return true;
1457
- },
1458
- OnMoved: (msg) => {
1459
- Promise.resolve().then(() => {
1460
- this._tryReoprtVisibleEvent(msg);
1461
- Forge.sRenderBridge.InstantPerformSwap();
1462
- });
1463
- return true;
1464
- },
1465
- OnDragEnd: (msg) => {
1466
- // console.log("SimpleWidget Container OnDragEnd:", msg);
1467
- this._tryReoprtVisibleEvent(msg);
1468
- this._updateFocusByDragInfo(msg["viewX"], msg["viewY"]);
1469
- this._onSlideEnd();
1470
- return true;
1471
- },
1472
- OnFling: (msg) => {
1473
- // console.log("SimpleWidget Container OnFling:", msg);
1474
- this._tryReoprtVisibleEvent(msg);
1475
- this._updateFocusByDragInfo(msg["viewX"], msg["viewY"]);
1476
- this._onSlideEnd();
1477
- return true;
1478
- },
1479
- OnRelease: () => {
1480
- // console.log("SimpleWidget Container OnRelease:", msg);
1481
- return true;
1482
- },
1483
- };
1484
- return callback;
1485
- },
1486
- _getFocusBlockActions() {
1487
- return {
1488
- onFocus: this._onFocus,
1489
- onBlur: this._onBlur,
1490
- onKeyDown: this.onKeyDown,
1491
- };
1492
- },
1493
- },
1494
- created() {
1495
- if (this.dispatcher) {
1496
- this.dispatcher.registerComponent(this);
1497
- }
1498
-
1499
- let template_parser = _getTemplateParser(
1500
- this.width,
1501
- this.height,
1502
- this.direction,
1503
- this.padding,
1504
- this.supportHistoryPath,
1505
- this.layoutType
1506
- );
1507
- if (this.provideData) {
1508
- this.dataList = this.provideData();
1509
- } else if (this.data) {
1510
- this.dataList = this.data;
1511
- }
1512
- _AddTemplateItem(this.dataList, this.measures, template_parser, 0);
1513
- this.templateParser = template_parser;
1514
- let template_list = this.templateParser.GetTemplate().List;
1515
- let last_item = template_list[template_list.length - 1];
1516
- this.touchListener = this._getTouchListener();
1517
- this.innerPadding = _getPadding(this.padding);
1518
- this.touchContainerW =
1519
- this.direction === VERTICAL
1520
- ? this.width
1521
- : last_item.xPos + last_item.width;
1522
- this.touchContainerH =
1523
- this.direction === VERTICAL
1524
- ? last_item.yPos + last_item.height
1525
- : this.height;
1526
- this.slidePile = new Forge.RectArea(
1527
- 0,
1528
- 0,
1529
- this.width - this.innerPadding.left - this.innerPadding.right,
1530
- this.height - this.innerPadding.top - this.innerPadding.bottom
1531
- );
1532
- this.dragDirection =
1533
- this.direction === VERTICAL
1534
- ? Forge.DragSetting.DIRECTION_VERTICAL
1535
- : Forge.DragSetting.DIRECTION_HORIZONTAL;
1536
- this.innerData = template_list.map((item, index) => {
1537
- return {
1538
- data: item,
1539
- index: index,
1540
- controller: reactive({
1541
- visible: false,
1542
- zIndex: 0,
1543
- }),
1544
- mounted: false,
1545
- itemRef: null,
1546
- itemHandler: {},
1547
- itemConfig: this.itemConfig?.(item.data),
1548
- };
1549
- });
1550
- let visible_base_index = 0;
1551
- let init_focus_id = 0;
1552
- let cur_visible_start = 0;
1553
- this.visibleRange =
1554
- this.direction === VERTICAL
1555
- ? this.height - this.innerPadding.top - this.innerPadding.bottom
1556
- : this.width - this.innerPadding.left - this.innerPadding.right;
1557
- this.visibleRangeWithPadding =
1558
- this.direction === VERTICAL ? this.height : this.width;
1559
- if (this.initFocusId) {
1560
- init_focus_id = this.initFocusId;
1561
- visible_base_index = this.templateParser.FocusIdToIndex(init_focus_id);
1562
- cur_visible_start = this._calculateVisibleStart(
1563
- this.templateParser.GetItemById(this.initFocusId),
1564
- 1
1565
- );
1566
- }
1567
-
1568
- this.visibleItemIndexList = this._getVisibleItemIndexList(
1569
- visible_base_index,
1570
- cur_visible_start,
1571
- cur_visible_start + this.visibleRange - 1
1572
- );
1573
- this.focusId = init_focus_id;
1574
- this.visibleStart = cur_visible_start;
1575
- },
1576
- updated() {},
1577
- mounted() {
1578
- if (this.visibleStart) {
1579
- this._slideTo(this.visibleStart, null);
1580
- }
1581
- },
1582
- beforeUnmount() {
1583
- if (this.dispatcher) {
1584
- this.dispatcher.unregisterComponent();
1585
- }
1586
- },
1587
- };
1588
-
1589
- export default SimpleWidget;
1590
- </script>
1591
-
1592
- <template>
1593
- <jsv-focus-block :name="name" :onAction="_getFocusBlockActions()">
1594
- <div
1595
- :style="{
1596
- left: left,
1597
- top: top,
1598
- width: width,
1599
- height: height,
1600
- overflow: 'hidden',
1601
- }"
1602
- >
1603
- <root-view
1604
- :token="token"
1605
- :x="innerPadding.left"
1606
- :y="innerPadding.top"
1607
- :width="touchContainerW"
1608
- :height="touchContainerH"
1609
- :flingPageWidth="flingPageWidth"
1610
- :flingPageEdge="flingPageEdge"
1611
- :slidePile="slidePile"
1612
- :direction="dragDirection"
1613
- :touchListener="touchListener"
1614
- :enableTouch="enableTouch"
1615
- :loadAll="loadAll"
1616
- :register="_registerRootView"
1617
- :data="innerData"
1618
- :onLoad="_onContentUpdate"
1619
- :onItemEdge="_onFocusableItemEdge"
1620
- :widgetHandler="_injectHandler()"
1621
- :enableItemRenderBreak="enableItemRenderBreak"
1622
- >
1623
- <template v-slot:renderItem="slotProps">
1624
- <slot name="renderItem" v-bind="slotProps"></slot>
1625
- </template>
1626
- </root-view>
1627
- </div>
1628
- </jsv-focus-block>
1629
- </template>