Skip to content

Commit

Permalink
优化页面动画
Browse files Browse the repository at this point in the history
  • Loading branch information
hyperzlib committed Nov 17, 2024
1 parent f999759 commit 70020d6
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 152 deletions.
71 changes: 0 additions & 71 deletions frontend/src/components/partials/StrengthSettings.vue

This file was deleted.

67 changes: 45 additions & 22 deletions frontend/src/components/transitions/FadeAndSlideTransitionGroup.vue
Original file line number Diff line number Diff line change
@@ -1,47 +1,70 @@
<script lang="ts" setup>
import { TransitionGroup } from 'vue';
defineOptions({
name: 'FadeAndSlideTransitionGroup',
name: 'FadeAndSlideTransitionGroup',
});
const transitionRef = ref<any | null>(null);
const onEnter = (el: Element, done: () => void) => {
const transitionContainer = transitionRef.value!.$el as HTMLElement;
console.log('onEnter', el, transitionContainer);
let prevHeight = el.clientHeight;
transitionContainer.style.height = `${prevHeight}px`;
setTimeout(() => {
transitionContainer.style.height = '';
}, 300);
console.log('onEnter');
const transitionContainer = transitionRef.value!.$el as HTMLElement;
const transitionEl = el as HTMLElement;
let prevHeight = el.clientHeight;
transitionContainer.style.height = `${prevHeight}px`;
transitionEl.style.visibility = 'hidden';
let timer = setInterval(() => {
const height = el.clientHeight;
if (height !== prevHeight) {
transitionContainer.style.height = `${height}px`;
prevHeight = height;
}
}, 100);
setTimeout(() => {
// 与onLeave的duration保持一致
transitionEl.style.visibility = '';
transitionContainer.style.opacity = '1';
}, 150);
setTimeout(() => {
clearInterval(timer);
transitionContainer.style.height = '';
transitionContainer.style.opacity = '';
done();
}, 400);
};
const onLeave = (el: Element, done: () => void) => {
const transitionContainer = transitionRef.value!.$el as HTMLElement;
const height = el.clientHeight;
transitionContainer.style.height = `${height}px`;
console.log('onLeave');
const transitionContainer = transitionRef.value!.$el as HTMLElement;
const height = el.clientHeight;
transitionContainer.style.height = `${height}px`;
transitionContainer.style.opacity = '0';
setTimeout(() => {
console.log('onLeave done');
done();
}, 150);
};
const onAfterEnter = () => {
// const transitionContainer = transitionRef.value!.$el as HTMLElement;
// transitionContainer.style.height = '';
// const transitionContainer = transitionRef.value!.$el as HTMLElement;
// transitionContainer.style.height = '';
};
</script>

<template>
<TransitionGroup name="fade-and-slide" tag="div" class="fade-and-slide" ref="transitionRef"
@enter="onEnter" @leave="onLeave" @after-enter="onAfterEnter">
<slot></slot>
</TransitionGroup>
<TransitionGroup name="fade-and-slide" tag="div" class="fade-and-slide" ref="transitionRef" @enter="onEnter"
@leave="onLeave" @after-enter="onAfterEnter" mode="out-in">
<slot></slot>
</TransitionGroup>
</template>

<style scoped>
.fade-and-slide {
transition: height 250ms ease-in-out;
overflow: hidden;
transition: height 250ms ease-in-out, opacity 100ms linear;
opacity: 1;
overflow: hidden;
}
</style>
10 changes: 9 additions & 1 deletion frontend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@ import App from './App.vue'
const appName = '战败惩罚';

const routes: RouteRecordRaw[] = [
{ path: '/', component: () => import('./pages/Controller.vue'), name: '控制器' },
{
path: '/', component: () => import('./pages/Controller.vue'), name: '控制器',
children: [
{ path: '', redirect: 'strength' },
{ path: 'strength', component: () => import('./pages/controller/StrengthSettings.vue'), name: '控制器 - 强度设置' },
{ path: 'pulse', component: () => import('./pages/controller/PulseSettings.vue'), name: '控制器 - 波形设置' },
{ path: 'game', component: () => import('./pages/controller/GameConnection.vue'), name: '控制器 - 游戏连接' },
],
},
];

