@shijiu/jsview-vue-samples 2.0.999 → 2.0.1021
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/DemoHomepage/components/TabFrame.vue +14 -0
- package/DemoHomepage/router.js +30 -15
- package/DemoHomepage/views/Homepage.vue +11 -1
- package/FilterDemo/VideoLayer.vue +6 -2
- package/FocusMoveStyle/App.vue +136 -0
- package/FocusMoveStyle/Item.vue +74 -0
- package/FocusMoveStyle/assets/focus.png +0 -0
- package/GiftRain/App.vue +243 -0
- package/GiftRain/audio/boom.mp3 +0 -0
- package/GiftRain/audio/get.mp3 +0 -0
- package/GiftRain/common/Sound.js +48 -0
- package/GiftRain/components/RedPacket.vue +161 -0
- package/GiftRain/components/Score.vue +55 -0
- package/GiftRain/components/SpriteTranslate.vue +72 -0
- package/NinePatchDemo/App.vue +5 -1
- package/NinePatchDemo/Item.vue +1 -1
- package/TestNativeSharedView/App.vue +182 -0
- package/package.json +1 -1
|
@@ -39,6 +39,20 @@ export default {
|
|
|
39
39
|
focusable: true,
|
|
40
40
|
id: 1,
|
|
41
41
|
},
|
|
42
|
+
{
|
|
43
|
+
width: 200,
|
|
44
|
+
height: 50,
|
|
45
|
+
name: "首页/运营",
|
|
46
|
+
focusable: true,
|
|
47
|
+
id: 2,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
width: 200,
|
|
51
|
+
height: 50,
|
|
52
|
+
name: "游戏实例",
|
|
53
|
+
focusable: true,
|
|
54
|
+
id: 3,
|
|
55
|
+
}
|
|
42
56
|
];
|
|
43
57
|
const direction = VERTICAL;
|
|
44
58
|
return {
|
package/DemoHomepage/router.js
CHANGED
|
@@ -16,6 +16,11 @@ let routeList = [
|
|
|
16
16
|
path: '/feature/Basic',
|
|
17
17
|
component: () => import('jsview-vue-samples/Basic/App.vue'),
|
|
18
18
|
},
|
|
19
|
+
{
|
|
20
|
+
name: 'NativeSharedView测试',
|
|
21
|
+
path: '/feature/TestNativeSharedView',
|
|
22
|
+
component: () => import('jsview-vue-samples/TestNativeSharedView/App.vue'),
|
|
23
|
+
},
|
|
19
24
|
{
|
|
20
25
|
name: 'CSS预处理',
|
|
21
26
|
path: '/feature/CssPreprocessor',
|
|
@@ -33,7 +38,7 @@ let routeList = [
|
|
|
33
38
|
},
|
|
34
39
|
{
|
|
35
40
|
name: '.9图焦点框漂移',
|
|
36
|
-
path: '/
|
|
41
|
+
path: '/Operations/NinePatchDemo',
|
|
37
42
|
component: () => import('jsview-vue-samples/NinePatchDemo/App.vue'),
|
|
38
43
|
},
|
|
39
44
|
{
|
|
@@ -54,7 +59,7 @@ let routeList = [
|
|
|
54
59
|
},
|
|
55
60
|
{
|
|
56
61
|
name: '翻牌游戏',
|
|
57
|
-
path: '/
|
|
62
|
+
path: '/Game/FlipCard',
|
|
58
63
|
component: () => import('jsview-vue-samples/FlipCard/App.vue'),
|
|
59
64
|
},
|
|
60
65
|
{
|
|
@@ -69,12 +74,12 @@ let routeList = [
|
|
|
69
74
|
},
|
|
70
75
|
{
|
|
71
76
|
name: '动图',
|
|
72
|
-
path: '/
|
|
77
|
+
path: '/Operations/AnimPicture',
|
|
73
78
|
component: () => import('jsview-vue-samples/AnimPicture/App.vue'),
|
|
74
79
|
},
|
|
75
80
|
{
|
|
76
81
|
name: '粒子效果',
|
|
77
|
-
path: '/
|
|
82
|
+
path: '/Operations/SprayView',
|
|
78
83
|
component: () => import('jsview-vue-samples/SprayView/App.vue'),
|
|
79
84
|
},
|
|
80
85
|
{
|
|
@@ -84,7 +89,7 @@ let routeList = [
|
|
|
84
89
|
},
|
|
85
90
|
{
|
|
86
91
|
name: '长图片',
|
|
87
|
-
path: '/
|
|
92
|
+
path: '/Operations/LongImage',
|
|
88
93
|
component: () => import('jsview-vue-samples/LongImage/App.vue'),
|
|
89
94
|
},
|
|
90
95
|
{
|
|
@@ -104,12 +109,12 @@ let routeList = [
|
|
|
104
109
|
},
|
|
105
110
|
{
|
|
106
111
|
name: '抛物运动写法样例',
|
|
107
|
-
path: '/
|
|
112
|
+
path: '/Game/ThrowMoveDemo',
|
|
108
113
|
component: () => import('jsview-vue-samples/ThrowMoveDemo/App.vue'),
|
|
109
114
|
},
|
|
110
115
|
{
|
|
111
116
|
name: '精灵图',
|
|
112
|
-
path: '/
|
|
117
|
+
path: '/Game/SpriteImage',
|
|
113
118
|
component: () => import('jsview-vue-samples/SpriteImage/App.vue'),
|
|
114
119
|
},
|
|
115
120
|
{
|
|
@@ -124,27 +129,27 @@ let routeList = [
|
|
|
124
129
|
},
|
|
125
130
|
{
|
|
126
131
|
name: '拼图demo',
|
|
127
|
-
path: '/
|
|
132
|
+
path: '/Operations/MaskClip',
|
|
128
133
|
component: () => import('jsview-vue-samples/MaskClip/App.vue'),
|
|
129
134
|
},
|
|
130
135
|
{
|
|
131
136
|
name: 'SoundPool',
|
|
132
|
-
path: '/
|
|
137
|
+
path: '/Game/SoundPool',
|
|
133
138
|
component: () => import('jsview-vue-samples/SoundPool/App.vue'),
|
|
134
139
|
},
|
|
135
140
|
{
|
|
136
141
|
name: 'TextureAnimation',
|
|
137
|
-
path: '/
|
|
142
|
+
path: '/Operations/TextureAnimation',
|
|
138
143
|
component: () => import('jsview-vue-samples/TextureAnimation/App.vue'),
|
|
139
144
|
},
|
|
140
145
|
{
|
|
141
146
|
name: '焦点框旋转光效果',
|
|
142
|
-
path: '/
|
|
147
|
+
path: '/Operations/TextureAnimation2',
|
|
143
148
|
component: () => import('jsview-vue-samples/TextureAnimation/App2.vue'),
|
|
144
149
|
},
|
|
145
150
|
{
|
|
146
151
|
name: '公祭日黑白效果',
|
|
147
|
-
path: '/
|
|
152
|
+
path: '/Operations/GrayDown',
|
|
148
153
|
component: () => import('jsview-vue-samples/FilterDemo/App.vue'),
|
|
149
154
|
},
|
|
150
155
|
{
|
|
@@ -159,17 +164,17 @@ let routeList = [
|
|
|
159
164
|
},
|
|
160
165
|
{
|
|
161
166
|
name: '碰撞检测',
|
|
162
|
-
path: '/
|
|
167
|
+
path: '/Game/Collision',
|
|
163
168
|
component: () => import('jsview-vue-samples/Collision/App.vue'),
|
|
164
169
|
},
|
|
165
170
|
{
|
|
166
171
|
name: '碰撞即停',
|
|
167
|
-
path: '/
|
|
172
|
+
path: '/Game/ImpactStop',
|
|
168
173
|
component: () => import('jsview-vue-samples/ImpactStop/App.vue'),
|
|
169
174
|
},
|
|
170
175
|
{
|
|
171
176
|
name: '滚动图',
|
|
172
|
-
path: '/
|
|
177
|
+
path: '/Operations/Swiper',
|
|
173
178
|
component: () => import('jsview-vue-samples/Swiper/App.vue'),
|
|
174
179
|
},
|
|
175
180
|
{
|
|
@@ -177,6 +182,16 @@ let routeList = [
|
|
|
177
182
|
path: '/feature/JsvPreDownloader',
|
|
178
183
|
component: () => import('jsview-vue-samples/JsvPreDownloader/App.vue'),
|
|
179
184
|
},
|
|
185
|
+
{
|
|
186
|
+
name: '焦点移动样式',
|
|
187
|
+
path: '/Operations/FocusMoveStyle',
|
|
188
|
+
component: () => import('jsview-vue-samples/FocusMoveStyle/App.vue'),
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name:'红包雨',
|
|
192
|
+
path:'/Game/GiftRain',
|
|
193
|
+
component:()=>import('jsview-vue-samples/GiftRain/App.vue'),
|
|
194
|
+
}
|
|
180
195
|
];
|
|
181
196
|
|
|
182
197
|
//添加MetroWidget demo
|
|
@@ -10,8 +10,12 @@ const isDevelopment = process.env.NODE_ENV !== 'production';
|
|
|
10
10
|
|
|
11
11
|
const colorTemplete = ["#89BEB2", "#C9BA83", "#DED38C", "#DE9C53"];
|
|
12
12
|
|
|
13
|
+
//功能实例 MetroWidgetData 首页/运营 游戏实例
|
|
13
14
|
const featureData = [];
|
|
14
15
|
const metroWidgetData = [];
|
|
16
|
+
const operationsData=[];
|
|
17
|
+
const gameData=[]
|
|
18
|
+
|
|
15
19
|
for (let item of routeList) {
|
|
16
20
|
let obj = {
|
|
17
21
|
name: item.name,
|
|
@@ -26,9 +30,15 @@ for (let item of routeList) {
|
|
|
26
30
|
} else if (item.path.indexOf("metroWidget") >= 0) {
|
|
27
31
|
obj.backgroundColor = colorTemplete[metroWidgetData.length % 4];
|
|
28
32
|
metroWidgetData.push(obj);
|
|
33
|
+
}else if (item.path.indexOf("Operations") >= 0) {
|
|
34
|
+
obj.backgroundColor = colorTemplete[operationsData.length % 4];
|
|
35
|
+
operationsData.push(obj);
|
|
36
|
+
}else if (item.path.indexOf("Game") >= 0) {
|
|
37
|
+
obj.backgroundColor = colorTemplete[gameData.length % 4];
|
|
38
|
+
gameData.push(obj);
|
|
29
39
|
}
|
|
30
40
|
}
|
|
31
|
-
const dataList = [featureData, metroWidgetData];
|
|
41
|
+
const dataList = [featureData, metroWidgetData,operationsData,gameData];
|
|
32
42
|
|
|
33
43
|
let showExitDialog = shallowRef(false);
|
|
34
44
|
let contentData = shallowRef(dataList[0]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
2
|
+
import { JsvPlayer, globalLoadJsvPlayerPlugin } from "jsview";
|
|
3
3
|
|
|
4
4
|
const props = defineProps({
|
|
5
5
|
top: {
|
|
@@ -20,6 +20,10 @@ const props = defineProps({
|
|
|
20
20
|
},
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
+
globalLoadJsvPlayerPlugin((status)=>{
|
|
24
|
+
console.log("JsvPlayer plugin load status: " + status);
|
|
25
|
+
})
|
|
26
|
+
|
|
23
27
|
// const video_url = "http://qcast-image.oss-cn-qingdao.aliyuncs.com/homepage/20210207/52fae4231350c85fec605b47bbe479c5.mp4";
|
|
24
28
|
const video_url =
|
|
25
29
|
"http://qcast-image.oss-cn-qingdao.aliyuncs.com/homepage/20190726/4cc4e6a8fd7d9d9c707ed4c4da27ca9d.mp4";
|
|
@@ -47,7 +51,7 @@ const video_url =
|
|
|
47
51
|
animation: 'opacityVideoDemo_CompositeOpacity 3s infinite',
|
|
48
52
|
}"
|
|
49
53
|
>
|
|
50
|
-
<
|
|
54
|
+
<JsvPlayer
|
|
51
55
|
:src="video_url"
|
|
52
56
|
autoplay="autoplay"
|
|
53
57
|
loop="loop"
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { MetroWidget, HORIZONTAL, JsvNinePatch, useFocusHub } from "jsview";
|
|
3
|
+
import Item from "./Item.vue";
|
|
4
|
+
import borderImageUrl from "./assets/focus.png";
|
|
5
|
+
import { reactive, provide, onMounted } from "vue";
|
|
6
|
+
const focusHub = useFocusHub();
|
|
7
|
+
const randomColor = () => {
|
|
8
|
+
let randomColor = Math.round(Math.random() * 2 ** 24).toString(16);
|
|
9
|
+
return (
|
|
10
|
+
"#" + new Array(6 - randomColor.length).fill("0").join("") + randomColor
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
const focusSize = reactive({
|
|
14
|
+
width: 0,
|
|
15
|
+
height: 0,
|
|
16
|
+
left: 0,
|
|
17
|
+
top: 0,
|
|
18
|
+
onTransitionEnd: null,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const focusFrameController = {
|
|
22
|
+
preRect: null,
|
|
23
|
+
curRect: null,
|
|
24
|
+
onFocusChange: function (rect) {
|
|
25
|
+
this.preRect = this.curRect;
|
|
26
|
+
this.curRect = rect;
|
|
27
|
+
if (this.preRect) {
|
|
28
|
+
focusSize.left = Math.min(this.preRect.left, this.curRect.left);
|
|
29
|
+
focusSize.top = Math.min(this.preRect.top, this.curRect.top);
|
|
30
|
+
focusSize.width =
|
|
31
|
+
Math.max(
|
|
32
|
+
this.preRect.left + this.preRect.width,
|
|
33
|
+
this.curRect.left + this.curRect.width
|
|
34
|
+
) - Math.min(this.preRect.left, this.curRect.left);
|
|
35
|
+
focusSize.height =
|
|
36
|
+
Math.max(
|
|
37
|
+
this.preRect.top + this.preRect.height,
|
|
38
|
+
this.curRect.top + this.curRect.height
|
|
39
|
+
) - Math.min(this.preRect.top, this.curRect.top);
|
|
40
|
+
focusSize.onTransitionEnd = () => {
|
|
41
|
+
focusSize.left = this.curRect.left;
|
|
42
|
+
focusSize.top = this.curRect.top;
|
|
43
|
+
focusSize.width = this.curRect.width;
|
|
44
|
+
focusSize.height = this.curRect.height;
|
|
45
|
+
focusSize.onTransitionEnd = null;
|
|
46
|
+
};
|
|
47
|
+
} else {
|
|
48
|
+
focusSize.left = this.curRect.left;
|
|
49
|
+
focusSize.top = this.curRect.top;
|
|
50
|
+
focusSize.width = this.curRect.width;
|
|
51
|
+
focusSize.height = this.curRect.height;
|
|
52
|
+
focusSize.onTransitionEnd = null;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
provide("focusFrameController", focusFrameController);
|
|
57
|
+
|
|
58
|
+
const provideData = () => {
|
|
59
|
+
const data = [];
|
|
60
|
+
for (let i = 0; i < 20; ++i) {
|
|
61
|
+
data.push({
|
|
62
|
+
width: 100 + Math.round(Math.random() * 4) * 20,
|
|
63
|
+
height: 50,
|
|
64
|
+
color: randomColor(),
|
|
65
|
+
content: i,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return data;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const measures = (item) => {
|
|
72
|
+
return {
|
|
73
|
+
width: item.width,
|
|
74
|
+
height: item.height,
|
|
75
|
+
marginRight: 10,
|
|
76
|
+
marginBottom: 10,
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
onMounted(() => {
|
|
81
|
+
focusHub.setFocus("myWidget");
|
|
82
|
+
});
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<template>
|
|
86
|
+
<div :style="{ width: 1280, height: 720, backgroundColor: '#007788' }">
|
|
87
|
+
<div
|
|
88
|
+
:style="{
|
|
89
|
+
textAlign: 'center',
|
|
90
|
+
fontSize: 30,
|
|
91
|
+
lineHeight: 50,
|
|
92
|
+
color: '#ffffff',
|
|
93
|
+
left: 140,
|
|
94
|
+
top: 20,
|
|
95
|
+
width: 1000,
|
|
96
|
+
height: 50,
|
|
97
|
+
backgroundColor: 'rgba(27,38,151,0.8)',
|
|
98
|
+
}"
|
|
99
|
+
>
|
|
100
|
+
爬行样式的焦点示例
|
|
101
|
+
</div>
|
|
102
|
+
<metro-widget
|
|
103
|
+
name="myWidget"
|
|
104
|
+
:top="100"
|
|
105
|
+
:left="40"
|
|
106
|
+
:width="1200"
|
|
107
|
+
:height="110"
|
|
108
|
+
:direction="HORIZONTAL"
|
|
109
|
+
:provideData="provideData"
|
|
110
|
+
:measures="measures"
|
|
111
|
+
:padding="{ left: 20, right: 20, top: 20, height: 20 }"
|
|
112
|
+
>
|
|
113
|
+
<template #renderItem="{ data, onAction, query }">
|
|
114
|
+
<item :data="data" :onAction="onAction" :query="query" />
|
|
115
|
+
</template>
|
|
116
|
+
<template #background>
|
|
117
|
+
<jsv-nine-patch
|
|
118
|
+
:style="{
|
|
119
|
+
width: focusSize.width,
|
|
120
|
+
height: focusSize.height,
|
|
121
|
+
top: focusSize.top,
|
|
122
|
+
left: focusSize.left,
|
|
123
|
+
}"
|
|
124
|
+
:onTransitionEnd="focusSize.onTransitionEnd"
|
|
125
|
+
:imageUrl="borderImageUrl"
|
|
126
|
+
:imageWidth="55"
|
|
127
|
+
:centerWidth="1"
|
|
128
|
+
:borderOutset="13"
|
|
129
|
+
:imageDspWidth="30"
|
|
130
|
+
:animTime="0.2"
|
|
131
|
+
:waitForInit="true"
|
|
132
|
+
></jsv-nine-patch>
|
|
133
|
+
</template>
|
|
134
|
+
</metro-widget>
|
|
135
|
+
</div>
|
|
136
|
+
</template>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, inject, nextTick } from "vue";
|
|
3
|
+
|
|
4
|
+
const focusFrameController = inject("focusFrameController");
|
|
5
|
+
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
data: Object,
|
|
8
|
+
query: Object,
|
|
9
|
+
onEdge: Function,
|
|
10
|
+
onAction: Object,
|
|
11
|
+
frameChanged: Function,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const focusRect = ref({
|
|
15
|
+
left: 0,
|
|
16
|
+
top: 0,
|
|
17
|
+
width: 0,
|
|
18
|
+
height: 0,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const focused = ref(false);
|
|
22
|
+
const divRef = ref(null);
|
|
23
|
+
|
|
24
|
+
const onFocus = () => {
|
|
25
|
+
if (focusFrameController) {
|
|
26
|
+
const rect = props.query.templatePosition(props.query.index);
|
|
27
|
+
focusFrameController.onFocusChange(rect);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const onBlur = () => {
|
|
32
|
+
focused.value = false;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const onClicked = () => {
|
|
36
|
+
console.log("item clicked", props.data);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
props.onAction.register("onFocus", onFocus);
|
|
40
|
+
props.onAction.register("onBlur", onBlur);
|
|
41
|
+
props.onAction.register("onClick", onClicked);
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<div>
|
|
46
|
+
<div
|
|
47
|
+
ref="divRef"
|
|
48
|
+
:style="{
|
|
49
|
+
fontSize: 30,
|
|
50
|
+
width: data.width,
|
|
51
|
+
height: data.height,
|
|
52
|
+
color: '#FFFFFF',
|
|
53
|
+
backgroundColor: data.color,
|
|
54
|
+
borderRadius: 5,
|
|
55
|
+
}"
|
|
56
|
+
>
|
|
57
|
+
{{ data.content }}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</template>
|
|
61
|
+
|
|
62
|
+
<style scoped>
|
|
63
|
+
.focus {
|
|
64
|
+
transform: scale3d(1.2, 1.2, 1);
|
|
65
|
+
transition: transform 0.25s linear;
|
|
66
|
+
font-size: 30;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.blur {
|
|
70
|
+
transform: scale3d(1, 1, 1);
|
|
71
|
+
transition: transform 0.25s linear;
|
|
72
|
+
font-size: 30;
|
|
73
|
+
}
|
|
74
|
+
</style>
|
|
Binary file
|
package/GiftRain/App.vue
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<jsv-focus-block autoFocus ref="App" :onAction="actionDefines">
|
|
3
|
+
<div
|
|
4
|
+
:style="{ width: 1920, height: 1080, overflow: 'hidden', transform: 'scale3d(0.67,0.67,1)', left: -220 * 1.5 + 8, top: -170 - 8 }">
|
|
5
|
+
<JsvPreload :preloadList="preload_info"></JsvPreload>
|
|
6
|
+
<div
|
|
7
|
+
:style="{ backgroundImage: bg, width: 1920, height: 1080, overflow: 'hidden' }">
|
|
8
|
+
<Score :score="score"></Score>
|
|
9
|
+
<JsvActorMove key="JsvSpriteTranslate" :style="{
|
|
10
|
+
top: 476 * 1.5,
|
|
11
|
+
left: 220 * 1.5,
|
|
12
|
+
width: 194 * 1.5,
|
|
13
|
+
height: 244 * 1.5,
|
|
14
|
+
}" :control=_TranslateControl>
|
|
15
|
+
<div key="kimi" :style="{
|
|
16
|
+
top: 0,
|
|
17
|
+
left: 0,
|
|
18
|
+
width: 194 * 1.5,
|
|
19
|
+
height: 244 * 1.5,
|
|
20
|
+
backgroundImage: kimi,
|
|
21
|
+
}">
|
|
22
|
+
<div key="MoneyBag" ref="moneyBag" :style="{
|
|
23
|
+
top: 22 * 1.3,
|
|
24
|
+
left: 7,
|
|
25
|
+
width: 180 * 1.5,
|
|
26
|
+
height: 100 * 1.5,
|
|
27
|
+
backgroundColor: 'rgba(0,0,0,0)'
|
|
28
|
+
}"></div>
|
|
29
|
+
<div :style="{
|
|
30
|
+
top: 0,
|
|
31
|
+
left: 40 * 1.5,
|
|
32
|
+
width: 81 * 1.5,
|
|
33
|
+
height: 74 * 1.5,
|
|
34
|
+
visibility: scoreMinAnim !== null ? 'visible' : 'hidden',
|
|
35
|
+
backgroundImage: min_score_image,
|
|
36
|
+
animation: scoreMinAnim,
|
|
37
|
+
}" @animationend=_ScoreMinAnimationEnd />
|
|
38
|
+
<div :style="{
|
|
39
|
+
top: 0,
|
|
40
|
+
left: 40 * 1.5,
|
|
41
|
+
width: 81 * 1.5,
|
|
42
|
+
height: 74 * 1.5,
|
|
43
|
+
visibility: scoreAddAnim !== null ? 'visible' : 'hidden',
|
|
44
|
+
backgroundImage: add_score_image,
|
|
45
|
+
animation: scoreAddAnim,
|
|
46
|
+
}" @animationend=_ScoreAddAnimationEnd />
|
|
47
|
+
</div>
|
|
48
|
+
</JsvActorMove>
|
|
49
|
+
<RedPacket :MoneyBag="moneyBag" :onImpactTracer="_onImpactTracer" :_ScoreMinAnimationEnd="_ScoreMinAnimationEnd"
|
|
50
|
+
:_ScoreAddAnimationEnd="_ScoreAddAnimationEnd" />
|
|
51
|
+
|
|
52
|
+
</div>
|
|
53
|
+
<!-- 音频 -->
|
|
54
|
+
<JsvSystemAudio key="AudioBg" :src="_AudioBgUrl" :loop="true" :onRef="onRef1" :onLoad="audioOnLoad" />
|
|
55
|
+
|
|
56
|
+
<JsvSystemAudio v-if="!_DisableEffectSound" :onRef="onRef2" :loop="true" />
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
</div>
|
|
60
|
+
</jsv-focus-block>
|
|
61
|
+
</template>
|
|
62
|
+
<script setup>
|
|
63
|
+
/* eslint-disable */
|
|
64
|
+
import { JsvFocusBlock, JsvActorMove, JsvActorMoveControl, jJsvRuntimeBridge, JsvPreload, buildPreloadInfo,JsvSystemAudio} from "jsview";
|
|
65
|
+
import { shallowRef, onMounted, onBeforeUnmount } from "vue";
|
|
66
|
+
import { useRouter } from "vue-router";
|
|
67
|
+
import Score from "./components/Score.vue";
|
|
68
|
+
import RedPacket from "./components/RedPacket.vue";
|
|
69
|
+
import Sound from "./common/Sound.js"
|
|
70
|
+
//音频Sound
|
|
71
|
+
const MySound = new Sound()
|
|
72
|
+
//预加载信息
|
|
73
|
+
const kimi_normal = 'http://oss.image.qcast.cn/demo_images/red_packet_rain/kimi_normal.png';
|
|
74
|
+
const kimi_smile = 'http://oss.image.qcast.cn/demo_images/red_packet_rain/kimi_smile.png';
|
|
75
|
+
const kimi_boom = 'http://oss.image.qcast.cn/demo_images/red_packet_rain/kimi_boom.png';
|
|
76
|
+
const red_packet = 'http://oss.image.qcast.cn/demo_images/red_packet_rain/red.png';
|
|
77
|
+
const bigRed_packet = 'http://oss.image.qcast.cn/demo_images/red_packet_rain/bigred.png'
|
|
78
|
+
const boom_image = 'http://oss.image.qcast.cn/demo_images/red_packet_rain/boom.png'
|
|
79
|
+
const bg = 'http://oss.image.qcast.cn/demo_images/red_packet_rain/bg.jpg'
|
|
80
|
+
const preload_info = [
|
|
81
|
+
buildPreloadInfo(kimi_normal),
|
|
82
|
+
buildPreloadInfo(kimi_smile),
|
|
83
|
+
buildPreloadInfo(kimi_boom),
|
|
84
|
+
buildPreloadInfo(red_packet),
|
|
85
|
+
buildPreloadInfo(bigRed_packet),
|
|
86
|
+
buildPreloadInfo(boom_image),
|
|
87
|
+
buildPreloadInfo(bg)
|
|
88
|
+
];
|
|
89
|
+
//定义不需要响应式的变量
|
|
90
|
+
let _CurrentRain = null;
|
|
91
|
+
//音频ref
|
|
92
|
+
let _Audio = null;
|
|
93
|
+
let _AudioBgUrl = "https://qcast-image.oss-cn-qingdao.aliyuncs.com/JsViewAudio/MiniGameBackgroundMusic-redpack.mp3";
|
|
94
|
+
//背景音频ref
|
|
95
|
+
let _BgAudio = null;
|
|
96
|
+
let _IsRunning = false;
|
|
97
|
+
let _DisableEffectSound = true;
|
|
98
|
+
let _TranslateControl = new JsvActorMoveControl()
|
|
99
|
+
//定义需要响应式的变量
|
|
100
|
+
let kimi = shallowRef("http://oss.image.qcast.cn/demo_images/red_packet_rain/kimi_normal.png")
|
|
101
|
+
let score = shallowRef(0)
|
|
102
|
+
let min_score_image = shallowRef(null)
|
|
103
|
+
let add_score_image = shallowRef(null)
|
|
104
|
+
let scoreAddAnim = shallowRef(null)
|
|
105
|
+
let scoreMinAnim = shallowRef(null)
|
|
106
|
+
let moneyBag = shallowRef(null)
|
|
107
|
+
|
|
108
|
+
//定义扣分结束动画
|
|
109
|
+
const _ScoreAddAnimationEnd = (event) => {
|
|
110
|
+
// event.stopPropagation();
|
|
111
|
+
scoreAddAnim.value = null
|
|
112
|
+
console.log(" _ScoreAddAnimationEnd event:", event);
|
|
113
|
+
}
|
|
114
|
+
//定义加分结束动画
|
|
115
|
+
const _ScoreMinAnimationEnd = (event) => {
|
|
116
|
+
// event.stopPropagation();
|
|
117
|
+
scoreMinAnim.value = null
|
|
118
|
+
console.log(" _ScoreMinAnimationEnd event:", event);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//定义碰撞函数
|
|
122
|
+
const _onImpactTracer = (rain) => {
|
|
123
|
+
if (rain !== null && rain !== _CurrentRain) {
|
|
124
|
+
_CurrentRain = rain;
|
|
125
|
+
console.log("_onImpactTracer rain:", rain);
|
|
126
|
+
switch (rain.type) {
|
|
127
|
+
case 0:
|
|
128
|
+
scoreAddAnim.value = "scoreUp 0.2s";
|
|
129
|
+
kimi.value = "http://oss.image.qcast.cn/demo_images/red_packet_rain/kimi_normal.png";
|
|
130
|
+
add_score_image.value = "http://oss.image.qcast.cn/demo_images/red_packet_rain/add1.png";
|
|
131
|
+
score.value += 1;
|
|
132
|
+
MySound.playGetSound()
|
|
133
|
+
break;
|
|
134
|
+
case 1:
|
|
135
|
+
scoreAddAnim.value = "scoreUp 0.2s";
|
|
136
|
+
kimi.value = "http://oss.image.qcast.cn/demo_images/red_packet_rain/kimi_smile.png";
|
|
137
|
+
add_score_image.value = "http://oss.image.qcast.cn/demo_images/red_packet_rain/add5.png";
|
|
138
|
+
MySound.playGetSound()
|
|
139
|
+
score.value += 5;
|
|
140
|
+
break;
|
|
141
|
+
case 2:
|
|
142
|
+
scoreMinAnim.value = "scoreUp 0.2s";
|
|
143
|
+
min_score_image.value = "http://oss.image.qcast.cn/demo_images/red_packet_rain/min1.png";
|
|
144
|
+
kimi.value = "http://oss.image.qcast.cn/demo_images/red_packet_rain/kimi_boom.png";
|
|
145
|
+
score.value -= 1;
|
|
146
|
+
MySound.playBoomSound()
|
|
147
|
+
if (score.value < 0) {
|
|
148
|
+
score.value = 0;
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
default:
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//键盘松开时应该暂停动作
|
|
157
|
+
const onKeyUp = (ev) => {
|
|
158
|
+
console.log("onKeyUp in : ", ev);
|
|
159
|
+
if (ev.keyCode === 37 || ev.keyCode === 39) {
|
|
160
|
+
_IsRunning = false;
|
|
161
|
+
_TranslateControl.pause((x, y) => {
|
|
162
|
+
console.log(`_TranslateControl pause x:${x}`);
|
|
163
|
+
});
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const router = useRouter();
|
|
170
|
+
//定义键盘按下
|
|
171
|
+
const onKeyDown = (ev) => {
|
|
172
|
+
if (ev.keyCode == 8 || ev.keyCode == 27 || ev.keyCode == 10000) {
|
|
173
|
+
router.go(-1)
|
|
174
|
+
} else if (ev.keyCode === 37) {
|
|
175
|
+
console.log(" ev.keyCode === 37 ");
|
|
176
|
+
if (!_IsRunning) {
|
|
177
|
+
_TranslateControl.moveToX(0, 400 * 1.5, null);
|
|
178
|
+
_IsRunning = true;
|
|
179
|
+
}
|
|
180
|
+
} else if (ev.keyCode === 39) {
|
|
181
|
+
console.log(" ev.keyCode === 39");
|
|
182
|
+
if (!_IsRunning) {
|
|
183
|
+
_TranslateControl.moveToX((1280 - 220 - 194) * 1.5, 400 * 1.5, null);
|
|
184
|
+
_IsRunning = true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
//注册
|
|
191
|
+
const actionDefines = {
|
|
192
|
+
onKeyDown,
|
|
193
|
+
onKeyUp
|
|
194
|
+
}
|
|
195
|
+
//定义音频回调
|
|
196
|
+
const onRef1 = (ref) => {
|
|
197
|
+
_BgAudio = ref
|
|
198
|
+
}
|
|
199
|
+
const onRef2 = (ref) => {
|
|
200
|
+
_Audio = ref
|
|
201
|
+
}
|
|
202
|
+
const audioOnLoad = () => {
|
|
203
|
+
console.log("audio on load")
|
|
204
|
+
_BgAudio.play()
|
|
205
|
+
}
|
|
206
|
+
onMounted(() => {
|
|
207
|
+
//初始化音效
|
|
208
|
+
MySound.initSound();
|
|
209
|
+
//摘画布
|
|
210
|
+
jJsvRuntimeBridge.notifyPageLoaded();
|
|
211
|
+
window.BgAudio = _BgAudio;
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
//卸载之前摧毁音效
|
|
215
|
+
onBeforeUnmount(() => {
|
|
216
|
+
MySound.destroy();
|
|
217
|
+
});
|
|
218
|
+
</script>
|
|
219
|
+
|
|
220
|
+
<style scoped>
|
|
221
|
+
@keyframes scoreUp {
|
|
222
|
+
from {
|
|
223
|
+
transform: translate3d(0, 0, 0);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
to {
|
|
227
|
+
transform: translate3d(0, -20, 0);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@keyframes rainDown {
|
|
232
|
+
from {
|
|
233
|
+
transform: translate3d(0, -780, 0);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
to {
|
|
237
|
+
transform: translate3d(0, 0, 0);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
;
|
|
242
|
+
;
|
|
243
|
+
</style>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { JsvSoundPool } from "jsview";
|
|
2
|
+
import getAudio from "../audio/get.mp3";
|
|
3
|
+
import boomAudio from "../audio/boom.mp3";
|
|
4
|
+
|
|
5
|
+
class Sound {
|
|
6
|
+
initSound() {
|
|
7
|
+
this.soundPool = new JsvSoundPool(10);
|
|
8
|
+
this.soundPool.request(
|
|
9
|
+
`url(${getAudio})`,
|
|
10
|
+
null,
|
|
11
|
+
1,
|
|
12
|
+
(state, audioController) => {
|
|
13
|
+
console.log("load get audio ", state)
|
|
14
|
+
if (state === 0) {
|
|
15
|
+
Sound._AudioController1 = audioController;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
this.soundPool.request(
|
|
20
|
+
`url(${boomAudio})`,
|
|
21
|
+
null,
|
|
22
|
+
1,
|
|
23
|
+
(state, audioController) => {
|
|
24
|
+
console.log("load boom audio ", state)
|
|
25
|
+
if (state === 0) {
|
|
26
|
+
Sound._AudioController2 = audioController;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
playGetSound() {
|
|
33
|
+
if (Sound._AudioController1) {
|
|
34
|
+
Sound._AudioController1.play();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
playBoomSound() {
|
|
39
|
+
if (Sound._AudioController2) {
|
|
40
|
+
Sound._AudioController2.play();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
destroy () {
|
|
44
|
+
this.soundPool.destroy()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
export default Sound ;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div key="timer" :style="{
|
|
4
|
+
width: 140*1.5,
|
|
5
|
+
height: 140*1.5,
|
|
6
|
+
backgroundImage: _ScoreBg,
|
|
7
|
+
top: 40*1.5,
|
|
8
|
+
left: 40*1.5,
|
|
9
|
+
textAlign: 'center',
|
|
10
|
+
lineHeight: 140*1.5,
|
|
11
|
+
color: 'rgba(255,0,0,1.0)',
|
|
12
|
+
fontSize: 72*1.5
|
|
13
|
+
}">{{ timer }}</div>
|
|
14
|
+
<SpriteTranslate v-for="(item, index) in itemList" :MoneyBag="props.MoneyBag" :onImpactTracer="onImpactTracer"
|
|
15
|
+
:onDestory="_RemoveItem" :key="`spritetranslate${item.key}`" :item=item />
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup>
|
|
20
|
+
import { shallowRef, defineProps, onMounted, onBeforeUnmount } from 'vue';
|
|
21
|
+
import SpriteTranslate from './SpriteTranslate.vue';
|
|
22
|
+
//定义props
|
|
23
|
+
const props = defineProps({
|
|
24
|
+
onImpactTracer: Function,
|
|
25
|
+
MoneyBag: Object,
|
|
26
|
+
_ScoreMinAnimationEnd:Function,
|
|
27
|
+
_ScoreAddAnimationEnd:Function
|
|
28
|
+
})
|
|
29
|
+
let _Index = 0;
|
|
30
|
+
// 随机生成列表
|
|
31
|
+
const _RedImage = 'http://oss.image.qcast.cn/demo_images/red_packet_rain/red.png';
|
|
32
|
+
const _BigRedImage = 'http://oss.image.qcast.cn/demo_images/red_packet_rain/bigred.png';
|
|
33
|
+
const _BoomImage = 'http://oss.image.qcast.cn/demo_images/red_packet_rain/boom.png';
|
|
34
|
+
const _ScoreBg = "http://oss.image.qcast.cn/demo_images/red_packet_rain/score_bg.png";
|
|
35
|
+
let itemList =shallowRef([])
|
|
36
|
+
let timer = shallowRef(60)
|
|
37
|
+
const onImpactTracer = props.onImpactTracer;
|
|
38
|
+
let _TimerOutId = null;
|
|
39
|
+
let _GameTimerID = null;
|
|
40
|
+
let _IsRunning = shallowRef(false);
|
|
41
|
+
|
|
42
|
+
//定义随机加入的item
|
|
43
|
+
const addRandomItemList = () => {
|
|
44
|
+
const total_num = 1;
|
|
45
|
+
let ret_obj = "";
|
|
46
|
+
for (let i = 0; i < total_num; i++) {
|
|
47
|
+
const random_index = Math.floor(Math.random() * 3);
|
|
48
|
+
const duration = 2 + Math.floor(Math.random() * 2);
|
|
49
|
+
const index = ++_Index;
|
|
50
|
+
const left = 300 * 1.5 + Math.floor(Math.random() * (1280 - 500) * 1.5);
|
|
51
|
+
const top = -20 * 1.5;
|
|
52
|
+
|
|
53
|
+
switch (random_index) {
|
|
54
|
+
case 0:
|
|
55
|
+
ret_obj = {
|
|
56
|
+
key: index.toString(), type: 0, src: _RedImage, left, top, width: 87, height: 118, duration,
|
|
57
|
+
};
|
|
58
|
+
break;
|
|
59
|
+
case 1:
|
|
60
|
+
ret_obj = {
|
|
61
|
+
key: index.toString(), type: 1, src: _BigRedImage, left, top, width: 210, height: 114, duration,
|
|
62
|
+
};
|
|
63
|
+
break;
|
|
64
|
+
case 2:
|
|
65
|
+
ret_obj = {
|
|
66
|
+
key: index.toString(), type: 2, src: _BoomImage, left, top, width: 100, height: 116, duration
|
|
67
|
+
};
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log("initRandomItemList ret_obj:", ret_obj);
|
|
74
|
+
itemList.value.push(ret_obj);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// addRandomItemList();
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
const startTimer = () => {
|
|
82
|
+
_TimerOutId = setInterval(() => {
|
|
83
|
+
console.log('timmmm', timer.value);
|
|
84
|
+
timer.value = timer.value - 1;
|
|
85
|
+
if (timer.value === 0) {
|
|
86
|
+
stopGame();
|
|
87
|
+
itemList.value = []
|
|
88
|
+
}
|
|
89
|
+
}, 1000);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const startGame = () => {
|
|
93
|
+
console.log("startGame ");
|
|
94
|
+
_IsRunning.value = true;
|
|
95
|
+
_Refresh();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const stopGame = () => {
|
|
99
|
+
console.log("stopGame ");
|
|
100
|
+
_IsRunning.value = false;
|
|
101
|
+
if (_TimerOutId !== null) {
|
|
102
|
+
clearInterval(_TimerOutId);
|
|
103
|
+
_TimerOutId = null;
|
|
104
|
+
}
|
|
105
|
+
//停止游戏时动画也应该停止
|
|
106
|
+
props._ScoreMinAnimationEnd()
|
|
107
|
+
props._ScoreAddAnimationEnd()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const _RemoveItem = (key) => {
|
|
111
|
+
console.log("_RemoveItem in itemList.length:", itemList.value.length);
|
|
112
|
+
for (let i = 0; i < itemList.value.length; i++) {
|
|
113
|
+
if (itemList.value[i].key === key) {
|
|
114
|
+
const item = itemList.value[i];
|
|
115
|
+
if (item.sensor) {
|
|
116
|
+
item.sensor.Recycle();
|
|
117
|
+
}
|
|
118
|
+
console.log("_RemoveItem key:", itemList.value[i].key);
|
|
119
|
+
itemList.value.splice(i, 1);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
console.log("_RemoveItem out itemList.length:", itemList.value.length);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const _Refresh = () => {
|
|
127
|
+
if (_IsRunning.value === false) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const delay = 500;// Math.floor(Math.random()*600);
|
|
131
|
+
_GameTimerID = setTimeout(() => {
|
|
132
|
+
if (_IsRunning.value === true) {
|
|
133
|
+
addRandomItemList();
|
|
134
|
+
_Refresh();
|
|
135
|
+
}
|
|
136
|
+
}, delay);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
onMounted(() => {
|
|
141
|
+
console.log("render itemList.length:", itemList.value.length);
|
|
142
|
+
startGame();
|
|
143
|
+
startTimer();
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
onBeforeUnmount(() => {
|
|
147
|
+
if (_GameTimerID !== null) {
|
|
148
|
+
clearInterval(_GameTimerID);
|
|
149
|
+
_GameTimerID = null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (_TimerOutId !== null) {
|
|
153
|
+
clearInterval(_TimerOutId);
|
|
154
|
+
_TimerOutId = null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
stopGame();
|
|
158
|
+
})
|
|
159
|
+
</script>
|
|
160
|
+
|
|
161
|
+
<style scoped></style>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div key="progress-container" :style="{
|
|
4
|
+
width: 40 * 1.5,
|
|
5
|
+
height: 400 * 1.5,
|
|
6
|
+
top: 200 * 1.5,
|
|
7
|
+
left: (40 + 70 - 20) * 1.5,
|
|
8
|
+
backgroundColor: 'rgba(255,255,255,0.2)'
|
|
9
|
+
}">
|
|
10
|
+
<div key="progress" :style="{
|
|
11
|
+
top: process_top * 1.5,
|
|
12
|
+
width: 40 * 1.5,
|
|
13
|
+
height: score_height * 1.5,
|
|
14
|
+
backgroundColor: '#ffd050'
|
|
15
|
+
}">
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
<div key="score" :style="{
|
|
19
|
+
width: 140 * 1.5,
|
|
20
|
+
height: 40 * 1.5,
|
|
21
|
+
color: '#ffd050',
|
|
22
|
+
fontSize: 24 * 1.5,
|
|
23
|
+
top: 620 * 1.5,
|
|
24
|
+
left: 40 * 1.5,
|
|
25
|
+
lineHeight: 40 * 1.5,
|
|
26
|
+
textOverflow: 'clip',
|
|
27
|
+
textAlign: 'center'
|
|
28
|
+
}">{{ `分数:${score}` }}</div>
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup type="text/javascript">
|
|
33
|
+
/* eslint-disable */
|
|
34
|
+
import { shallowRef, defineProps, watch} from 'vue';
|
|
35
|
+
//定义props
|
|
36
|
+
const props = defineProps({
|
|
37
|
+
score: Number
|
|
38
|
+
})
|
|
39
|
+
//定义得分
|
|
40
|
+
let score_height = shallowRef(0);
|
|
41
|
+
// let score = toRef(props, 'score');
|
|
42
|
+
let process_top = shallowRef(0)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
//监听分数
|
|
46
|
+
watch(props, (n, o) => {
|
|
47
|
+
score_height.value = (props.score * 400 / 200)
|
|
48
|
+
if (score_height.value > 400) {
|
|
49
|
+
score_height.value = 400;
|
|
50
|
+
}
|
|
51
|
+
process_top.value = 400 - score_height.value;
|
|
52
|
+
})
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<style scoped></style>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<JsvActorMove :key="`translate${item.key}`" ref="translateF"
|
|
3
|
+
:style="{ left: item.left, top: item.top, width: item.width, height: item.height }" :control="_Control">
|
|
4
|
+
<div :key="`bg${item.key}`" ref="translate"
|
|
5
|
+
:style="{ backgroundImage: `url(${item.src})`, left: 0, top: 0, width: item.width, height: item.height }" />
|
|
6
|
+
</JsvActorMove>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup>
|
|
10
|
+
import { shallowRef, defineProps, onMounted, onBeforeMount } from 'vue';
|
|
11
|
+
import { JsvActorMove, JsvActorMoveControl, createImpactTracer, createImpactCallback, createImpactAutoFroze } from 'jsview'
|
|
12
|
+
//定义子ref
|
|
13
|
+
let translate = shallowRef(null)
|
|
14
|
+
//定义父ref
|
|
15
|
+
let translateF=shallowRef(null)
|
|
16
|
+
//定义props
|
|
17
|
+
const props = defineProps({
|
|
18
|
+
onDestory: Function,
|
|
19
|
+
item: Object,
|
|
20
|
+
onImpactTracer: Function,
|
|
21
|
+
MoneyBag: Object
|
|
22
|
+
})
|
|
23
|
+
const control = new JsvActorMoveControl();
|
|
24
|
+
const _Control = control;
|
|
25
|
+
const item = props.item;
|
|
26
|
+
//销毁方法
|
|
27
|
+
const _onDestroy = () => {
|
|
28
|
+
if (props.onDestory) {
|
|
29
|
+
props.onDestory(props.item.key);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let sensor = null;
|
|
34
|
+
|
|
35
|
+
const _InitItemEle = (item, ele) => {
|
|
36
|
+
if (ele && !item.ele) {
|
|
37
|
+
item.ele = ele;
|
|
38
|
+
if (props.MoneyBag) {
|
|
39
|
+
const giftrain_sensor = createImpactTracer(props.MoneyBag, ele, createImpactCallback(
|
|
40
|
+
() => {
|
|
41
|
+
props.onImpactTracer(item);
|
|
42
|
+
_onDestroy();
|
|
43
|
+
},
|
|
44
|
+
), //碰撞即停
|
|
45
|
+
createImpactAutoFroze(
|
|
46
|
+
[props.MoneyBag,translateF.value.mainDiv],
|
|
47
|
+
null
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
sensor = giftrain_sensor;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
//挂载时初始化
|
|
57
|
+
onMounted(() => {
|
|
58
|
+
_InitItemEle(item, translate.value)
|
|
59
|
+
_Control.moveToY(720 * 1.5 + 30, 720 * 1.5 / item.duration, () => {
|
|
60
|
+
_onDestroy();
|
|
61
|
+
});
|
|
62
|
+
})
|
|
63
|
+
//卸载之前释放碰撞监听者
|
|
64
|
+
onBeforeMount(()=>{
|
|
65
|
+
if(sensor!=null){
|
|
66
|
+
sensor.Recycle()
|
|
67
|
+
sensor=null
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<style lang="scss" scoped></style>
|
package/NinePatchDemo/App.vue
CHANGED
|
@@ -42,10 +42,13 @@ const measures = (item) => {
|
|
|
42
42
|
width: item.width,
|
|
43
43
|
height: item.height,
|
|
44
44
|
marginRight: 10,
|
|
45
|
-
marginTop: 10,
|
|
46
45
|
};
|
|
47
46
|
};
|
|
48
47
|
|
|
48
|
+
const onTransitionEnd = () => {
|
|
49
|
+
console.log("NinePatch move end.")
|
|
50
|
+
}
|
|
51
|
+
|
|
49
52
|
onMounted(() => {
|
|
50
53
|
focusHub.setFocus("myWidget");
|
|
51
54
|
});
|
|
@@ -97,6 +100,7 @@ onMounted(() => {
|
|
|
97
100
|
:imageDspWidth="81"
|
|
98
101
|
:animTime="0.2"
|
|
99
102
|
:waitForInit="true"
|
|
103
|
+
:onTransitionEnd="onTransitionEnd"
|
|
100
104
|
></jsv-nine-patch>
|
|
101
105
|
</div>
|
|
102
106
|
</template>
|
package/NinePatchDemo/Item.vue
CHANGED
|
@@ -17,7 +17,7 @@ const divRef = ref(null);
|
|
|
17
17
|
const onFocus = () => {
|
|
18
18
|
focused.value = true;
|
|
19
19
|
if (focusSize) {
|
|
20
|
-
divRef.value?.
|
|
20
|
+
divRef.value?.jsvGetBoundingClientRect().then(
|
|
21
21
|
(data) => {
|
|
22
22
|
focusSize.width = data.width;
|
|
23
23
|
focusSize.height = data.height;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { JsvNativeSharedDiv, JsvFocusBlock, jJsvRuntimeBridge, enableNativeViewListener, disableNativeViewListener } from "jsview"
|
|
3
|
+
import { onBeforeUnmount, onMounted, reactive } from 'vue';
|
|
4
|
+
|
|
5
|
+
let state = reactive({
|
|
6
|
+
outX: 20,
|
|
7
|
+
outY: 30,
|
|
8
|
+
inX: 13,
|
|
9
|
+
inY: 15,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
let _TestData = [
|
|
13
|
+
[20, 30, 13, 15],
|
|
14
|
+
[30, 40, 13, 15],
|
|
15
|
+
[40, 50, 3, 5], // 绝对位置不动,不触发信息更新
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
let _Index = 0;
|
|
19
|
+
|
|
20
|
+
// 每2秒进行位置变化以测试位置信息更新
|
|
21
|
+
let loopTimer = setInterval(() => {
|
|
22
|
+
_Index = (_Index + 1) % 3;
|
|
23
|
+
|
|
24
|
+
state.outX = _TestData[_Index][0];
|
|
25
|
+
state.outY = _TestData[_Index][1];
|
|
26
|
+
state.inX = _TestData[_Index][2];
|
|
27
|
+
state.inY = _TestData[_Index][3];
|
|
28
|
+
}, 2000);
|
|
29
|
+
|
|
30
|
+
// 使用两个View来测试Id跟踪的正确性
|
|
31
|
+
let _ReisterId = null;
|
|
32
|
+
let _ReisterId2 = null;
|
|
33
|
+
let _ResiterCallbackId1 = -1;
|
|
34
|
+
let _ResiterCallbackId2 = -1;
|
|
35
|
+
|
|
36
|
+
let getId = (id) => {
|
|
37
|
+
if (_ReisterId !== id) {
|
|
38
|
+
_ResiterCallbackId1 = enableNativeViewListener(id);
|
|
39
|
+
_ReisterId = id;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
let timeout1 = -1;
|
|
44
|
+
let timeout2 = -1;
|
|
45
|
+
|
|
46
|
+
let getId2 = (id) => {
|
|
47
|
+
if (_ReisterId2 !== id) {
|
|
48
|
+
_ReisterId2 = id;
|
|
49
|
+
|
|
50
|
+
// 延迟注册,以测试listener注册前发送event的场景
|
|
51
|
+
// 提前发出的event在listener注册时,可以收到最后状态信息
|
|
52
|
+
timeout1 = setTimeout(() => {
|
|
53
|
+
timeout1 = -1;
|
|
54
|
+
_ResiterCallbackId2 = enableNativeViewListener(id);
|
|
55
|
+
timeout2 = setTimeout(() => {
|
|
56
|
+
timeout2 = -1;
|
|
57
|
+
disableNativeViewListener(_ResiterCallbackId2);
|
|
58
|
+
_ResiterCallbackId2 = -1;
|
|
59
|
+
}, 10000);
|
|
60
|
+
}, 1000);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
onBeforeUnmount(()=>{
|
|
65
|
+
if (loopTimer >= 0) {
|
|
66
|
+
clearInterval(loopTimer);
|
|
67
|
+
loopTimer = -1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (timeout1 >= 0) {
|
|
71
|
+
clearTimeout(timeout1);
|
|
72
|
+
timeout1 = -1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (timeout2 >= 0) {
|
|
76
|
+
clearTimeout(timeout2);
|
|
77
|
+
timeout2 = -1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (_ResiterCallbackId1 >= 0) {
|
|
81
|
+
disableNativeViewListener(_ResiterCallbackId1);
|
|
82
|
+
_ResiterCallbackId1 = -1;
|
|
83
|
+
}
|
|
84
|
+
if (_ResiterCallbackId2 >= 0) {
|
|
85
|
+
disableNativeViewListener(_ResiterCallbackId2);
|
|
86
|
+
_ResiterCallbackId2 = -1;
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
onMounted(()=>{
|
|
91
|
+
console.log("TestNativeSharedView mounted");
|
|
92
|
+
jJsvRuntimeBridge.notifyPageLoaded();
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
</script>
|
|
96
|
+
|
|
97
|
+
<template>
|
|
98
|
+
<jsv-focus-block
|
|
99
|
+
autoFocus
|
|
100
|
+
>
|
|
101
|
+
<!-- 一个无限动画元素,来测试卡顿 -->
|
|
102
|
+
<div
|
|
103
|
+
:style="{
|
|
104
|
+
top: 100,
|
|
105
|
+
left: 1000,
|
|
106
|
+
height: 150,
|
|
107
|
+
width: 150,
|
|
108
|
+
backgroundColor: '#334455',
|
|
109
|
+
animation: 'test-anim-rotate 1s infinite linear',
|
|
110
|
+
}"
|
|
111
|
+
/>
|
|
112
|
+
<div
|
|
113
|
+
:style="{
|
|
114
|
+
left: state.outX,
|
|
115
|
+
top: state.outY,
|
|
116
|
+
backgroundColor: '#00FF00',
|
|
117
|
+
width: 600,
|
|
118
|
+
height: 600,
|
|
119
|
+
}"
|
|
120
|
+
>
|
|
121
|
+
<jsv-native-shared-div
|
|
122
|
+
:getId="getId"
|
|
123
|
+
:style="{
|
|
124
|
+
left: state.inX,
|
|
125
|
+
top: state.inY,
|
|
126
|
+
width: 500,
|
|
127
|
+
height: 500,
|
|
128
|
+
}"
|
|
129
|
+
>
|
|
130
|
+
<div
|
|
131
|
+
:style="{
|
|
132
|
+
backgroundColor: '#00FF00',
|
|
133
|
+
left: 50,
|
|
134
|
+
top: 40,
|
|
135
|
+
width: 30,
|
|
136
|
+
height: 30,
|
|
137
|
+
}"
|
|
138
|
+
/>
|
|
139
|
+
</jsv-native-shared-div>
|
|
140
|
+
</div>
|
|
141
|
+
<div
|
|
142
|
+
:style="{
|
|
143
|
+
left: state.outX + 200,
|
|
144
|
+
top: state.outY,
|
|
145
|
+
backgroundColor: '#00FF00',
|
|
146
|
+
width: 600,
|
|
147
|
+
height: 600,
|
|
148
|
+
}"
|
|
149
|
+
>
|
|
150
|
+
<jsv-native-shared-div
|
|
151
|
+
:getId="getId2"
|
|
152
|
+
:style="{
|
|
153
|
+
left: state.inX,
|
|
154
|
+
top: state.inY,
|
|
155
|
+
width: 500,
|
|
156
|
+
height: 500,
|
|
157
|
+
}"
|
|
158
|
+
>
|
|
159
|
+
<div
|
|
160
|
+
:style="{
|
|
161
|
+
backgroundColor: '#00FF00',
|
|
162
|
+
left: 50,
|
|
163
|
+
top: 40,
|
|
164
|
+
width: 30,
|
|
165
|
+
height: 30,
|
|
166
|
+
}"
|
|
167
|
+
/>
|
|
168
|
+
</jsv-native-shared-div>
|
|
169
|
+
</div>
|
|
170
|
+
</jsv-focus-block>
|
|
171
|
+
</template>
|
|
172
|
+
|
|
173
|
+
<style scoped>
|
|
174
|
+
@keyframes test-anim-rotate {
|
|
175
|
+
from {
|
|
176
|
+
transform: rotate3d(0, 0, 1, 270deg);
|
|
177
|
+
}
|
|
178
|
+
to {
|
|
179
|
+
transform: rotate3d(0, 0, 1, 0deg);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
</style>
|