mirror of
https://github.com/caojiezi2003/Snavigation.git
synced 2024-11-23 19:39:46 +00:00
feat: 优化消息通知效果
This commit is contained in:
parent
82d822d8a6
commit
855c313fec
3
.env
3
.env
@ -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 |
21
src/App.vue
21
src/App.vue
@ -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>
|
||||||
|
@ -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");
|
||||||
};
|
};
|
||||||
|
|
||||||
// 图片显示失败
|
// 图片显示失败
|
||||||
|
@ -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", () => {
|
|
||||||
console.log("动画开始");
|
|
||||||
inputClickable.value = true;
|
|
||||||
});
|
|
||||||
dom.addEventListener("animationend", () => {
|
|
||||||
console.log("动画结束");
|
|
||||||
inputClickable.value = false;
|
inputClickable.value = false;
|
||||||
// 自动 focus
|
// 自动 focus
|
||||||
if (set.autoFocus) {
|
if (set.autoFocus) {
|
||||||
status.setSiteStatus("focus");
|
status.setSiteStatus("focus");
|
||||||
searchInputRef.value?.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>
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@media (min-width: 520px) {
|
||||||
&:hover,
|
&:hover,
|
||||||
&.focus {
|
&.focus {
|
||||||
background-color: var(--main-background-light-color);
|
background-color: var(--main-background-light-color);
|
||||||
padding-left: 18px;
|
padding-left: 18px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: var(--main-background-light-color);
|
||||||
|
padding-left: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -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");
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user