const router = createRouter({
Expand Down
26 changes: 14 additions & 12 deletions frontend/src/pages/Controller.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { PulseItemInfo } from '../type/pulse';
import { useConfirm } from 'primevue/useconfirm';
import { ConnectorType, CoyoteDeviceVersion } from '../type/common';
import CoyoteBluetoothService from '../components/partials/CoyoteBluetoothService.vue';
import PulseSettings from '../components/partials/PulseSettings.vue';
import ClientInfoDialog from '../components/dialogs/ClientInfoDialog.vue';
import { useClientsStore } from '../stores/ClientsStore';
import ConnectToSavedClientsDialog from '../components/dialogs/ConnectToSavedClientsDialog.vue';
Expand Down Expand Up @@ -93,6 +92,8 @@ const state = reactive<ControllerPageState>({
showConnectToSavedClientsDialog: false,
});
const router = useRouter();
const coyoteBTRef = ref<InstanceType<typeof CoyoteBluetoothService> | null>(null);
const controllerPageTabs = [
Expand All @@ -101,6 +102,10 @@ const controllerPageTabs = [
{ title: '游戏连接', id: 'game', icon: 'pi pi-map' },
];
watch(() => state.controllerPage, (newVal) => {
router.push({ path: newVal });
});
// 在收到服务器的配置后设置为true,防止触发watch
let receivedConfig = false;
Expand Down Expand Up @@ -391,6 +396,7 @@ const postCustomPulseConfig = async () => {
console.error('Cannot post custom pulse config:', error);
}
};
provide('postCustomPulseConfig', postCustomPulseConfig);
const handleStartGame = async () => {
if (!dgClientConnected) {
Expand Down Expand Up @@ -533,17 +539,13 @@ watch([gameConfig, strengthConfig], () => {
</template>

<template #content>
<FadeAndSlideTransitionGroup>
<div v-if="state.controllerPage === 'strength'">
<StrengthSettings :state="state" />
</div>
<div v-else-if="state.controllerPage === 'pulse'">
<PulseSettings :state="state" @post-custom-pulse-config="postCustomPulseConfig" />
</div>
<div v-else-if="state.controllerPage === 'game'">
TODO: Game settings
</div>
</FadeAndSlideTransitionGroup>
<RouterView>
<template #default="{ Component }">
<FadeAndSlideTransitionGroup>
<component :is="Component" :state="state" />
</FadeAndSlideTransitionGroup>
</template>
</RouterView>
</template>
</Card>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ const state = reactive({
showRenamePulseDialog: false,
});
const emit = defineEmits<{
postCustomPulseConfig: []
}>();
const postCustomPulseConfig = inject<() => void>('postCustomPulseConfig');
const toast = inject<ToastServiceMethods>('parentToast');
const confirm = inject<{
Expand Down Expand Up @@ -75,7 +73,7 @@ const handlePulseImported = async (pulseInfo: PulseItemInfo) => {
parentState.customPulseList.push(pulseInfo);
toast?.add({ severity: 'success', summary: '导入成功', detail: '波形已导入', life: 3000 });
emit('postCustomPulseConfig');
postCustomPulseConfig?.();
};
const togglePulse = (pulseId: string) => {
Expand Down Expand Up @@ -110,7 +108,7 @@ const handleRenamePulseConfirm = async (newName: string) => {
let pulse = parentState.customPulseList.find((item) => item.id === renamePulseId);
if (pulse) {
pulse.name = newName;
emit('postCustomPulseConfig');
postCustomPulseConfig?.();
}
};
Expand All @@ -135,55 +133,57 @@ const handleDeletePulse = async (pulseId: string) => {
parentState.selectPulseIds = [fullPulseList.value[0].id];
}
emit('postCustomPulseConfig');
postCustomPulseConfig?.();
},
});
};
</script>

<template>
<div class="flex flex-col justify-between gap-2 mb-2 items-start md:flex-row md:items-center">
<h2 class="font-bold text-xl">波形列表</h2>
<div class="flex gap-2 items-center">
<Button icon="pi pi-sort-alpha-down" title="波形排序" severity="secondary" @click="state.showSortPulseDialog = true"
v-if="parentState.pulseMode === 'sequence'"></Button>
<Button icon="pi pi-plus" title="导入波形" severity="secondary"
@click="state.showImportPulseDialog = true"></Button>
<Button icon="pi pi-clock" title="波形切换间隔" severity="secondary" :label="parentState.pulseChangeInterval + 's'"
@click="showPulseTimePopover"></Button>
<SelectButton v-model="parentState.pulseMode" :options="pulseModeOptions" optionLabel="label" optionValue="value"
:allowEmpty="false" aria-labelledby="basic" />
<div class="w-full">
<div class="flex flex-col justify-between gap-2 mb-2 items-start md:flex-row md:items-center">
<h2 class="font-bold text-xl">波形列表</h2>
<div class="flex gap-2 items-center">
<Button icon="pi pi-sort-alpha-down" title="波形排序" severity="secondary" @click="state.showSortPulseDialog = true"
v-if="parentState.pulseMode === 'sequence'"></Button>
<Button icon="pi pi-plus" title="导入波形" severity="secondary"
@click="state.showImportPulseDialog = true"></Button>
<Button icon="pi pi-clock" title="波形切换间隔" severity="secondary" :label="parentState.pulseChangeInterval + 's'"
@click="showPulseTimePopover"></Button>
<SelectButton v-model="parentState.pulseMode" :options="pulseModeOptions" optionLabel="label" optionValue="value"
:allowEmpty="false" aria-labelledby="basic" />
</div>
</div>
</div>
<div v-if="parentState.pulseList" class="grid justify-center grid-cols-1 md:grid-cols-2 gap-4 pb-2">
<PulseCard v-for="pulse in fullPulseList" :key="pulse.id" :pulse-info="pulse"
:is-current-pulse="parentState.selectPulseIds.includes(pulse.id)"
:is-fire-pulse="pulse.id === parentState.firePulseId" @set-current-pulse="togglePulse"
@set-fire-pulse="setFirePulse" @delete-pulse="handleDeletePulse" @rename-pulse="handleRenamePulse" />
</div>
<div v-else class="flex justify-center py-4">
<ProgressSpinner />
</div>
<SortPulseDialog v-model:visible="state.showSortPulseDialog" :pulse-list="parentState.pulseList ?? []"
v-model:modelValue="parentState.selectPulseIds" />
<ImportPulseDialog v-model:visible="state.showImportPulseDialog" @on-pulse-imported="handlePulseImported" />
<PromptDialog v-model:visible="state.showRenamePulseDialog" @confirm="handleRenamePulseConfirm" title="重命名波形"
input-label="波形名称" :default-value="state.willRenamePulseName" />

<Popover class="popover-pulseTime" ref="pulseTimePopoverRef">
<div class="flex flex-col gap-4 w-[25rem]">
<div>
<span class="font-medium block mb-2">波形切换间隔</span>
<div class="flex gap-2">
<InputGroup>
<InputNumber v-model="parentState.pulseChangeInterval" :min="5" :max="600" />
<InputGroupAddon>秒</InputGroupAddon>
</InputGroup>
<SelectButton v-model="parentState.pulseChangeInterval" :options="presetPulseTimeOptions" optionLabel="label"
optionValue="value" :allowEmpty="false" aria-labelledby="basic" />
<div v-if="parentState.pulseList" class="grid justify-center grid-cols-1 md:grid-cols-2 gap-4 pb-2">
<PulseCard v-for="pulse in fullPulseList" :key="pulse.id" :pulse-info="pulse"
:is-current-pulse="parentState.selectPulseIds.includes(pulse.id)"
:is-fire-pulse="pulse.id === parentState.firePulseId" @set-current-pulse="togglePulse"
@set-fire-pulse="setFirePulse" @delete-pulse="handleDeletePulse" @rename-pulse="handleRenamePulse" />
</div>
<div v-else class="flex justify-center py-4">
<ProgressSpinner />
</div>
<SortPulseDialog v-model:visible="state.showSortPulseDialog" :pulse-list="parentState.pulseList ?? []"
v-model:modelValue="parentState.selectPulseIds" />
<ImportPulseDialog v-model:visible="state.showImportPulseDialog" @on-pulse-imported="handlePulseImported" />
<PromptDialog v-model:visible="state.showRenamePulseDialog" @confirm="handleRenamePulseConfirm" title="重命名波形"
input-label="波形名称" :default-value="state.willRenamePulseName" />

<Popover class="popover-pulseTime" ref="pulseTimePopoverRef">
<div class="flex flex-col gap-4 w-[25rem]">
<div>
<span class="font-medium block mb-2">波形切换间隔</span>
<div class="flex gap-2">
<InputGroup>
<InputNumber v-model="parentState.pulseChangeInterval" :min="5" :max="600" />
<InputGroupAddon>秒</InputGroupAddon>
</InputGroup>
<SelectButton v-model="parentState.pulseChangeInterval" :options="presetPulseTimeOptions" optionLabel="label"
optionValue="value" :allowEmpty="false" aria-labelledby="basic" />
</div>
</div>
</div>
</div>
</Popover>
</Popover>
</div>
</template>
Loading

0 comments on commit 70020d6

Please sign in to comment.