完整版
This commit is contained in:
parent
7631aa1cb7
commit
6f377745d2
104
src/App.vue
104
src/App.vue
@ -1,13 +1,9 @@
|
||||
<style scoped>
|
||||
#table {
|
||||
background-color: #beb1a0;
|
||||
width: 350px;
|
||||
height: 350px;
|
||||
position: relative;
|
||||
margin: 10px auto;
|
||||
padding: 0px 0px;
|
||||
border-radius: 10px;
|
||||
border: #857c71 solid 2px;
|
||||
@media (max-width: 400px) or (max-height: 400px) {
|
||||
* {
|
||||
scale: 0.85;
|
||||
transform-origin: center top;
|
||||
}
|
||||
}
|
||||
#first_line,
|
||||
#last_line {
|
||||
@ -15,52 +11,64 @@
|
||||
width: 350px;
|
||||
justify-content: space-between;
|
||||
margin: 0px auto;
|
||||
padding-top: 10px;
|
||||
}
|
||||
#first_line div,
|
||||
#last_line div{
|
||||
margin-top: 8px;
|
||||
#score div {
|
||||
text-align: center;
|
||||
}
|
||||
#score {
|
||||
background-color: #beb1a0;
|
||||
width: 170px;
|
||||
border-radius: 3px;
|
||||
border: #857c71 solid 1px;
|
||||
#table {
|
||||
background-color: #bbada0;
|
||||
width: 390px;
|
||||
height: 390px;
|
||||
position: relative;
|
||||
margin: 10px auto;
|
||||
padding: 0px 0px;
|
||||
border-radius: 10px;
|
||||
border: #857c71 solid 2px;
|
||||
}
|
||||
h1{
|
||||
h1 {
|
||||
margin: 0px;
|
||||
font-weight: bolder;
|
||||
font-size: 300%;
|
||||
}
|
||||
button{
|
||||
button {
|
||||
background-color: #beb1a0;
|
||||
border-radius: 2px;
|
||||
border: #857c71 solid 1px;
|
||||
border: #857c71 solid 2px;
|
||||
color: #736d64;
|
||||
}
|
||||
.fonts{
|
||||
.fonts {
|
||||
color: #736d64;
|
||||
}
|
||||
.font_white{
|
||||
.font_white {
|
||||
color: whitesmoke;
|
||||
}
|
||||
#num{
|
||||
font-size: smaller;
|
||||
#num {
|
||||
font-size: large;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<!-- <check :show="show" :result="result"></check> -->
|
||||
<check :show="show" :result="result" :score="score" :max="max"></check>
|
||||
<div id="first_line" class="fonts">
|
||||
<h1>2048</h1>
|
||||
<div id="score" class="font_white"> </div>
|
||||
<div id="score" class="font_white">
|
||||
<shows name="最高数" :value="max"></shows>
|
||||
<shows name="分数" :value="score"></shows>
|
||||
</div>
|
||||
</div>
|
||||
<div id="last_line" class="fonts">
|
||||
<div id="num">合并数字达到2048</div>
|
||||
<button class="font_white">重新开始游戏</button>
|
||||
<button class="font_white" @click="f5">重新开始游戏</button>
|
||||
</div>
|
||||
<div id="table">
|
||||
<div id="table" ref="tables">
|
||||
<buttom></buttom>
|
||||
<move></move>
|
||||
<move
|
||||
@change-win="changeWin"
|
||||
@change-max="changeMax"
|
||||
@change-score="changeScore"
|
||||
></move>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -68,11 +76,37 @@ button{
|
||||
import buttom from './components/buttom.vue';
|
||||
import move from './components/move.vue';
|
||||
import check from './components/check.vue';
|
||||
import { ref } from 'vue';
|
||||
const show=ref(false);
|
||||
const result=ref("")
|
||||
const chenge=(shows:boolean,results:"胜利"|"失败")=>{
|
||||
show.value=shows;
|
||||
result.value=results;
|
||||
import shows from './components/shows.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import gsap from 'gsap';
|
||||
const f5=()=>{
|
||||
location.replace(location.href)
|
||||
}
|
||||
const show = ref(false); //check
|
||||
const result = ref(''); //check
|
||||
const score = ref(0);
|
||||
const max = ref(0);
|
||||
const changeWin = (shows: boolean, results: '胜利' | '失败') => {
|
||||
//move
|
||||
show.value = shows;
|
||||
result.value = results;
|
||||
};
|
||||
const changeScore = (newScore: number) => {
|
||||
score.value = newScore;
|
||||
};
|
||||
const changeMax = (newMax: number) => {
|
||||
max.value = newMax;
|
||||
};
|
||||
const tables=ref<HTMLElement>()
|
||||
onMounted(()=>{
|
||||
gsap.fromTo(tables.value!,{
|
||||
opacity:0.3,
|
||||
scale:0.8
|
||||
},{
|
||||
ease:"power1.out",
|
||||
duration:0.8,
|
||||
opacity:1,
|
||||
scale:1
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
@ -1,3 +1,5 @@
|
||||
body{
|
||||
background-color: #fcf6e3;
|
||||
background-color: #f3f0e5;
|
||||
width: 100vw;
|
||||
height: 100vh;padding: 0;margin: 0;
|
||||
}
|
@ -1,61 +1,73 @@
|
||||
<style scoped>
|
||||
@media (max-width:400px) or (max-height:400px) {
|
||||
*{
|
||||
scale: 0.85;
|
||||
transform-origin: center top;
|
||||
}
|
||||
}
|
||||
.buttom {
|
||||
background-color: #cec0b3;
|
||||
background-color: #cdc1b4;
|
||||
position: absolute;
|
||||
padding: 0px 0px;
|
||||
border: #857c71 solid 2px;
|
||||
border-radius: 7px;
|
||||
border-radius: 3px;
|
||||
z-index: 0;
|
||||
scale: 0;
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
scale: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<transition-group :css="false" name="div" @enter="enter" tag="div" >
|
||||
<div
|
||||
v-for="obj in arr"
|
||||
key="obj"
|
||||
class="buttom"
|
||||
v-show="obj.show"
|
||||
:style="{ top: `${obj.y * 85 + 10}px`, left: `${obj.x * 85 + 10}px` }"
|
||||
></div>
|
||||
</transition-group>
|
||||
<div v-for="obj in arr" ref="block" class="buttom"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useEventListener } from '@vueuse/core';
|
||||
import gsap from 'gsap';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import timmer from '../ts/my_ts_pack';
|
||||
type GSAPTweenTarget = string | Element | Element[] | object;
|
||||
const arr = ref(
|
||||
Array.from(Array(16), (_, index) => ({
|
||||
show: false,
|
||||
x: index % 4,
|
||||
y: Math.floor(index / 4),
|
||||
}))
|
||||
);
|
||||
const enter = (vDom: gsap.TweenTarget, done: () => void) => {
|
||||
gsap.to(vDom, {
|
||||
scale:1,
|
||||
duration:1.2,
|
||||
ease: "back.out(1.5)",
|
||||
onComplete:done
|
||||
});
|
||||
};
|
||||
onMounted(() => {
|
||||
useEventListener(window, 'load', async () => {
|
||||
for (let i = 0; i <= 7; i++) {
|
||||
await timmer(120);
|
||||
for (let j = 0; j <= i; j++) {
|
||||
const y = j;
|
||||
const x = i - j;
|
||||
if (arr.value[y * 4 + x]!=undefined)
|
||||
arr.value[y * 4 + x].show = true;
|
||||
const block = ref<HTMLElement[]>([]);
|
||||
const arr = Array.from({ length: 16 }, (_, index) => ({
|
||||
id: index,
|
||||
x: index % 4,
|
||||
y: Math.floor(index / 4),
|
||||
show(delay: number) {
|
||||
const self = block.value[this.id];
|
||||
const deltaX = this.x <= 1 ? 37 : -37;
|
||||
const deltaY = this.y <= 1 ? 37 : -37;
|
||||
gsap.fromTo(
|
||||
self,
|
||||
{
|
||||
x: this.x * 95 + 12 + deltaX,
|
||||
y: this.y * 95 + 12 + deltaY,
|
||||
opacity:-0.5,
|
||||
scale: 0,
|
||||
},
|
||||
{
|
||||
ease: "power1.out",
|
||||
x: this.x * 95 + 12,
|
||||
y: this.y * 95 + 12,
|
||||
opacity:1,
|
||||
scale: 1,
|
||||
duration: 0.8,
|
||||
delay: delay,
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
);
|
||||
},
|
||||
}));
|
||||
const animate = [
|
||||
[5, 6, 9, 10],
|
||||
[1, 2, 4, 8, 13, 14, 7, 11],
|
||||
[0, 3, 12, 15],
|
||||
];
|
||||
const main = () => {
|
||||
animate.forEach((arrs, delay) => {
|
||||
arrs.forEach((index) => {
|
||||
arr[index].show(delay * 0.17+0.3);
|
||||
});
|
||||
});
|
||||
};
|
||||
onMounted(main);
|
||||
</script>
|
||||
|
@ -1,33 +1,44 @@
|
||||
<style scoped>
|
||||
@media (max-width: 400px) or (max-height: 400px) {
|
||||
* {
|
||||
transform-origin: center top;
|
||||
}
|
||||
#white {
|
||||
scale: 3;
|
||||
}
|
||||
}
|
||||
* {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
z-index: 30;
|
||||
color: rgba(255, 255, 255, 0.65);
|
||||
font-size: 200%;
|
||||
}
|
||||
#white {
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(125, 125, 125, 0.6);
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
#win {
|
||||
font-family: '楷体';
|
||||
font-size: 500%;
|
||||
top:10%;
|
||||
top: 10%;
|
||||
}
|
||||
#time{
|
||||
top: 50%;
|
||||
#time {
|
||||
top: 55%;
|
||||
}
|
||||
#tick{
|
||||
top:53%
|
||||
#tick {
|
||||
top: 63%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<Transition @enter="obj.white.animate">
|
||||
<div id="white" v-show="obj.white.show"> </div>
|
||||
<div id="white" v-if="obj.white.show"> </div>
|
||||
</Transition>
|
||||
<Transition @enter="obj.win.animate">
|
||||
<div id="win" v-show="obj.white.show">
|
||||
@ -35,22 +46,32 @@
|
||||
</div>
|
||||
</Transition>
|
||||
<Transition @enter="obj.time.animate">
|
||||
<div id="time" v-show="obj.white.show">时间:(还未做),分数:(还未做)</div>
|
||||
<div id="time" v-show="obj.white.show">
|
||||
最高数:{{ Math.floor(max.value) }}, 分数:{{ Math.floor(score.value) }}
|
||||
</div>
|
||||
</Transition>
|
||||
<Transition @enter="obj.tick.animate">
|
||||
<div id="tick" v-show="obj.white.show">单击任意一处即可继续游戏</div>
|
||||
<div id="tick" v-show="obj.white.show" @click="f5">
|
||||
单击此处即可重新开始游戏
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, Transition, watch } from 'vue';
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import timmer from '../ts/my_ts_pack';
|
||||
import gsap from 'gsap';
|
||||
|
||||
const f5 = () => {
|
||||
location.replace(location.href);
|
||||
};
|
||||
const max = reactive({ value: 0 }),
|
||||
score = reactive({ value: 0 });
|
||||
type GSAPTweenTarget = string | Element | Element[] | object;
|
||||
const props = defineProps<{
|
||||
result: string;
|
||||
show: boolean;
|
||||
score: number;
|
||||
max: number;
|
||||
}>();
|
||||
const obj = reactive({
|
||||
white: {
|
||||
@ -70,7 +91,7 @@ const obj = reactive({
|
||||
opacity: 0,
|
||||
duration: 2,
|
||||
y: -1000,
|
||||
ease: "bounce.out",
|
||||
ease: 'bounce.out',
|
||||
onComplete: done,
|
||||
});
|
||||
},
|
||||
@ -81,9 +102,19 @@ const obj = reactive({
|
||||
gsap.from(vDom, {
|
||||
opacity: 0,
|
||||
y: window.innerHeight,
|
||||
duration: 1,
|
||||
duration: 0.7,
|
||||
onComplete: done,
|
||||
});
|
||||
gsap.to(max, {
|
||||
duration: 2.3,
|
||||
ease: 'power1.out',
|
||||
value: props.max,
|
||||
});
|
||||
gsap.to(score, {
|
||||
duration: 2.3,
|
||||
ease: 'power1.out',
|
||||
value: props.score,
|
||||
});
|
||||
},
|
||||
},
|
||||
tick: {
|
||||
@ -92,7 +123,7 @@ const obj = reactive({
|
||||
gsap.from(vDom, {
|
||||
opacity: 0,
|
||||
duration: 4,
|
||||
ease:"power4.in",
|
||||
ease: 'power4.in',
|
||||
onComplete: done,
|
||||
});
|
||||
},
|
||||
|
@ -1,18 +1,30 @@
|
||||
<style scoped>
|
||||
@media (max-width:400px) or (max-height:400px) {
|
||||
*{
|
||||
scale: 0.85;
|
||||
transform-origin: center top;
|
||||
}
|
||||
}
|
||||
.move {
|
||||
z-index: 10;
|
||||
color: #736d64;
|
||||
color: #776e65;
|
||||
font-weight: bolder;
|
||||
font-size: large;
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
line-height: 74px;
|
||||
background-color: #efe0c9;
|
||||
width: 74px;
|
||||
height: 74px;
|
||||
line-height: 80px;
|
||||
background-color: #eee4da;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
position: absolute;
|
||||
margin: 0px 0px;
|
||||
padding: 0px 0px;
|
||||
border-radius: 7px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.move[data-length='4'] {
|
||||
font-size: 15px;
|
||||
}
|
||||
.move[data='T'] {
|
||||
color: #f3f0e5;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
@ -22,16 +34,37 @@
|
||||
v-for="dom in block"
|
||||
v-show="dom.value"
|
||||
:style="{ zIndex: dom.merge === true ? 10 : 0 }"
|
||||
:data-length="String(dom.value).length"
|
||||
:data="dom.value >= 8 ? 'T' : 'F'"
|
||||
>
|
||||
{{ dom.value }}
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue';
|
||||
import gsap from 'gsap';
|
||||
import timmer from '../ts/my_ts_pack';
|
||||
import { useEventListener } from '@vueuse/core';
|
||||
const scores=reactive({
|
||||
max:0,
|
||||
score:0
|
||||
})
|
||||
let score=0
|
||||
const emits= defineEmits(["changeWin","changeScore","changeMax"])
|
||||
const blockes = ref<HTMLElement[]>([]);
|
||||
const colorMap = new Map([
|
||||
[2, 'rgb(238, 228, 218)'],
|
||||
[4, 'rgb(237, 224, 200)'],
|
||||
[8, 'rgb(242, 177, 121)'],
|
||||
[16, 'rgb(242, 177, 121)'],
|
||||
[32, 'rgb(246, 124, 95)]'],
|
||||
[64, 'rgb(246, 94, 59)'],
|
||||
[128, 'rgb(237, 207, 114)'],
|
||||
[256, 'rgb(237, 204, 97)'],
|
||||
[512, 'rgb(237, 200, 80)'],
|
||||
[1024, 'rgb(237, 197, 63)'],
|
||||
[2048, 'rgb(237, 194, 46)'],
|
||||
]);
|
||||
const color = (value: number) => colorMap.get(value);
|
||||
class Block {
|
||||
constructor(
|
||||
public index: number,
|
||||
@ -39,21 +72,20 @@ class Block {
|
||||
public to = { x: -1, y: -1 },
|
||||
public value = 0,
|
||||
public digitalValue = 0,
|
||||
public endValue = 0,
|
||||
public merge = false as boolean | Block,
|
||||
public create = false
|
||||
) {}
|
||||
get positionForm() {
|
||||
return {
|
||||
x: this.from.x * 85 + 12,
|
||||
y: this.from.y * 85 + 12,
|
||||
x: this.from.x * 95 + 13,
|
||||
y: this.from.y * 95 + 13,
|
||||
};
|
||||
}
|
||||
get positionTo() {
|
||||
return {
|
||||
x: this.to.x * 85 + 12,
|
||||
y: this.to.y * 85 + 12,
|
||||
duration: 0.5, //时间
|
||||
x: this.to.x * 95 + 13,
|
||||
y: this.to.y * 95 + 13,
|
||||
duration: 0.15, //时间
|
||||
};
|
||||
}
|
||||
digitalMove(deltaY: number, deltaX: number) {
|
||||
@ -65,33 +97,42 @@ class Block {
|
||||
return;
|
||||
}
|
||||
if (target.digitalValue == this.digitalValue) {
|
||||
if (this.merge == false) {
|
||||
if (this.merge === false && target.merge === false) {
|
||||
this.merge = target;
|
||||
this.digitalValue = this.endValue = 0;
|
||||
this.digitalValue = 0;
|
||||
target.merge = true;
|
||||
target.digitalValue *= 2;
|
||||
target.endValue *= 2;
|
||||
score+=target.digitalValue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
allAnimation() {
|
||||
const self = blockes.value[this.index];
|
||||
const timeLine=gsap.timeline()
|
||||
gsap.set(self, { backgroundColor: color(this.value) });
|
||||
const timeLine = gsap.timeline();
|
||||
timeLine.add(gsap.set(self, { scale: 1 }));
|
||||
timeLine.add(gsap.fromTo(self, this.positionForm, this.positionTo), '<');
|
||||
if (this.merge == true) {
|
||||
this.value *= 2;
|
||||
const self = blockes.value[this.index];
|
||||
timeLine.add(gsap.to(self, { scale: 1.1, duration: 0.2 }));
|
||||
timeLine.add(gsap.to(self, { scale: 1, duration: 0.2 }));
|
||||
timeLine.add(
|
||||
gsap.to(self, {
|
||||
scale: 1.1,
|
||||
duration: 0.1,
|
||||
onStart: () => {
|
||||
this.value = this.digitalValue;
|
||||
gsap.set(self, { backgroundColor: color(this.value) });
|
||||
},
|
||||
})
|
||||
);
|
||||
timeLine.add(gsap.to(self, { scale: 1, duration: 0.1 }));
|
||||
}
|
||||
if (typeof this.merge == 'object') {
|
||||
this.merge = false;
|
||||
}
|
||||
if (this.create) {
|
||||
this.create = false;
|
||||
gsap.from(self, { scale: 0, duration: 0.3 ,delay:0.1});
|
||||
timeLine.add(gsap.from(self, { scale: 0, duration: 0.2 }));
|
||||
gsap.to(self, { backgroundColor: color(this.value) });
|
||||
}
|
||||
}
|
||||
syncing(target: 'from&to' | 'merge&xy') {
|
||||
@ -111,11 +152,30 @@ class Block {
|
||||
if (table.value[newY][newX] === null) {
|
||||
this.from.x = this.to.x = newX;
|
||||
this.from.y = this.to.y = newY;
|
||||
this.digitalValue = this.value = this.endValue = 2;
|
||||
this.digitalValue = this.value = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
checkWoring() {
|
||||
if (!this.digitalValue) return false;
|
||||
const arr = [
|
||||
[0, -1],
|
||||
[0, 1],
|
||||
[-1, 0],
|
||||
[1, 0],
|
||||
];
|
||||
for (const [x, y] of arr) {
|
||||
const target = table.value[this.to.y + y]?.[this.to.x + x];
|
||||
if (target?.value == this.value&&target!=undefined)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
checkWin(){
|
||||
if(this.digitalValue) return true;
|
||||
return false
|
||||
}
|
||||
}
|
||||
const block = reactive(
|
||||
Array.from({ length: 16 }, (_, index) => new Block(index))
|
||||
@ -131,7 +191,9 @@ const table = computed<(Block | null)[][]>(() => {
|
||||
return result;
|
||||
});
|
||||
const controller = async (e: KeyboardEvent) => {
|
||||
let createFlag = true;
|
||||
let createFlag = true,
|
||||
woringFlag = true,
|
||||
winFlag=false;
|
||||
switch (e.key) {
|
||||
case 'ArrowUp':
|
||||
case 'ArrowDown':
|
||||
@ -139,10 +201,10 @@ const controller = async (e: KeyboardEvent) => {
|
||||
case 'ArrowRight':
|
||||
block.forEach((element) => {
|
||||
element.syncing('from&to');
|
||||
const result = element.endValue;
|
||||
element.value = element.digitalValue = result;
|
||||
element.value = element.digitalValue;
|
||||
element.create = element.merge = false;
|
||||
});
|
||||
break;
|
||||
}
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
switch (e.key) {
|
||||
@ -170,17 +232,36 @@ const controller = async (e: KeyboardEvent) => {
|
||||
createFlag = false;
|
||||
}
|
||||
}
|
||||
block.forEach((element) => {
|
||||
if (!element.value && createFlag) {
|
||||
element.digitalCreate();
|
||||
createFlag = false;
|
||||
element.create=true;
|
||||
if (createFlag){
|
||||
let max=0;
|
||||
block.forEach((element) => {
|
||||
if (!element.value&&createFlag) {
|
||||
element.digitalCreate();
|
||||
createFlag = false;
|
||||
element.create = true;
|
||||
}
|
||||
element.syncing('merge&xy');
|
||||
element.allAnimation();
|
||||
element.create = false;
|
||||
if (!element.checkWoring()) woringFlag = false;
|
||||
if(element.checkWin()) winFlag =false;
|
||||
if(element.digitalValue>max) max=element.digitalValue
|
||||
});
|
||||
scores.max=max
|
||||
scores.score=score
|
||||
if(winFlag){
|
||||
emits("changeWin",true,"胜利")
|
||||
}else if(woringFlag){
|
||||
emits("changeWin",true,"失败")
|
||||
}
|
||||
element.syncing('merge&xy');
|
||||
element.allAnimation();
|
||||
element.create=false;
|
||||
});
|
||||
}
|
||||
};
|
||||
watch(()=>scores.score,(newValue)=>{
|
||||
emits("changeScore",newValue)
|
||||
})
|
||||
watch(()=>scores.max,(newValue)=>{
|
||||
emits("changeMax",newValue)
|
||||
})
|
||||
onMounted(() => {
|
||||
useEventListener(window, 'keydown', controller);
|
||||
});
|
||||
|
45
src/components/shows.vue
Normal file
45
src/components/shows.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<style scoped>
|
||||
#sd div {
|
||||
background-color: #beb1a0;
|
||||
width: 80px;
|
||||
height: 50%;
|
||||
font-size: large;
|
||||
}
|
||||
#sd {
|
||||
margin-top: 10px;
|
||||
margin-left: 10px;
|
||||
float: right;
|
||||
border: #857c71 solid 2px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div id="sd">
|
||||
<div>{{ props.name }}</div>
|
||||
<div ref="value">{{ Math.floor(num.value) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import gsap from 'gsap';
|
||||
const value = ref<HTMLElement>();
|
||||
const props = defineProps<{
|
||||
name: string;
|
||||
value: number;
|
||||
}>();
|
||||
let num = reactive({
|
||||
value:0
|
||||
})
|
||||
watch(
|
||||
() => props.value,
|
||||
(newValue) => {
|
||||
gsap.to(num, {
|
||||
value: newValue,
|
||||
ease: 'power1.out',
|
||||
duration: 0.7,
|
||||
});
|
||||
}
|
||||
);
|
||||
</script>
|
Loading…
x
Reference in New Issue
Block a user