feat: 优化消息通知效果

This commit is contained in:
imsyy 2023-07-31 14:12:31 +08:00
parent 82d822d8a6
commit 855c313fec
9 changed files with 172 additions and 42 deletions

5
.env
View File

@ -1,2 +1,5 @@
# 搜索框提示词 # 搜索框提示词
VITE_INPUT_TIP = "想要搜点什么" VITE_INPUT_TIP = "想要搜点什么"
# 进入欢迎词
VITE_WELCOME_TEXT = "欢迎访问本站"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 138 KiB

View File

@ -1,6 +1,6 @@
<template> <template>
<!-- 壁纸 --> <!-- 壁纸 -->
<Cover /> <Cover @loadComplete="loadComplete" />
<!-- 主界面 --> <!-- 主界面 -->
<Transition name="fade" mode="out-in"> <Transition name="fade" mode="out-in">
<main v-if="status.imgLoadStatus" id="main" @click="mainClick"> <main v-if="status.imgLoadStatus" id="main" @click="mainClick">
@ -20,19 +20,36 @@
</template> </template>
<script setup> <script setup>
import { nextTick } from "vue";
import { statusStore } from "@/stores"; import { statusStore } from "@/stores";
import { Notivue, Notifications } from "notivue"; import { Notivue, Notifications, usePush } from "notivue";
import { getGreeting } from "@/utils/timeTools";
import Cover from "@/components/Cover.vue"; import Cover from "@/components/Cover.vue";
import WeatherTime from "@/components/WeatherTime.vue"; import WeatherTime from "@/components/WeatherTime.vue";
import SearchInp from "@/components/SearchInp.vue"; import SearchInp from "@/components/SearchInp.vue";
import Footer from "@/components/Footer.vue"; import Footer from "@/components/Footer.vue";
const status = statusStore(); const status = statusStore();
const push = usePush();
//
const welcomeText = import.meta.env.VITE_WELCOME_TEXT ?? "欢迎访问本站";
// //
const mainClick = () => { const mainClick = () => {
status.setSiteStatus("normal"); status.setSiteStatus("normal");
}; };
//
const loadComplete = () => {
nextTick(() => {
push.info({
title: getGreeting(),
message: welcomeText,
duration: 2000,
});
});
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -7,6 +7,7 @@
:src="bgUrl" :src="bgUrl"
@load="imgLoadComplete" @load="imgLoadComplete"
@error.once="imgLoadError" @error.once="imgLoadError"
@animationend="imgAnimationEnd"
/> />
<Transition name="fade"> <Transition name="fade">
<div v-if="set.showBackgroundGray" class="gray" /> <div v-if="set.showBackgroundGray" class="gray" />
@ -22,6 +23,7 @@ const set = setStore();
const status = statusStore(); const status = statusStore();
const bgUrl = ref(null); const bgUrl = ref(null);
const imgTimeout = ref(null); const imgTimeout = ref(null);
const emit = defineEmits(["loadComplete"]);
// //
// Math.random() // Math.random()
@ -53,8 +55,14 @@ const setBgUrl = () => {
const imgLoadComplete = () => { const imgLoadComplete = () => {
imgTimeout.value = setTimeout(() => { imgTimeout.value = setTimeout(() => {
status.setImgLoadStatus(true); status.setImgLoadStatus(true);
console.log("壁纸加载完成"); }, Math.floor(Math.random() * (600 - 300 + 1)) + 300);
}, 500); };
//
const imgAnimationEnd = () => {
console.log("壁纸加载且动画完成");
//
emit("loadComplete");
}; };
// //

View File

@ -6,9 +6,11 @@
@click="closeSearchInput" @click="closeSearchInput"
/> />
<div <div
ref="searchAllRef"
:class="status.siteStatus === 'focus' ? 'all focus' : 'all'" :class="status.siteStatus === 'focus' ? 'all focus' : 'all'"
:style="{ pointerEvents: inputClickable ? 'none' : 'auto' }" :style="{ pointerEvents: inputClickable ? 'none' : 'auto' }"
ref="searchAllRef" @animationstart="inputClickable = true"
@animationend="inputAnimationEnd"
> >
<div class="engine" title="切换搜索引擎"> <div class="engine" title="切换搜索引擎">
<SvgIcon iconName="icon-baidu" className="baidu" /> <SvgIcon iconName="icon-baidu" className="baidu" />
@ -40,9 +42,9 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from "vue"; import { ref } from "vue";
import { statusStore, setStore } from "@/stores";
import { usePush } from "notivue"; import { usePush } from "notivue";
import { statusStore, setStore } from "@/stores";
import Suggestions from "@/components/Suggestions.vue"; import Suggestions from "@/components/Suggestions.vue";
const set = setStore(); const set = setStore();
@ -109,26 +111,19 @@ const toSearch = (val, type = 1) => {
} else { } else {
status.setSiteStatus("focus"); status.setSiteStatus("focus");
searchInputRef.value?.focus(); searchInputRef.value?.focus();
push.info({ message: "请输入搜索内容", duration: 1000 }); push.info({ message: "请输入搜索内容", duration: 1500 });
} }
}; };
// Dom //
const searchInputDom = (dom) => { const inputAnimationEnd = () => {
if (!dom) return false; console.log("搜索框动画结束");
dom.addEventListener("animationstart", () => { inputClickable.value = false;
console.log("动画开始"); // focus
inputClickable.value = true; if (set.autoFocus) {
}); status.setSiteStatus("focus");
dom.addEventListener("animationend", () => { searchInputRef.value?.focus();
console.log("动画结束"); }
inputClickable.value = false;
// focus
if (set.autoFocus) {
status.setSiteStatus("focus");
searchInputRef.value?.focus();
}
});
}; };
// //
@ -140,10 +135,6 @@ const pressKeyboard = (event) => {
// //
suggestionsRef.value?.keyboardEvents(keyCode, event); suggestionsRef.value?.keyboardEvents(keyCode, event);
}; };
onMounted(() => {
searchInputDom(searchAllRef.value);
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -232,7 +232,10 @@ defineExpose({ keyboardEvents });
left: 0; left: 0;
width: 100%; width: 100%;
max-height: 44vh; max-height: 44vh;
overflow-y: auto; overflow-y: scroll;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
color: var(--main-text-color); color: var(--main-text-color);
background-color: var(--main-background-light-color); background-color: var(--main-background-light-color);
backdrop-filter: blur(30px) saturate(1.25); backdrop-filter: blur(30px) saturate(1.25);
@ -260,12 +263,22 @@ defineExpose({ keyboardEvents });
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
&:hover, @media (min-width: 520px) {
&.focus { &:hover,
&.focus {
background-color: var(--main-background-light-color);
padding-left: 18px;
}
}
&:active {
background-color: var(--main-background-light-color); background-color: var(--main-background-light-color);
padding-left: 18px; padding-left: 18px;
} }
} }
} }
&::-webkit-scrollbar {
width: 0;
height: 0;
}
} }
</style> </style>

