@shijiu/jsview-vue-samples 2.2.426-test.0 → 2.3.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.
- package/BakeViewDemo/AnimatePic.vue +1 -1
- package/Basic/components/text/TextDirection.vue +7 -1
- package/BasicFocusControl/components/BaseBlock.vue +65 -18
- package/BreakRender/assets/imageList.json +235 -235
- package/ColorSpace/App.vue +2 -2
- package/CoupletsTest/App.vue +1 -1
- package/CoupletsTest/widget/Banger/Banger.vue +3 -3
- package/CoupletsTest/widget/Banger/MaroonLoader.vue +5 -5
- package/CoupletsTest/widget/Couplets/Couplets.vue +4 -4
- package/CoupletsTest/widget/Fireworks/Fireworks.vue +13 -13
- package/CustomShader/App.vue +4 -4
- package/CustomShader/gaussianBlur.glsl +1 -1
- package/DashPath/App.vue +79 -0
- package/DashPath/AppForOperator.vue +35 -0
- package/DashPath/DashPath.vue +118 -0
- package/DemoForOperator/AnimPic/AnimPic.vue +47 -0
- package/DemoForOperator/AnimPic/App.vue +28 -0
- package/DemoForOperator/Banger/App.vue +26 -0
- package/DemoForOperator/Banger/Banger/Banger.vue +252 -0
- package/DemoForOperator/Banger/Banger/Maroon.vue +123 -0
- package/DemoForOperator/Banger/Banger/MaroonLoader.vue +78 -0
- package/DemoForOperator/Banger/Banger/SpriteDeal.js +30 -0
- package/DemoForOperator/Bounce/App.vue +43 -0
- package/DemoForOperator/Bounce/Bounce.vue +49 -0
- package/DemoForOperator/Bounce/FreeMoveBuilder.js +139 -0
- package/DemoForOperator/ChunLian/App.vue +47 -0
- package/DemoForOperator/ChunLian/Couplets.vue +248 -0
- package/DemoForOperator/EpisodeList/App.vue +80 -0
- package/DemoForOperator/EpisodeList/EpisodeList/Controller.vue +113 -0
- package/DemoForOperator/EpisodeList/EpisodeList/EpisodeList.vue +176 -0
- package/DemoForOperator/EpisodeList/GroupItem.vue +65 -0
- package/DemoForOperator/EpisodeList/ListItem.vue +48 -0
- package/DemoForOperator/Firework1/App.vue +25 -0
- package/DemoForOperator/Firework1/Fireworks.vue +358 -0
- package/DemoForOperator/Firework1/SpriteDeal.js +30 -0
- package/DemoForOperator/FlipPage/App.vue +75 -0
- package/DemoForOperator/FlipPage/FlipPage/FlipPage.vue +150 -0
- package/DemoForOperator/FlipPage/FlipPage/flipIn.glsl +41 -0
- package/DemoForOperator/FlipPage/FlipPage/flipOut.glsl +41 -0
- package/DemoForOperator/Focus/Alpha/AlphaFocusBox.vue +70 -0
- package/DemoForOperator/Focus/Alpha/AlphaPage.vue +40 -0
- package/DemoForOperator/Focus/Alpha/Item.vue +64 -0
- package/DemoForOperator/Focus/App.vue +124 -0
- package/DemoForOperator/Focus/CommonPageSetting.js +30 -0
- package/DemoForOperator/Focus/Item.vue +46 -0
- package/DemoForOperator/Focus/Light/Item.vue +67 -0
- package/DemoForOperator/Focus/Light/LightFocusBox.vue +46 -0
- package/DemoForOperator/Focus/Light/LightPage.vue +43 -0
- package/DemoForOperator/Focus/Light/utils/FrameCanvasStore.ts +68 -0
- package/DemoForOperator/Focus/Light/utils/RotateFrame.vue +146 -0
- package/DemoForOperator/Focus/Light/utils/circleHaloMask.png +0 -0
- package/DemoForOperator/Focus/Normal/Item.vue +64 -0
- package/DemoForOperator/Focus/Normal/NormalFocusBox.vue +53 -0
- package/DemoForOperator/Focus/Normal/NormalPage.vue +41 -0
- package/DemoForOperator/Focus/SwipeLight/Item.vue +73 -0
- package/DemoForOperator/Focus/SwipeLight/SwipeLightBox.vue +62 -0
- package/DemoForOperator/Focus/SwipeLight/SwipeLightPage.vue +44 -0
- package/DemoForOperator/FullscreenIn/App.vue +105 -0
- package/DemoForOperator/FullscreenIn/FullscreenPoster.vue +41 -0
- package/DemoForOperator/FullscreenIn/Item.vue +50 -0
- package/DemoForOperator/Genie/App.vue +78 -0
- package/DemoForOperator/Genie/geniePakcer/Genie.vue +699 -0
- package/DemoForOperator/Genie/geniePakcer/genieBottom.glsl +49 -0
- package/DemoForOperator/Genie/geniePakcer/genieLeft.glsl +50 -0
- package/DemoForOperator/Genie/geniePakcer/genieRight.glsl +57 -0
- package/DemoForOperator/Genie/geniePakcer/genieTop.glsl +50 -0
- package/DemoForOperator/GrayFilter/App.vue +51 -0
- package/DemoForOperator/GrayFilter/GrayFilter.vue +38 -0
- package/DemoForOperator/Jigsaw/App.vue +45 -0
- package/DemoForOperator/Jigsaw/JigsawFull.vue +100 -0
- package/DemoForOperator/Jigsaw/JigsawSingle.vue +86 -0
- package/DemoForOperator/Particle/App.vue +69 -0
- package/DemoForOperator/Particle/Drop/DropParticle.vue +176 -0
- package/DemoForOperator/Particle/Explode/ExplodeParticle.vue +99 -0
- package/DemoForOperator/PosterAnim/App.vue +125 -0
- package/DemoForOperator/PosterAnim/Bounce/BouncePage.vue +54 -0
- package/DemoForOperator/PosterAnim/Bounce/Item.vue +85 -0
- package/DemoForOperator/PosterAnim/Breath/BreathPage.vue +47 -0
- package/DemoForOperator/PosterAnim/Breath/Item.vue +58 -0
- package/DemoForOperator/PosterAnim/CommonPageSetting.js +30 -0
- package/DemoForOperator/PosterAnim/Item.vue +46 -0
- package/DemoForOperator/PosterAnim/PosterAnim.js +58 -0
- package/DemoForOperator/PosterAnim/Scale/Item.vue +72 -0
- package/DemoForOperator/PosterAnim/Scale/ScalePage.vue +48 -0
- package/DemoForOperator/PosterAnim/Shake/Item.vue +85 -0
- package/DemoForOperator/PosterAnim/Shake/ShakePage.vue +53 -0
- package/DemoForOperator/PosterOverflow/App.vue +116 -0
- package/DemoForOperator/PosterOverflow/Item.vue +67 -0
- package/DemoForOperator/PosterOverflow/PosterOverflow.vue +23 -0
- package/DemoForOperator/Ripple/App.vue +54 -0
- package/DemoForOperator/Ripple/Ripple.vue +50 -0
- package/DemoForOperator/ScalePoster/App.vue +4 -0
- package/DemoForOperator/ScalePoster/ScalePoster.vue +0 -0
- package/DemoForOperator/Sprite/App.vue +33 -0
- package/DemoForOperator/Sprite/Sprite.vue +90 -0
- package/DemoForOperator/Stretch/App.vue +103 -0
- package/DemoForOperator/Stretch/Stretch/Item.vue +192 -0
- package/DemoForOperator/Stretch/Stretch/Stretch.vue +168 -0
- package/DemoForOperator/TabContent/App.vue +89 -0
- package/DemoForOperator/TabContent/ContentPage.vue +66 -0
- package/DemoForOperator/TabContent/Item.vue +85 -0
- package/DemoForOperator/TabContent/PageItem.vue +40 -0
- package/DemoForOperator/TabContent/TabContent/CreepFocus.vue +160 -0
- package/DemoForOperator/TabContent/TabContent/Item.vue +63 -0
- package/DemoForOperator/TabContent/TabContent/TabContent.vue +146 -0
- package/DemoForOperator/TabContent/TabContent/TabItem.vue +368 -0
- package/DemoForOperator/TabContent/TabContent/TabWidget.vue +243 -0
- package/DemoForOperator/TabContent/TabContent/Util.js +3 -0
- package/DemoForOperator/TabContent/TabContent/ViewSwiper.vue +110 -0
- package/DemoForOperator/TabContent/testData.js +241 -0
- package/DemoForOperator/Vortex/App.vue +78 -0
- package/DemoForOperator/Vortex/Vortex/Vortex.vue +154 -0
- package/DemoForOperator/Vortex/Vortex/vortexIn.glsl +38 -0
- package/DemoForOperator/Vortex/Vortex/vortexOut.glsl +38 -0
- package/DemoForOperator/index.js +6 -0
- package/DemoForOperator/routeList.js +142 -0
- package/DemoHomepage/App.vue +50 -30
- package/DemoHomepage/components/Dialog.vue +1 -0
- package/DemoHomepage/components/TabFrame.vue +7 -0
- package/DemoHomepage/router.js +104 -81
- package/DemoHomepage/views/Homepage.vue +7 -2
- package/DivMetroPerformance/data.js +3 -3
- package/DriftScopeTest/App.vue +1 -1
- package/FilterDemo/AnimatePic.vue +1 -1
- package/FilterDemo/VideoLayer.vue +2 -2
- package/FullScreenFlex/TestFrame2.vue +1 -1
- package/GiftRain/App.vue +12 -12
- package/JsvPreDownloader/App.vue +4 -4
- package/MediaDemo/components/frames/AudioFrame.vue +1 -1
- package/MediaDemo/components/frames/VideoFrame.vue +1 -1
- package/MetroWidgetDemos/MassiveItems/ContentItem.vue +1 -1
- package/MetroWidgetDemos/MassiveItems/data.js +1 -1
- package/MetroWidgetDemos/PerformanceTest/data.js +3 -3
- package/MetroWidgetDemos/RefreshDemo/assets/imageList.json +235 -235
- package/MetroWidgetDemos/SkeletonDiagram/assets/imageList.json +235 -235
- package/MetroWidgetDemos/focusableItemMetroWidget/WidgetItem.vue +3 -1
- package/MetroWidgetDemos/routeList.js +17 -17
- package/Poster3d/App.vue +69 -0
- package/Poster3d/Poster3d.vue +92 -0
- package/PosterPacker/App.vue +3 -3
- package/PosterPacker/tools/vortexPacker/Vortex.vue +1 -1
- package/QrcodeDemo/App.vue +1 -1
- package/Ripple/App.vue +1 -1
- package/ScaleDownNeon/App.vue +4 -4
- package/SceneTransition/App.vue +2 -2
- package/SceneTransition/maskConfig/config2.js +12 -12
- package/SceneTransition/maskConfig/config3.js +14 -14
- package/SprayView/App.vue +96 -51
- package/SpringFestival/App.vue +73 -0
- package/SpringFestival/SpringFestivalScene/ChunLian.vue +211 -0
- package/SpringFestival/SpringFestivalScene/FreeMoveBuilder.js +139 -0
- package/SpringFestival/SpringFestivalScene/LanternAnim.js +60 -0
- package/SpringFestival/SpringFestivalScene/Rain.vue +137 -0
- package/SpringFestival/SpringFestivalScene/Scene.vue +218 -0
- package/SpringFestival/SpringFestivalScene/imageConfig.js +87 -0
- package/SpringFestival/SpringFestivalScene/index.js +1 -0
- package/Swiper/App.vue +28 -29
- package/Swiper/Item.vue +19 -0
- package/SwiperTest/App.vue +9 -9
- package/TestNativeSharedView/AckEventDefine.ts +82 -0
- package/TestNativeSharedView/App.vue +4 -6
- package/TestNativeSharedView/JsvDemoTester.js +131 -0
- package/TextureAnimation/App.vue +16 -6
- package/TextureAnimation/App3.vue +100 -0
- package/TextureAnimation/utils/FrameCanvasStore.ts +68 -0
- package/TextureAnimation/utils/RotateFrame.vue +146 -0
- package/TextureAnimation/utils/circleHaloMask.png +0 -0
- package/TombSweepingDayTest/Raining/RainScene.vue +4 -4
- package/ViewOpacity/App.vue +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export class AckEventDefine {
|
|
2
|
+
// Category
|
|
3
|
+
static CATEGORY_JSC: number = 1;
|
|
4
|
+
static CATEGORY_VIEW: number = 2;
|
|
5
|
+
static CATEGORY_EXCEPTION: number = 3;
|
|
6
|
+
|
|
7
|
+
// Type of jsc
|
|
8
|
+
// Content lifeCycle: event格式:
|
|
9
|
+
// {
|
|
10
|
+
// "act": string类型,当前动作,
|
|
11
|
+
// JsContext重载启动时(reload动作,或者loadUrl动作, 以及closeView时): "reset"
|
|
12
|
+
// js启动过程事件: 按顺序
|
|
13
|
+
// "systemJsLoaded": 系统js加载完成
|
|
14
|
+
// "engineJsRead": Engine Js 完成下载
|
|
15
|
+
// "engineJsLoaded": Engine Js 完成eval
|
|
16
|
+
// "mainJsRead": Main Js 完成下载
|
|
17
|
+
// "mainJsLoaded": Main Js 完成 eval
|
|
18
|
+
// "appJsStart": 开始运行框架的主入口处理
|
|
19
|
+
// "contextId": int类型,发生事件对应的context id,当url切换或者reload时,contentId会发生变化
|
|
20
|
+
// }
|
|
21
|
+
static TYPE_JS_CONTEXT_LIFECYCLE: number = 1;
|
|
22
|
+
|
|
23
|
+
// Content permission: event格式:
|
|
24
|
+
// {
|
|
25
|
+
// "contextId": int类型,发生事件对应的context id,当url切换或者reload时,contentId会发生变化
|
|
26
|
+
// "authDone": int类型 是否完成校验, 0: 还未进行校验, 1: 已完成校验
|
|
27
|
+
// ================== 授权做完后的信息 ====================
|
|
28
|
+
// success(bool): 当次授权校验是否通过
|
|
29
|
+
// showAlert(bool): APP界面右下角展示未授权提示,满足下面条件之一时会展示
|
|
30
|
+
// 1. app运行的main.js是未进行签名(签名参考src/appConfig/中的描述)的,提示"npm start 调试模式"
|
|
31
|
+
// 2. 仅在在线授权服务器无法达到, 并且达到允许次数时生效(每日累计1次, 最多累计30天), 提示"抢先版内核"
|
|
32
|
+
// 3. 远程授权api返回结果为未授权时
|
|
33
|
+
// 4. 本地有授权文件,但授权文件不合法或者过期
|
|
34
|
+
// errorCount(int): 在线授权api访问失败(网络不通)的累计次数, api访问到并拿到结果后清0
|
|
35
|
+
// checkType(int): 授权的校验方式, 1: 调试模式, 2: 本地文件校验的方式, 3: 在线校验方式
|
|
36
|
+
// customDescribe: 授权的描述, 许可范围等描述
|
|
37
|
+
// errorCode: 授权失败的错误码
|
|
38
|
+
// -1: apk签名不匹配(仅离线校验时)
|
|
39
|
+
// -2: js的app name未登记
|
|
40
|
+
// -3: js的app签名和app name登记信息不匹配
|
|
41
|
+
// -4: permission.js文件过期
|
|
42
|
+
// -5: core版本不匹配
|
|
43
|
+
// -6: 分支名不匹配
|
|
44
|
+
// -7: 在线鉴权时未通过的统一错误码(后台详细错误码搭建中...)
|
|
45
|
+
// -8: 页面为npm start的调试模式(开发人员调试时才会出现此状态)
|
|
46
|
+
// -101: 本地permission.js文件格式错误
|
|
47
|
+
// -102: permission.js文件授权信息中core版本无法正确解析为数字错误
|
|
48
|
+
// -103: permission.js文件授权信息中的日期格式错误
|
|
49
|
+
// -105: 在线鉴权api请求失败错误
|
|
50
|
+
// playerMaxVer(int): 播放器授权的最高版本(0000 00000) 前4位为渠道号,后5位为版本号
|
|
51
|
+
// }
|
|
52
|
+
static TYPE_JS_CONTEXT_PERMISSION: number = 2;
|
|
53
|
+
|
|
54
|
+
// Type of view
|
|
55
|
+
// Shared view layout: event格式:
|
|
56
|
+
// {
|
|
57
|
+
// "x": int类型,对应view更新到了x位置,
|
|
58
|
+
// "y": int类型,对应view更新到了y位置,
|
|
59
|
+
// "width": int类型,对应view宽度更新后的值,
|
|
60
|
+
// "height": int类型,对应view高度更新后的值,
|
|
61
|
+
// "mat4": native指针类型, view的位置信息的matrix,
|
|
62
|
+
// "visible": int类型, view是否可见,(0:不可见, 1:可见)
|
|
63
|
+
// "order": int类型, 本NativeSharedView的相对图层
|
|
64
|
+
// "dw": int类型,Design map width,用于换算x,y,width,height
|
|
65
|
+
// }
|
|
66
|
+
static TYPE_SHARED_VIEW_LAYOUT: number = 1;
|
|
67
|
+
|
|
68
|
+
// app view aspect ratio change: event格式:
|
|
69
|
+
// {
|
|
70
|
+
// "width": int类型,横轴比例,对应"16/9"中的16,
|
|
71
|
+
// "height": int类型,纵轴比例,对应"16/9"中的9,
|
|
72
|
+
// }
|
|
73
|
+
static TYPE_APP_ASPECT_RATIO_CHANGE: number = 2;
|
|
74
|
+
|
|
75
|
+
// Type of exception
|
|
76
|
+
// Unhandled exit action: event格式:
|
|
77
|
+
// {
|
|
78
|
+
// "reason": string类型,触发离开动作的触发器,例如: "backKey",
|
|
79
|
+
// "comment": string类型, 当BackKey场景, 为"keyDown"和"keyUp"
|
|
80
|
+
// }
|
|
81
|
+
static TYPE_EXCEPTION_UNHANDLED_EXIT_ACTION: number = 1;
|
|
82
|
+
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { JsvNativeSharedDiv, JsvFocusBlock, jJsvRuntimeBridge } from "jsview";
|
|
2
3
|
import {
|
|
3
|
-
JsvNativeSharedDiv,
|
|
4
|
-
JsvFocusBlock,
|
|
5
|
-
jJsvRuntimeBridge,
|
|
6
4
|
enableNativeViewListener,
|
|
7
5
|
disableNativeViewListener,
|
|
8
|
-
} from "
|
|
6
|
+
} from "./JsvDemoTester";
|
|
9
7
|
import { onBeforeUnmount, onMounted, reactive, watch, shallowRef } from "vue";
|
|
10
8
|
|
|
11
9
|
let state = reactive({
|
|
@@ -26,8 +24,8 @@ let _Index = 0;
|
|
|
26
24
|
//给两个div给定不同的响应式变量
|
|
27
25
|
let view1 = shallowRef("null");
|
|
28
26
|
let view2 = shallowRef("null");
|
|
29
|
-
let view1Dsp = shallowRef(
|
|
30
|
-
let view2Dsp = shallowRef(
|
|
27
|
+
let view1Dsp = shallowRef({ x: 0, y: 0, width: 0, height: 0 });
|
|
28
|
+
let view2Dsp = shallowRef({ x: 0, y: 0, width: 0, height: 0 });
|
|
31
29
|
let isShow = shallowRef(false);
|
|
32
30
|
let isStop = shallowRef(false);
|
|
33
31
|
//创造出需要的四个属性的对象
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import "./AckEventDefine"
|
|
2
|
+
import { AckEventDefine } from "./AckEventDefine";
|
|
3
|
+
|
|
4
|
+
let interfaceLoaded = false;
|
|
5
|
+
let idGeneratoer = 1;
|
|
6
|
+
let idObjectMap = {};
|
|
7
|
+
|
|
8
|
+
let TesterApis = {
|
|
9
|
+
"android": {
|
|
10
|
+
prepareApi: (resolve, reject) => {
|
|
11
|
+
let cb = () => {
|
|
12
|
+
// dynamic加载完成
|
|
13
|
+
if (window.jJsvDemoTester) {
|
|
14
|
+
console.log("window.jJsvDemoTester ready")
|
|
15
|
+
} else {
|
|
16
|
+
console.log("window.jJsvDemoTester failed")
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
console.log("remove cb=" + cb);
|
|
20
|
+
|
|
21
|
+
// 移除回调
|
|
22
|
+
window.JsView.removeEventListener(cb);
|
|
23
|
+
|
|
24
|
+
// 无论成功失败,暂且都论为加载完成
|
|
25
|
+
interfaceLoaded = true;
|
|
26
|
+
resolve();
|
|
27
|
+
};
|
|
28
|
+
window.JsView.addEventListener("__DemoTesterReady", cb);
|
|
29
|
+
window.JsView.ensureTesterUtils();
|
|
30
|
+
},
|
|
31
|
+
eventParser: (ret, reactive_ref) => {
|
|
32
|
+
// 返回是 .info 为android的bundle格式
|
|
33
|
+
let new_value = ret.info
|
|
34
|
+
.replace(/(\w+)\=/g, '"$1":')
|
|
35
|
+
.replace(/'/g, '"')
|
|
36
|
+
.replace(/^Bundle\[/, "")
|
|
37
|
+
.replace(/\]$/, "");
|
|
38
|
+
reactive_ref.value = new_value;
|
|
39
|
+
},
|
|
40
|
+
listenerToAckEvent: (nativeViewId, listenerId, callback) => {
|
|
41
|
+
// android
|
|
42
|
+
let eventName = "__enableNativeViewListener_" + listenerId;
|
|
43
|
+
window.JsView?.addEventListener(eventName, callback);
|
|
44
|
+
window.jJsvDemoTester?.enableNativeViewListener(nativeViewId, listenerId, eventName);
|
|
45
|
+
},
|
|
46
|
+
expireListener: (listenerId, callback) => {
|
|
47
|
+
window.JsView?.removeEventListener(callback);
|
|
48
|
+
window.jJsvDemoTester?.disableNativeViewListener(listenerId);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"pc-wasm": {
|
|
52
|
+
prepareApi: (resolve, reject) => {
|
|
53
|
+
// pc-wasm场景
|
|
54
|
+
interfaceLoaded = true;
|
|
55
|
+
resolve(); // 非JsView场景,默认为完成状态
|
|
56
|
+
},
|
|
57
|
+
eventParser: (ret, reactive_ref) => {
|
|
58
|
+
// ret为普通的json格式
|
|
59
|
+
reactive_ref.value = ret;
|
|
60
|
+
},
|
|
61
|
+
listenerToAckEvent: (nativeViewId, listenerId, callback) => {
|
|
62
|
+
// pc wasm
|
|
63
|
+
window.JsvCoreApi.WasmExt.listenerToAckEvent(
|
|
64
|
+
AckEventDefine.CATEGORY_VIEW,
|
|
65
|
+
AckEventDefine.TYPE_SHARED_VIEW_LAYOUT,
|
|
66
|
+
nativeViewId,
|
|
67
|
+
callback
|
|
68
|
+
);
|
|
69
|
+
},
|
|
70
|
+
expireListener: (listenerId, callback) => {
|
|
71
|
+
window.JsvCoreApi.WasmExt.recycleAckListener(callback);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
const ensureInterface = () => {
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
if (interfaceLoaded) {
|
|
80
|
+
// 已经加载完成
|
|
81
|
+
resolve();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
TesterApis[window.JsvCoreApi.Platform].prepareApi(resolve, reject);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const enableNativeViewListener = (nativeViewId, reactive_ref) => {
|
|
89
|
+
let listenerId = idGeneratoer;
|
|
90
|
+
idGeneratoer++;
|
|
91
|
+
idObjectMap[listenerId] = {
|
|
92
|
+
eventCallback: (event_info) => {
|
|
93
|
+
TesterApis[window.JsvCoreApi.Platform].eventParser(event_info, reactive_ref);
|
|
94
|
+
console.log(`JsvDemoTester nativeView viewid=${nativeViewId} info=${reactive_ref.value}`);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
(async () => {
|
|
99
|
+
await ensureInterface();
|
|
100
|
+
|
|
101
|
+
if (idObjectMap.hasOwnProperty(listenerId)) {
|
|
102
|
+
TesterApis[window.JsvCoreApi.Platform]
|
|
103
|
+
.listenerToAckEvent(
|
|
104
|
+
nativeViewId,
|
|
105
|
+
listenerId,
|
|
106
|
+
idObjectMap[listenerId].eventCallback);
|
|
107
|
+
}
|
|
108
|
+
})();
|
|
109
|
+
|
|
110
|
+
return listenerId; // 用于 disableNativeViewListener() 调用
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const disableNativeViewListener = (listenerId) => {
|
|
114
|
+
(async () => {
|
|
115
|
+
await ensureInterface();
|
|
116
|
+
|
|
117
|
+
if (idObjectMap.hasOwnProperty(listenerId)) {
|
|
118
|
+
TesterApis[window.JsvCoreApi.Platform].expireListener(
|
|
119
|
+
listenerId, idObjectMap[listenerId].eventCallback
|
|
120
|
+
);
|
|
121
|
+
delete idObjectMap[listenerId];
|
|
122
|
+
} else {
|
|
123
|
+
console.warn("disableNativeViewListener id gone");
|
|
124
|
+
}
|
|
125
|
+
})();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
enableNativeViewListener,
|
|
130
|
+
disableNativeViewListener,
|
|
131
|
+
}
|
package/TextureAnimation/App.vue
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
jJsvRuntimeBridge,
|
|
4
|
+
getKeyFramesGroup,
|
|
5
|
+
JsvTextureAnim,
|
|
6
|
+
DefaultKeyCodeMap,
|
|
7
|
+
} from "jsview";
|
|
3
8
|
import img from "./assets/borderOpacity.png";
|
|
4
9
|
import swipLight from "./assets/swipLight.png";
|
|
5
|
-
import { onMounted, onBeforeUnmount } from "vue";
|
|
10
|
+
import { onMounted, onBeforeUnmount, shallowRef } from "vue";
|
|
6
11
|
import { useRouter } from "vue-router";
|
|
7
12
|
const router = useRouter();
|
|
8
13
|
const styleShell = getKeyFramesGroup();
|
|
@@ -13,6 +18,9 @@ const borderRadius = 40;
|
|
|
13
18
|
const repeat = -1;
|
|
14
19
|
const duration = 3000;
|
|
15
20
|
|
|
21
|
+
let sTranslateTextureRef = shallowRef(null);
|
|
22
|
+
let sTranslateTextureTrigger = shallowRef(1);
|
|
23
|
+
|
|
16
24
|
const translateAnim =
|
|
17
25
|
"{from {transform: translate3d(-100%, -50%, 0);} to {transform: translate3d(100%, 50%, 0);}}";
|
|
18
26
|
const rotateAnim =
|
|
@@ -30,6 +38,9 @@ const onKeyDown = (ev) => {
|
|
|
30
38
|
// 8:Backspace, 27:Escape, 10000:盒子返回键
|
|
31
39
|
if (ev.keyCode == 8 || ev.keyCode == 27 || ev.keyCode == 10000) {
|
|
32
40
|
router?.go(-1); // 有router时,是从DemoHomepage进入,回退
|
|
41
|
+
} else if (ev.keyCode == DefaultKeyCodeMap.Ok) {
|
|
42
|
+
sTranslateTextureRef.value.start();
|
|
43
|
+
sTranslateTextureTrigger.value = sTranslateTextureTrigger.value + 1;
|
|
33
44
|
}
|
|
34
45
|
return true;
|
|
35
46
|
};
|
|
@@ -68,6 +79,7 @@ onBeforeUnmount(() => {
|
|
|
68
79
|
}"
|
|
69
80
|
/>
|
|
70
81
|
<jsv-texture-anim
|
|
82
|
+
ref="sTranslateTextureRef"
|
|
71
83
|
:src="img"
|
|
72
84
|
:width="300"
|
|
73
85
|
:height="150"
|
|
@@ -75,18 +87,16 @@ onBeforeUnmount(() => {
|
|
|
75
87
|
:duration="duration"
|
|
76
88
|
:transform="null"
|
|
77
89
|
:borderRadius="borderRadius"
|
|
78
|
-
:repeat="repeat"
|
|
79
90
|
:autoStart="true"
|
|
80
91
|
></jsv-texture-anim>
|
|
81
92
|
<div
|
|
93
|
+
:key="sTranslateTextureTrigger"
|
|
82
94
|
:style="{
|
|
83
95
|
width: 300,
|
|
84
96
|
height: 150,
|
|
85
97
|
backgroundColor: 'rgba(255,0,0,0.5)',
|
|
86
98
|
transform: null,
|
|
87
|
-
animation: `texture-anim-translate ${
|
|
88
|
-
duration / 1000
|
|
89
|
-
}s linear infinite`,
|
|
99
|
+
animation: `texture-anim-translate ${duration / 1000}s linear 1`,
|
|
90
100
|
}"
|
|
91
101
|
/>
|
|
92
102
|
</div>
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, shallowRef, onBeforeUnmount } from "vue";
|
|
3
|
+
import { useRouter } from "vue-router";
|
|
4
|
+
import img from "./assets/blackWhiteTurntable.png";
|
|
5
|
+
import img2 from "./assets/light.png";
|
|
6
|
+
import { getDataUrl } from "../CommonUtils/ResourceData";
|
|
7
|
+
import RotateFrame from "./utils/RotateFrame.vue";
|
|
8
|
+
//无网络环境下使用
|
|
9
|
+
const DemoResourceBase = getDataUrl();
|
|
10
|
+
|
|
11
|
+
const getRandom = (start, end) => {
|
|
12
|
+
return Math.round(Math.random() * (end - start) + start);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const router = useRouter();
|
|
16
|
+
const width = ref(300);
|
|
17
|
+
const height = ref(200);
|
|
18
|
+
const left = ref(50);
|
|
19
|
+
const top = ref(80);
|
|
20
|
+
|
|
21
|
+
const targetBorderRadius = 35;
|
|
22
|
+
const targetLineWidth = 2;
|
|
23
|
+
const texCoord = {
|
|
24
|
+
width: 400,
|
|
25
|
+
height: 400,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 其他回调处理
|
|
30
|
+
*/
|
|
31
|
+
const onKeyDown = (ev) => {
|
|
32
|
+
// 8:Backspace, 27:Escape, 10000:盒子返回键
|
|
33
|
+
if (ev.keyCode == 8 || ev.keyCode == 27 || ev.keyCode == 10000) {
|
|
34
|
+
router?.go(-1); // 有router时,是从DemoHomepage进入,回退
|
|
35
|
+
} else if (ev.keyCode == 13) {
|
|
36
|
+
left.value = getRandom(50, 400);
|
|
37
|
+
top.value = getRandom(80, 200);
|
|
38
|
+
width.value = getRandom(100, 300);
|
|
39
|
+
height.value = getRandom(100, 300);
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
onBeforeUnmount(() => {});
|
|
45
|
+
</script>
|
|
46
|
+
<template>
|
|
47
|
+
<jsv-focus-block
|
|
48
|
+
autoFocus
|
|
49
|
+
:onKeyDown="onKeyDown"
|
|
50
|
+
:style="{
|
|
51
|
+
width: 1280,
|
|
52
|
+
height: 720,
|
|
53
|
+
backgroundColor: 'rgba(0,0,0,0.7)',
|
|
54
|
+
}"
|
|
55
|
+
>
|
|
56
|
+
<div
|
|
57
|
+
:style="{
|
|
58
|
+
textAlign: 'center',
|
|
59
|
+
fontSize: 30,
|
|
60
|
+
lineHeight: 50,
|
|
61
|
+
color: '#ffffff',
|
|
62
|
+
left: 140,
|
|
63
|
+
top: 20,
|
|
64
|
+
width: 1000,
|
|
65
|
+
height: 50,
|
|
66
|
+
backgroundColor: 'rgba(27,38,151,0.8)',
|
|
67
|
+
}"
|
|
68
|
+
>
|
|
69
|
+
.9型的旋转焦点框,OK键进行随机位置+尺寸变换
|
|
70
|
+
</div>
|
|
71
|
+
<div>
|
|
72
|
+
<div
|
|
73
|
+
:style="{
|
|
74
|
+
left: left,
|
|
75
|
+
top: top,
|
|
76
|
+
width: width,
|
|
77
|
+
height: height,
|
|
78
|
+
backgroundColor: 'rgba(0, 255, 0, 0.7)',
|
|
79
|
+
borderRadius: targetBorderRadius,
|
|
80
|
+
fontSize: 30,
|
|
81
|
+
lineHeight: height,
|
|
82
|
+
textAlign: 'center',
|
|
83
|
+
}"
|
|
84
|
+
>
|
|
85
|
+
{{ "带光晕的焦点框" }}
|
|
86
|
+
</div>
|
|
87
|
+
<rotate-frame
|
|
88
|
+
:imageUrl="img"
|
|
89
|
+
:left="left"
|
|
90
|
+
:top="top"
|
|
91
|
+
:width="width"
|
|
92
|
+
:height="height"
|
|
93
|
+
:maxViewSize="texCoord"
|
|
94
|
+
:borderRadius="targetBorderRadius"
|
|
95
|
+
:lineWidth="targetLineWidth"
|
|
96
|
+
:withHalo="true"
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
</jsv-focus-block>
|
|
100
|
+
</template>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JsvTextureStoreApi,
|
|
3
|
+
} from "jsview";
|
|
4
|
+
|
|
5
|
+
declare interface CacheInfoType {
|
|
6
|
+
borderRadius: number;
|
|
7
|
+
lineWidth: number;
|
|
8
|
+
canvasSourceId: String;
|
|
9
|
+
borderOutset: number;
|
|
10
|
+
canvasWidth: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let sCurrentCacheList: Array<CacheInfoType> = [];
|
|
14
|
+
|
|
15
|
+
function checkCache(border_radius: number, line_width: number): CacheInfoType | null {
|
|
16
|
+
for (let cache_item of sCurrentCacheList) {
|
|
17
|
+
if (cache_item.borderRadius == border_radius && cache_item.lineWidth == line_width) {
|
|
18
|
+
return cache_item;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function BuildFrame(border_radius: number, line_width: number): CacheInfoType {
|
|
25
|
+
let frame_cache: CacheInfoType | null;
|
|
26
|
+
|
|
27
|
+
frame_cache = checkCache(border_radius, line_width);
|
|
28
|
+
if (frame_cache != null) {
|
|
29
|
+
return frame_cache;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let sampleImageWidth = (border_radius + line_width + 3) * 2;
|
|
33
|
+
let canvasRef = JsvTextureStoreApi.canvasTexture(
|
|
34
|
+
sampleImageWidth,
|
|
35
|
+
sampleImageWidth
|
|
36
|
+
); // 创建画布
|
|
37
|
+
|
|
38
|
+
let circleInnerDiameter = border_radius * 2; // 环形内直径, 为所要包括图形的borderRadius的一倍
|
|
39
|
+
let circleLineWidth = line_width; // 线宽
|
|
40
|
+
let circleRadius = Math.floor(circleInnerDiameter / 2 + circleLineWidth / 2); // 绘制线是圆圈的轨迹中线
|
|
41
|
+
let customPath = canvasRef.circlePath(
|
|
42
|
+
Math.floor(sampleImageWidth / 2),
|
|
43
|
+
Math.floor(sampleImageWidth / 2),
|
|
44
|
+
circleRadius
|
|
45
|
+
); // 创建圆环绘制路径,圆形在画布的中心点位置
|
|
46
|
+
canvasRef.drawColor("rgba(0,0,0,0)"); // 画布绘制半透明底色
|
|
47
|
+
customPath!.stroke(circleLineWidth, "#000000FF"); // 以给定线宽绘制圆环
|
|
48
|
+
let source_id = canvasRef.commit(); // texture和div的textureStore绑定
|
|
49
|
+
|
|
50
|
+
frame_cache = {
|
|
51
|
+
canvasWidth: sampleImageWidth,
|
|
52
|
+
borderRadius: border_radius,
|
|
53
|
+
lineWidth: line_width,
|
|
54
|
+
canvasSourceId: source_id,
|
|
55
|
+
borderOutset: Math.floor((sampleImageWidth - circleInnerDiameter) / 2), // (画布 - 圆环内直径) / 2
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// 永远保存,不删除,界面上理论上不会有太多种转框,所以只存不清理
|
|
59
|
+
sCurrentCacheList.push(frame_cache);
|
|
60
|
+
|
|
61
|
+
console.log("Rotate frame cache increase to " + sCurrentCacheList.length);
|
|
62
|
+
|
|
63
|
+
return frame_cache;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
BuildFrame,
|
|
68
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { defineProps } from "vue";
|
|
3
|
+
import { JsvTextureAnim, DECORATE_NINEPATCH_ALPHA_MIX } from "jsview";
|
|
4
|
+
import { BuildFrame } from "./FrameCanvasStore";
|
|
5
|
+
import mask from "./circleHaloMask.png";
|
|
6
|
+
|
|
7
|
+
const rProps = defineProps({
|
|
8
|
+
// 旋转圈内的url,可以是import内容,也可以是https内容
|
|
9
|
+
imageUrl: {
|
|
10
|
+
type: String,
|
|
11
|
+
require: true,
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
// 所包含区域的left, top, width, height
|
|
15
|
+
left: {
|
|
16
|
+
type: Number,
|
|
17
|
+
default: 0,
|
|
18
|
+
},
|
|
19
|
+
top: {
|
|
20
|
+
type: Number,
|
|
21
|
+
default: 0,
|
|
22
|
+
},
|
|
23
|
+
width: {
|
|
24
|
+
type: Number,
|
|
25
|
+
require: true,
|
|
26
|
+
},
|
|
27
|
+
height: {
|
|
28
|
+
type: Number,
|
|
29
|
+
require: true,
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
// 所包含区域的圆角值borderRadius
|
|
33
|
+
borderRadius: {
|
|
34
|
+
type: Number,
|
|
35
|
+
require: true,
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
// 焦点框的线宽
|
|
39
|
+
lineWidth: {
|
|
40
|
+
type: Number,
|
|
41
|
+
require: true,
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
// 焦点框旋转一圈所用的时间
|
|
45
|
+
oneCircleTime: {
|
|
46
|
+
type: Number,
|
|
47
|
+
default: 0.5, // 转一圈0.5秒
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
// 是否需要外发光光晕
|
|
51
|
+
withHalo: {
|
|
52
|
+
type: Boolean,
|
|
53
|
+
default: false,
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 设置转盘的绘制覆盖区域
|
|
58
|
+
* 注意texture的尺寸需要兼顾最大的view即可
|
|
59
|
+
*/
|
|
60
|
+
maxViewSize: {
|
|
61
|
+
type: Object, // { width: Number, height: Number },
|
|
62
|
+
default: {
|
|
63
|
+
width: 400,
|
|
64
|
+
height: 400,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// 基础旋转动画
|
|
70
|
+
const cRotateAnimation =
|
|
71
|
+
"{from {transform: rotate3d(0,0,1,0);} to {transform: rotate3d(0,0,1,360deg);}}";
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 创建右图的边缘遮罩,可调节边框的粗细:circleLineWidth
|
|
75
|
+
*/
|
|
76
|
+
// 设置设定模拟绘制.9图
|
|
77
|
+
const cFrameInfo = BuildFrame(rProps.borderRadius, rProps.lineWidth);
|
|
78
|
+
|
|
79
|
+
// 创建内边框(实心不发光部分)
|
|
80
|
+
const ninePatchDecorator1 = {
|
|
81
|
+
type: DECORATE_NINEPATCH_ALPHA_MIX,
|
|
82
|
+
url: `jsvtexturestore://${cFrameInfo.canvasSourceId}`,
|
|
83
|
+
imageWidth: cFrameInfo.canvasWidth, // 等同于画布宽
|
|
84
|
+
centerWidth: 2, // 固定为1或2, 但1在PC上绘制可能有异常
|
|
85
|
+
borderOutset: cFrameInfo.borderOutset, // (画布 - 圆环内直径) / 2
|
|
86
|
+
animTime: rProps.oneCircleTime,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 导入右图的边缘光晕部分的遮罩
|
|
91
|
+
*/
|
|
92
|
+
// 外发光的圈的图片信息, 完全按照 circleHaloMask来配置
|
|
93
|
+
const cOriginPngInfo = {
|
|
94
|
+
size: 160, // 图片尺寸
|
|
95
|
+
radius: 56, // 图片中的圆的圆内半径
|
|
96
|
+
};
|
|
97
|
+
const cRectRadius = Math.floor(rProps.borderRadius + rProps.lineWidth); // 光环在描边之外,留出描边的宽度
|
|
98
|
+
const ninePatchDecorator2 = {
|
|
99
|
+
type: DECORATE_NINEPATCH_ALPHA_MIX,
|
|
100
|
+
url: `url(${mask})`,
|
|
101
|
+
imageWidth: cOriginPngInfo.size,
|
|
102
|
+
imageDspWidth: Math.floor(
|
|
103
|
+
(cRectRadius / cOriginPngInfo.radius) * cOriginPngInfo.size
|
|
104
|
+
),
|
|
105
|
+
centerWidth: 2,
|
|
106
|
+
borderOutset: Math.floor(cOriginPngInfo.size / 2 - cOriginPngInfo.radius),
|
|
107
|
+
animTime: rProps.oneCircleTime,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const texCoord = {
|
|
111
|
+
width: rProps.maxViewSize.width,
|
|
112
|
+
height: rProps.maxViewSize.height,
|
|
113
|
+
};
|
|
114
|
+
</script>
|
|
115
|
+
<template>
|
|
116
|
+
<div>
|
|
117
|
+
<!-- 光晕(halo)在下,实心区域在上 -->
|
|
118
|
+
<jsv-texture-anim
|
|
119
|
+
v-if="rProps.withHalo"
|
|
120
|
+
:src="rProps.imageUrl"
|
|
121
|
+
:left="rProps.left"
|
|
122
|
+
:top="rProps.top"
|
|
123
|
+
:width="rProps.width"
|
|
124
|
+
:height="rProps.height"
|
|
125
|
+
:texCoord="texCoord"
|
|
126
|
+
:animation="cRotateAnimation"
|
|
127
|
+
:duration="5000"
|
|
128
|
+
:repeat="-1"
|
|
129
|
+
:autoStart="true"
|
|
130
|
+
:decorate="ninePatchDecorator2"
|
|
131
|
+
></jsv-texture-anim>
|
|
132
|
+
<jsv-texture-anim
|
|
133
|
+
:src="rProps.imageUrl"
|
|
134
|
+
:left="rProps.left"
|
|
135
|
+
:top="rProps.top"
|
|
136
|
+
:width="rProps.width"
|
|
137
|
+
:height="rProps.height"
|
|
138
|
+
:texCoord="texCoord"
|
|
139
|
+
:animation="cRotateAnimation"
|
|
140
|
+
:duration="5000"
|
|
141
|
+
:repeat="-1"
|
|
142
|
+
:autoStart="true"
|
|
143
|
+
:decorate="ninePatchDecorator1"
|
|
144
|
+
></jsv-texture-anim>
|
|
145
|
+
</div>
|
|
146
|
+
</template>
|
|
Binary file
|
|
@@ -34,11 +34,11 @@ import Rain from "./Rain.vue";
|
|
|
34
34
|
import { JsvRipple, JsvRippleShape, JsvAudio, JsvSoundPool } from "jsview";
|
|
35
35
|
import { shallowRef, onMounted, onBeforeUnmount } from "vue";
|
|
36
36
|
const bg =
|
|
37
|
-
"https://qcast
|
|
37
|
+
"https://cdn.release.qcast.cn/JsViewFrameworkTester/JsViewVueSampleResources/TombSweepingDayTest/Raining/RainScene/qingming_bg.jpg";
|
|
38
38
|
const title =
|
|
39
|
-
"https://qcast
|
|
39
|
+
"https://cdn.release.qcast.cn/JsViewFrameworkTester/JsViewVueSampleResources/TombSweepingDayTest/Raining/RainScene/qingming_title.png";
|
|
40
40
|
const musicBg =
|
|
41
|
-
"https://qcast
|
|
41
|
+
"https://cdn.release.qcast.cn/JsViewFrameworkTester/JsViewVueSampleResources/TombSweepingDayTest/Raining/RainScene/rain_background.mp3";
|
|
42
42
|
let timer = { id: -1, id2: -1 };
|
|
43
43
|
const soundPool = new JsvSoundPool(10);
|
|
44
44
|
let rippleViewRef = shallowRef(null);
|
|
@@ -62,7 +62,7 @@ const genSource = () => {
|
|
|
62
62
|
let _BgAudio = null;
|
|
63
63
|
//水波音效
|
|
64
64
|
const mySound =
|
|
65
|
-
"https://qcast
|
|
65
|
+
"https://cdn.release.qcast.cn/JsViewFrameworkTester/JsViewVueSampleResources/TombSweepingDayTest/Raining/RainScene/rain_tiktok.mp3";
|
|
66
66
|
//音效ref
|
|
67
67
|
let mySoundControl = null;
|
|
68
68
|
//音效回调
|
package/ViewOpacity/App.vue
CHANGED
|
@@ -11,9 +11,9 @@ import { useRouter } from "vue-router";
|
|
|
11
11
|
const router = useRouter();
|
|
12
12
|
|
|
13
13
|
const test1 =
|
|
14
|
-
"url(https://qcast
|
|
14
|
+
"url(https://cdn.release.qcast.cn/JsViewFrameworkTester/JsViewVueSampleResources/ViewOpacity/App/test_1.jpeg)";
|
|
15
15
|
const test2 =
|
|
16
|
-
"url(https://qcast
|
|
16
|
+
"url(https://cdn.release.qcast.cn/JsViewFrameworkTester/JsViewVueSampleResources/ViewOpacity/App/test_2.jpeg)";
|
|
17
17
|
|
|
18
18
|
const onKeyDown = (ev) => {
|
|
19
19
|
// 8:Backspace, 27:Escape, 10000:盒子返回键
|