feat(工具箱): 完善“原神时钟”的交互逻辑
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
'clock-rotation': clockState.isRotation,
|
'clock-rotation': clockState.isRotation,
|
||||||
}"
|
}"
|
||||||
:style="elStyle"
|
:style="elStyle"
|
||||||
|
@touchmove.prevent
|
||||||
>
|
>
|
||||||
|
|
||||||
<!-- 外部 -->
|
<!-- 外部 -->
|
||||||
@@ -43,7 +44,7 @@
|
|||||||
<div class="pointer-wrapper pointer-upper bg-contain">
|
<div class="pointer-wrapper pointer-upper bg-contain">
|
||||||
<div
|
<div
|
||||||
class="pointer-content"
|
class="pointer-content"
|
||||||
@mousedown="handleDragPointer('upper')"
|
@pointerdown="handleDragPointer('upper')"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -71,6 +72,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 遮罩层,用于阻止操作 -->
|
||||||
|
<div v-show="isAutoRotating" class="clock-mask"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -79,6 +83,7 @@ import {
|
|||||||
computed,
|
computed,
|
||||||
onBeforeUnmount, onMounted,
|
onBeforeUnmount, onMounted,
|
||||||
reactive, ref,
|
reactive, ref,
|
||||||
|
watch,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -96,6 +101,10 @@ import {
|
|||||||
IMAGE_TIME_ICON_MORNING,
|
IMAGE_TIME_ICON_MORNING,
|
||||||
IMAGE_TIME_ICON_NIGHT,
|
IMAGE_TIME_ICON_NIGHT,
|
||||||
IMAGE_TIME_ICON_NOON,
|
IMAGE_TIME_ICON_NOON,
|
||||||
|
isAutoRotating, isTimeExceeded, isTimeTooEarly,
|
||||||
|
timeCurrHour, timeCurrMinute,
|
||||||
|
timeDiffLabel, timeDiffLabelStill,
|
||||||
|
timeNewHour, timeNewMinute,
|
||||||
} from './common-data';
|
} from './common-data';
|
||||||
|
|
||||||
import ClockColor from './ClockColor.vue';
|
import ClockColor from './ClockColor.vue';
|
||||||
@@ -138,6 +147,8 @@ const upperPointer = reactive({
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.upperPointer = upperPointer;
|
||||||
|
|
||||||
/** 元素 CSS */
|
/** 元素 CSS */
|
||||||
const elStyle = computed(() => {
|
const elStyle = computed(() => {
|
||||||
return {
|
return {
|
||||||
@@ -217,7 +228,11 @@ function handleDragPointer() {
|
|||||||
// 节流
|
// 节流
|
||||||
let last = 0;
|
let last = 0;
|
||||||
|
|
||||||
document.onmousemove = function (ev) {
|
/**
|
||||||
|
* @description 处理光标移动
|
||||||
|
* @param {PointerEvent} ev
|
||||||
|
*/
|
||||||
|
let handleMove = function (ev) {
|
||||||
|
|
||||||
let curr = Date.now();
|
let curr = Date.now();
|
||||||
|
|
||||||
@@ -283,10 +298,10 @@ function handleDragPointer() {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
document.onmouseup = function () {
|
window.addEventListener('pointermove', handleMove);
|
||||||
document.onmousemove = null;
|
window.addEventListener('pointerup', function () {
|
||||||
document.onmouseup = null;
|
window.removeEventListener('pointermove', handleMove);
|
||||||
};
|
}, { once: true });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,6 +319,8 @@ function handleSubmitTime() {
|
|||||||
// 结束
|
// 结束
|
||||||
if (upperAngleCurr === 0) {
|
if (upperAngleCurr === 0) {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
|
isAutoRotating.value = false;
|
||||||
|
timeDiffLabelStill.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let upperAngleDiff = upperAngleStart - upperAngleCurr;
|
let upperAngleDiff = upperAngleStart - upperAngleCurr;
|
||||||
@@ -315,12 +332,87 @@ function handleSubmitTime() {
|
|||||||
|
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
|
/** 更新状态 */
|
||||||
|
isAutoRotating.value = true;
|
||||||
|
|
||||||
|
// 固定时间差文本
|
||||||
|
timeDiffLabelStill.value = timeDiffLabel.value;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
handleSubmitTime,
|
handleSubmitTime,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 检测角度变化,计算时间信息(自动旋转时)
|
||||||
|
watch(() => {
|
||||||
|
return lowerPointer.viewAngle;
|
||||||
|
}, (viewAngle) => {
|
||||||
|
|
||||||
|
// 转换为对应 24 小时的角度
|
||||||
|
let timeAngle = viewAngle + (viewAngle < 180 ? 180 : -180);
|
||||||
|
let timeValue = timeAngle / 15;
|
||||||
|
let currHour = Math.floor(timeValue);
|
||||||
|
let currMinute = Math.round((timeValue - currHour) * 60);
|
||||||
|
|
||||||
|
// 计算时间值
|
||||||
|
timeCurrHour.value = String(currHour).padStart(2, '0');
|
||||||
|
timeCurrMinute.value = String(currMinute).padStart(2, '0');
|
||||||
|
|
||||||
|
}, { immediate: true });
|
||||||
|
|
||||||
|
// 检测角度变化,计算时间信息(用户操作时)
|
||||||
|
watch(() => {
|
||||||
|
return upperPointer.dataAngle;
|
||||||
|
}, (dataAngle) => {
|
||||||
|
|
||||||
|
// 注:15° / 小时
|
||||||
|
|
||||||
|
let isSecond = upperPointer.isSecond;
|
||||||
|
let currAngle = lowerPointer.viewAngle;
|
||||||
|
let viewAngle = upperPointer.viewAngle;
|
||||||
|
|
||||||
|
let diffAngle = dataAngle + (isSecond ? 360 : 0);
|
||||||
|
let diffAngle1 = 0; // +1 日角度差
|
||||||
|
let diffAngle2 = 0; // +2 日角度差
|
||||||
|
let diffLabel = '';
|
||||||
|
|
||||||
|
// 转换为对应 24 小时的角度
|
||||||
|
let timeAngle = viewAngle + (viewAngle < 180 ? 180 : -180);
|
||||||
|
let timeValue = timeAngle / 15;
|
||||||
|
let newHour = Math.floor(timeValue);
|
||||||
|
let newMinute = Math.round((timeValue - newHour) * 60);
|
||||||
|
|
||||||
|
if (currAngle < 180) {
|
||||||
|
diffAngle1 = 180 - currAngle;
|
||||||
|
diffAngle2 = diffAngle1 + 360;
|
||||||
|
} else {
|
||||||
|
diffAngle1 = 540 - currAngle; // 360 + 180
|
||||||
|
diffAngle2 = diffAngle1 + 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理时间差信息
|
||||||
|
if (diffAngle < diffAngle1) {
|
||||||
|
diffLabel = '今日';
|
||||||
|
} else if (diffAngle < diffAngle2) {
|
||||||
|
diffLabel = '次日';
|
||||||
|
} else {
|
||||||
|
diffLabel = '+2日';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理提示信息显示
|
||||||
|
isTimeTooEarly.value = diffAngle < 7.5;
|
||||||
|
isTimeExceeded.value = diffAngle === 720;
|
||||||
|
|
||||||
|
// 更新时间差信息
|
||||||
|
timeDiffLabel.value = diffLabel;
|
||||||
|
|
||||||
|
// 计算时间值
|
||||||
|
timeNewHour.value = String(newHour).padStart(2, '0');
|
||||||
|
timeNewMinute.value = String(newMinute).padStart(2, '0');
|
||||||
|
|
||||||
|
}, { immediate: true });
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
timerInit();
|
timerInit();
|
||||||
});
|
});
|
||||||
@@ -610,6 +702,16 @@ onBeforeUnmount(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clock-mask {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
cursor: wait;
|
||||||
|
}
|
||||||
|
|
||||||
// 顺时针旋转
|
// 顺时针旋转
|
||||||
@keyframes rotation-forward {
|
@keyframes rotation-forward {
|
||||||
0% {
|
0% {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tool-detail-page">
|
<div class="tool-detail-page has-radius">
|
||||||
|
|
||||||
<!-- 左 -->
|
<!-- 左 -->
|
||||||
<div class="page-column">
|
<div class="page-column">
|
||||||
@@ -13,17 +13,27 @@
|
|||||||
<clock-element ref="clockRef" />
|
<clock-element ref="clockRef" />
|
||||||
|
|
||||||
<!-- 上限提示 -->
|
<!-- 上限提示 -->
|
||||||
<div class="time-notice">
|
<div
|
||||||
|
:class="{
|
||||||
|
'is-hide': isAutoRotating,
|
||||||
|
'time-notice': true,
|
||||||
|
}"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
v-show="true"
|
v-show="isTimeExceeded"
|
||||||
class="time-notice-text"
|
class="time-notice-text"
|
||||||
>时间到达上限</span>
|
>时间到达上限</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 确认时间 -->
|
<!-- 确认时间 -->
|
||||||
<div class="time-submit">
|
<div
|
||||||
|
:class="{
|
||||||
|
'is-hide': isAutoRotating,
|
||||||
|
'time-submit': true,
|
||||||
|
}"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
v-if="false"
|
v-if="isTimeTooEarly"
|
||||||
class="time-notice-text"
|
class="time-notice-text"
|
||||||
>时间少于30分钟</span>
|
>时间少于30分钟</span>
|
||||||
<genshin-button
|
<genshin-button
|
||||||
@@ -44,6 +54,10 @@ import {
|
|||||||
ref,
|
ref,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
|
|
||||||
|
import {
|
||||||
|
isAutoRotating, isTimeTooEarly, isTimeExceeded,
|
||||||
|
} from './common-data';
|
||||||
|
|
||||||
import ClockElement from './ClockElement.vue';
|
import ClockElement from './ClockElement.vue';
|
||||||
import GenshinButton from './GenshinButton.vue';
|
import GenshinButton from './GenshinButton.vue';
|
||||||
import TimeInfo from './TimeInfo.vue';
|
import TimeInfo from './TimeInfo.vue';
|
||||||
@@ -68,7 +82,6 @@ function handleConfirm() {
|
|||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.tool-detail-page {
|
.tool-detail-page {
|
||||||
border-radius: 8px;
|
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -89,9 +102,23 @@ function handleConfirm() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.time-notice {
|
.time-notice, .time-submit {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
transition: opacity 0.25s, visibility 0s 0s;
|
||||||
|
|
||||||
|
// 注:
|
||||||
|
// visibility 动画时长用于等待 opacity 动画过渡完毕
|
||||||
|
&.is-hide {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.25s, visibility 0.25s 0s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-notice {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +129,4 @@ function handleConfirm() {
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.time-submit {
|
|
||||||
display: flex;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@@ -11,7 +11,11 @@
|
|||||||
<div class="time-title time-title-current">当前时间</div>
|
<div class="time-title time-title-current">当前时间</div>
|
||||||
|
|
||||||
<!-- 当前时间值 -->
|
<!-- 当前时间值 -->
|
||||||
<div class="time-value time-value-current">12:00</div>
|
<div class="time-value time-value-current">
|
||||||
|
<span>{{ timeCurrHour }}</span>
|
||||||
|
<span>:</span>
|
||||||
|
<span>{{ timeCurrMinute }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 三角形图标 -->
|
<!-- 三角形图标 -->
|
||||||
<div class="triangle-icon">
|
<div class="triangle-icon">
|
||||||
@@ -27,10 +31,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 目标时间值 -->
|
<!-- 目标时间值 -->
|
||||||
<div class="time-value time-value-target">12:00</div>
|
<div class="time-value time-value-target">
|
||||||
|
<span>{{ timeNewHour }}</span>
|
||||||
|
<span>:</span>
|
||||||
|
<span>{{ timeNewMinute }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 时间差 -->
|
<!-- 时间差 -->
|
||||||
<div class="time-diff">+2日</div>
|
<div class="time-diff">
|
||||||
|
<span>{{ timeDiffLabelStill || timeDiffLabel }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 装饰元素 -->
|
<!-- 装饰元素 -->
|
||||||
<div class="arrow-element"></div>
|
<div class="arrow-element"></div>
|
||||||
@@ -41,6 +51,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
IMAGE_TIME_INFO_ARROW,
|
IMAGE_TIME_INFO_ARROW,
|
||||||
|
timeCurrHour, timeCurrMinute,
|
||||||
|
timeDiffLabel, timeDiffLabelStill,
|
||||||
|
timeNewHour, timeNewMinute,
|
||||||
} from './common-data';
|
} from './common-data';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -66,8 +79,17 @@ import {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.time-diff {
|
.time-diff {
|
||||||
color: #ECE3D6;
|
display: flex;
|
||||||
|
width: 3.5em;
|
||||||
|
height: 1.75em;
|
||||||
|
border-radius: 1.75em;
|
||||||
|
background-color: #282C33;
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.time-title {
|
.time-title {
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
export const IMAGE_BASE = `https://c.frost-zx.top/data/static/image/genshin-impact-clock`;
|
export const IMAGE_BASE = `https://c.frost-zx.top/data/static/image/genshin-impact-clock`;
|
||||||
export const IMAGE_CLOCK_BG_INNER = `url("${IMAGE_BASE}/clock_bg_inner.png")`;
|
export const IMAGE_CLOCK_BG_INNER = `url("${IMAGE_BASE}/clock_bg_inner.png")`;
|
||||||
export const IMAGE_CLOCK_BG_OUTER = `url("${IMAGE_BASE}/clock_bg_outer.png")`;
|
export const IMAGE_CLOCK_BG_OUTER = `url("${IMAGE_BASE}/clock_bg_outer.png")`;
|
||||||
@@ -15,3 +17,30 @@ export const IMAGE_TIME_ICON_NIGHT = `url("${IMAGE_BASE}/time_icon_night.png")`;
|
|||||||
export const IMAGE_TIME_ICON_NOON = `url("${IMAGE_BASE}/time_icon_noon.png")`;
|
export const IMAGE_TIME_ICON_NOON = `url("${IMAGE_BASE}/time_icon_noon.png")`;
|
||||||
export const IMAGE_TIME_INFO_ARROW = `url("${IMAGE_BASE}/time_info_arrow.png")`;
|
export const IMAGE_TIME_INFO_ARROW = `url("${IMAGE_BASE}/time_info_arrow.png")`;
|
||||||
export const IMAGE_TIME_ZONE_COLOR = `${IMAGE_BASE}/time_zone_color.png`;
|
export const IMAGE_TIME_ZONE_COLOR = `${IMAGE_BASE}/time_zone_color.png`;
|
||||||
|
|
||||||
|
/** 是否正在自动旋转 */
|
||||||
|
export const isAutoRotating = ref(false);
|
||||||
|
|
||||||
|
/** 是否时间少于 30 分钟 */
|
||||||
|
export const isTimeTooEarly = ref(false);
|
||||||
|
|
||||||
|
/** 是否时间到达上限 */
|
||||||
|
export const isTimeExceeded = ref(false);
|
||||||
|
|
||||||
|
/** 当前时 */
|
||||||
|
export const timeCurrHour = ref('00');
|
||||||
|
|
||||||
|
/** 当前分 */
|
||||||
|
export const timeCurrMinute = ref('00');
|
||||||
|
|
||||||
|
/** 时间差(动态)*/
|
||||||
|
export const timeDiffLabel = ref('');
|
||||||
|
|
||||||
|
/** 时间差(固定)*/
|
||||||
|
export const timeDiffLabelStill = ref('');
|
||||||
|
|
||||||
|
/** 新的时 */
|
||||||
|
export const timeNewHour = ref('00');
|
||||||
|
|
||||||
|
/** 新的分 */
|
||||||
|
export const timeNewMinute = ref('00');
|
||||||
|
Reference in New Issue
Block a user