View File

@ -7,8 +7,7 @@ import SvgIcon from "@/components/SvgIcon.vue";
import "@/utils/iconfont.js"; import "@/utils/iconfont.js";
// Notivue // Notivue
import { notivue } from "notivue"; import { notivue } from "notivue";
import "notivue/notifications.css"; // Only needed if using built-in notifications import "notivue/notifications.css";
import "notivue/animations.css"; // Only needed if using built-in animations
// 主组件 // 主组件
import App from "@/App.vue"; import App from "@/App.vue";
@ -27,6 +26,11 @@ app.use(pinia);
app.use(notivue, { app.use(notivue, {
pauseOnHover: false, pauseOnHover: false,
limit: 1, limit: 1,
animations: {
enter: "notivue-slide-in",
leave: "notivue-slide-out",
clearAll: "notivue-fade",
},
}); });
app.component("SvgIcon", SvgIcon); app.component("SvgIcon", SvgIcon);
app.mount("#app"); app.mount("#app");

View File

@ -29,11 +29,6 @@ body {
height: 100vh; height: 100vh;
} }
::selection {
color: var(--main-text-color);
background-color: var(--main-text-hover-color);
}
// Transition 动画 // Transition 动画
.fade-enter-active, .fade-enter-active,
.fade-leave-active { .fade-leave-active {
@ -68,6 +63,12 @@ body {
} }
// Notivue // Notivue
.notivue-slide-in {
animation: notivue-slide-in 0.7s ease-in-out both;
}
.notivue-slide-out {
animation: notivue-slide-out 0.3s ease-in-out both;
}
.Notivue__notification { .Notivue__notification {
background-color: var(--main-background-light-color); background-color: var(--main-background-light-color);
// backdrop-filter: blur(30px) saturate(1.25); // backdrop-filter: blur(30px) saturate(1.25);
@ -77,11 +78,27 @@ body {
display: none; display: none;
} }
.Notivue__content { .Notivue__content {
padding: 0.5rem; padding: 0.8rem 0.5rem;
.Notivue__content-message { display: flex;
text-align: center; flex-direction: row;
justify-content: center;
align-items: center;
.Notivue__content-title {
margin: 0;
margin-right: 6px;
line-height: inherit;
color: var(--main-text-grey-color); color: var(--main-text-grey-color);
} }
.Notivue__content-message {
line-height: inherit;
color: var(--main-text-grey-color);
}
@media (max-width: 480px) {
flex-direction: column;
.Notivue__content-title {
margin-bottom: 6px;
}
}
} }
} }
@ -148,3 +165,56 @@ body {
transform: scale(1); transform: scale(1);
} }
} }
@keyframes notivue-slide-in {
0% {
opacity: 0;
transform: translateY(-200px);
}
50% {
opacity: 1;
transform: translateY(10px);
}
70% {
transform: translateY(-5px);
}
100% {
transform: translateY(0);
}
}
@keyframes notivue-slide-out {
from {
transform: perspective(400px);
}
30% {
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
opacity: 1;
}
to {
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
opacity: 0;
}
}
// 文本选中
::selection {
color: var(--main-text-color);
background-color: var(--main-text-hover-color);
}
// 滚动条
::-webkit-scrollbar {
background-color: transparent;
width: 6px;
}
::-webkit-scrollbar-track {
display: none;
}
::-webkit-scrollbar-thumb {
border-radius: 12px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: var(--main-background-color);
}

View File

@ -27,3 +27,27 @@ export const getCurrentTime = () => {
}; };
return currentTime; return currentTime;
}; };
/**
* 根据实时时间返回不同的问候语
* @returns {string} 问候语
*/
export const getGreeting = () => {
const currentTime = new Date();
const currentHour = currentTime.getHours();
let greeting = "";
if (currentHour >= 5 && currentHour < 9) {
greeting = "早上好";
} else if (currentHour >= 9 && currentHour < 12) {
greeting = "上午好";
} else if (currentHour >= 12 && currentHour < 18) {
greeting = "下午好";
} else if (currentHour >= 18 && currentHour < 24) {
greeting = "晚上好";
} else if (currentHour >= 0 && currentHour < 5) {
greeting = "凌晨好";
} else {
greeting = "夜深了";
}
return greeting;
};