Compare commits

...

2 Commits

Author SHA1 Message Date
qingfeng1121
4fe6add803 11 2025-09-29 18:39:17 +08:00
qingfeng1121
aaf326ed1f 更新样式和功能:添加背景图、打字机效果,优化留言板和吐槽区布局 2025-09-29 18:39:10 +08:00
10 changed files with 702 additions and 764 deletions

View File

@@ -8,7 +8,7 @@
/* 首页 hero 区域高度和间距 */ /* 首页 hero 区域高度和间距 */
--hero-height: 600px; --hero-height: 600px;
/* hero 默认高度 */ /* hero 默认高度 */
--hero-height-small: 200px; --hero-height-small: 150px;
/* hero 收缩后高度 */ /* hero 收缩后高度 */
--hero-margin-top: 5%; --hero-margin-top: 5%;
/* hero 顶部外边距 */ /* hero 顶部外边距 */
@@ -68,10 +68,14 @@
/* 菜单字体大小 */ /* 菜单字体大小 */
--font-weight-menu: bold; --font-weight-menu: bold;
/* 菜单字体加粗 */ /* 菜单字体加粗 */
--body-background-img: url('../img/8.21.1.jpg');
/* 页面背景图片 */
} }
/* 页面背景设置 */ /* 页面背景设置 */
body { body {
background-image: var(--body-background-img);
/* 背景图片 */
background-size: 120% 120%; background-size: 120% 120%;
/* 背景图片缩放比例 */ /* 背景图片缩放比例 */
background-repeat: no-repeat; background-repeat: no-repeat;
@@ -180,6 +184,12 @@ p {
border-right: 0; border-right: 0;
} }
/* 内容通用背景区样式 */
#allstyle {
background-color: rgba(255, 255, 255, 0.85);
border-radius: 10px;
}
/* 内容区样式 */ /* 内容区样式 */
#content-section { #content-section {
min-height: 100vh; min-height: 100vh;
@@ -231,6 +241,19 @@ p {
height: var(--hero-height-small); height: var(--hero-height-small);
} }
/* 打字机效果 */
.typewriter {
white-space: pre;
min-height: 2.5em;
font-size: var(--title-font-size, 2rem);
}
@keyframes blink {
50% {
border-color: transparent;
}
}
/* hero 主标题样式 */ /* hero 主标题样式 */
.hero h1 { .hero h1 {
font-size: var(--title-font-size); font-size: var(--title-font-size);
@@ -282,6 +305,11 @@ p {
--content-margin: 0; --content-margin: 0;
--leftmodlue-width: 100%; --leftmodlue-width: 100%;
--nonsense-title-width: 95%; --nonsense-title-width: 95%;
--nonsense-title-margin-bottom: 15px;
--nav-padding-small: 0 8px;
--nonsenset-margin-top: 10px;
--body-background-img: url();
/* 移动端不显示背景图片 */
} }
.elrow-top { .elrow-top {
@@ -330,11 +358,11 @@ p {
.RouterViewpage { .RouterViewpage {
width: 100%; width: 100%;
margin: 5% 0 0 0;
} }
.nonsensetitle { .nonsensetitle {
width: var(--nonsense-title-width); position: relative;
margin-top: 10%;
padding: 10px; padding: 10px;
font-size: 1rem; font-size: 1rem;
} }

View File

@@ -3,14 +3,12 @@
<el-row justify="center"> <el-row justify="center">
<el-col :span="4" v-if="windowwidth"> <el-col :span="4" v-if="windowwidth">
<div class="grid-content ep-bg-purple-dark"> <div class="grid-content ep-bg-purple-dark">
<!-- <div><img src="../public/favicon.ico" alt=""></div> -->
<div>清疯不颠</div> <div>清疯不颠</div>
</div> </div>
</el-col> </el-col>
<el-col :span="14" justify="center"> <el-col :span="14" justify="center">
<div class="grid-content ep-bg-purple-dark"> <div class="grid-content ep-bg-purple-dark">
<el-menu :default-active="activeIndex" class="el-menu-demo" :collapse="false" <el-menu :default-active="activeIndex" class="el-menu-demo" :collapse="false" @select="handleSelect">
@select="handleSelect">
<el-menu-item index="/:type"> <el-menu-item index="/:type">
首页 首页
</el-menu-item> </el-menu-item>
@@ -35,12 +33,12 @@
</el-row> </el-row>
</div> </div>
<div class="hero" :class="{ 'newhero': classhero }" v-if="windowwidth"> <div class="hero" :class="{ 'newhero': classhero }" v-if="windowwidth">
<h1>如果感到累了撸一管就好了</h1> <h1 class="typewriter">{{ heroText }}</h1>
</div> </div>
<div id="content-section" :class="{ 'visible': isconts }"> <div id="content-section" :class="{ 'visible': isconts }">
<div class="nonsensetitle" v-if="classnonsenset"> <div class="nonsensetitle" v-if="classnonsenset">
<div class="nonsensetitleconst" v-if="windowwidth"> <div class="nonsensetitleconst">
<h1>发癫中QAQ</h1> <h1>发癫中QAQ</h1>
</div> </div>
</div> </div>
@@ -54,309 +52,166 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed } from 'vue'; import { ref, onMounted, onUnmounted } from 'vue';
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router';
import leftmodlue from '@/views/leftmodlue.vue' import leftmodlue from '@/views/leftmodlue.vue';
// hero 的高度更新 // hero 区域样式控制
const classhero = ref(false); const classhero = ref(false);
const isconts = ref(false); // 内容 // 内容区可见性
const isconts = ref(false);
// 左侧模块滚动状态
const isScrollingleftmodlue = ref(false); const isScrollingleftmodlue = ref(false);
const elrowtop = ref(); // 导航 // 导航栏样式类名
const classnonsenset = ref(false) // 疯言疯语 const elrowtop = ref('transparent');
const windowwidth = ref(true) // 屏幕 // 疯言疯语标题区显示
// 路由 const classnonsenset = ref(false);
const router = useRouter() // 屏幕宽度标记true为大屏false为小屏
const windowwidth = ref(true);
// 当前激活菜单
const activeIndex = ref('/:type');
// 打字机效果相关
const fullHeroText = '如果感到累了撸一管就好了';
const heroText = ref('');
let heroIndex = 0;
let heroTimer: number | undefined;
const startTypewriter = () => {
heroText.value = '';
heroIndex = 0;
if (heroTimer) clearInterval(heroTimer);
heroTimer = window.setInterval(() => {
if (heroIndex < fullHeroText.length) {
heroText.value += fullHeroText[heroIndex];
heroIndex++;
} else {
clearInterval(heroTimer);
}
}, 100);
};
const router = useRouter();
/**
* 菜单选择跳转
*/
const handleSelect = (key: string) => { const handleSelect = (key: string) => {
router.push({ router.push({ path: key });
path: key };
})
}
// 是否在某页面
const isclass = (url: any) => {
classhero.value = url != '/:type';
classnonsenset.value = url == '/nonsense'
}
// url监听 /**
// 使用router.beforeEach或router.afterEach全局守卫 * 根据路由路径设置页面状态
*/
const updatePageState = (url: string) => {
classhero.value = url !== '/:type';
console.log("当前路径是:"+url);
classnonsenset.value = url == '/nonsense';
console.log( classnonsenset.value);
};
/**
* 路由切换时处理页面状态和滚动
*/
router.beforeEach((to) => { router.beforeEach((to) => {
// console.log("从", from.path, "到", to.path); updatePageState(to.path);
isclass(to.path) setActiveIndex(to.path);
// 回到顶部 // 跳转后回到顶部
window.scrollTo({ window.scrollTo({ top: 0, behavior: 'smooth' });
top: 0, // 首页内容区滚动动画仅大屏下生效
behavior: 'smooth' // 平滑滚动 if (to.path === '/:type') {
}); isconts.value = window.innerWidth <= 768 ? true : false;
// 首页时启动打字机
}); startTypewriter();
// 滚动事件 } else {
const handleScroll = () => {
const scrollYmo = window.scrollY;
// 只有首页才会执行页面内容滚动效果
if (location.pathname == '/:type') {
isconts.value = window.scrollY > 200;
isScrollingleftmodlue.value = window.scrollY > 600;
}else{
isconts.value = true; isconts.value = true;
isScrollingleftmodlue.value = true; heroText.value = '';
if (heroTimer) clearInterval(heroTimer);
} }
// 导航 });
if (scrollYmo > 1200) {
elrowtop.value = 'hide' /**
* 滚动事件处理
*/
const handleScroll = () => {
// 屏幕小于768时只切换导航栏样式不做内容动画
if (window.innerWidth < 768) {
elrowtop.value = window.scrollY > 100 ? 'solid' : 'transparent';
return;
}
// 导航栏样式切换
if (window.scrollY > 1200) {
elrowtop.value = 'hide';
} else { } else {
elrowtop.value = window.scrollY > 100 ? 'solid' : 'transparent'; elrowtop.value = window.scrollY > 100 ? 'solid' : 'transparent';
} }
// 首页内容区滚动动画
if (location.pathname === '/:type') {
isconts.value = window.scrollY > 200;
isScrollingleftmodlue.value = window.scrollY > 600;
} else {
isconts.value = true;
isScrollingleftmodlue.value = true;
}
console.log("好耶滚动了");
}; };
/**
* 添加滚动监听
*/
const addScrollListener = () => { const addScrollListener = () => {
console.log("添加滚动监听");
window.addEventListener('scroll', handleScroll); window.addEventListener('scroll', handleScroll);
}; };
/**
* 移除滚动监听
*/
const removeScrollListener = () => { const removeScrollListener = () => {
console.log("移除滚动监听");
window.removeEventListener('scroll', handleScroll); window.removeEventListener('scroll', handleScroll);
}; };
const mediaquery = () => { /**
// 在这里处理屏幕大小变化 * 屏幕尺寸变化处理
* 小屏时移除滚动监听并设置相关状态
* 大屏时添加滚动监听
*/
const handleResize = () => {
if (window.innerWidth < 768) { if (window.innerWidth < 768) {
removeScrollListener(); windowwidth.value = false;
windowwidth.value = false isScrollingleftmodlue.value = true;
isScrollingleftmodlue.value = true classnonsenset.value = false;
classnonsenset.value = false
isconts.value = true; isconts.value = true;
// removeScrollListener();
} else { } else {
addScrollListener(); windowwidth.value = true;
windowwidth.value = true
} }
}; };
// 页面加载完成后执行 /**
const activeIndex = ref('/:type') * 设置当前激活菜单
const isactiveindex = () => { */
// 获取当前路径 const setActiveIndex = (locationpathname) => {
const currentPath = window.location.pathname; activeIndex.value = locationpathname;
// 判断路径并设置hero值 };
activeIndex.value = currentPath;
}
window.addEventListener('DOMContentLoaded', () => { // 生命周期钩子
isactiveindex(); onMounted(() => {
mediaquery(); handleResize(); addScrollListener();
window.addEventListener('resize', handleResize);
// 初始进入时如果是首页,启动打字机
if (window.location.pathname === '/:type') {
startTypewriter();
}
}); });
window.addEventListener('resize', mediaquery); onUnmounted(() => {
// removeScrollListener();
window.addEventListener('DOMContentLoaded', isactiveindex); window.removeEventListener('resize', handleResize);
// 输入框 if (heroTimer) clearInterval(heroTimer);
});
</script> </script>
<style></style> <style></style>
<!-- <style>
body {
/* background-image: url(./img/8.21.1.jpg); */
background-size: 120% 120%;
background-repeat: no-repeat;
background-position: center;
background-attachment: fixed;
}
body ul {
border-bottom: 0px;
}
.h1,
.h2,
.h3,
.h4,
.h5,
.h6,
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: inherit;
font-weight: 400;
line-height: 1.5;
margin-bottom: .5rem;
color: #32325d;
}
p {
font-size: 1rem;
font-weight: 300;
line-height: 1.7;
}
.cont {
margin-top: 5%;
}
/* 导航 */
.elrow-top {
position: fixed;
top: 0;
left: 0;
width: 100%;
padding: 20px 40px;
justify-content: space-between;
align-items: center;
z-index: 1000;
transition: all 0.4s ease;
font-size: inherit;
}
.elrow-top.transparent {
background-color: transparent;
}
.elrow-top.solid {
background-color: rgba(145, 196, 238, 0.85);
padding: 15px 40px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
}
.elrow-top.hide {
background-color: rgba(145, 196, 238, 0);
box-shadow: 0 5px 20px rgba(0, 0, 0, 0);
top: -100px;
transition: all 0.8s ease;
}
.elrow-top .el-row .el-col .grid-content .el-menu--horizontal {
border-bottom: 0px;
}
.el-menu--horizontal {
background: rgb(0, 0, 0, 0);
}
.el-menu-demo {
font-weight: bold;
font-size: 20px;
left: 10%;
}
.el-menu-demo .el-menu-item {
margin-left: 10px;
}
.el-menu.el-menu--horizontal.el-menu-demo .el-menu-item {
font-size: inherit;
}
.el-menu.el-menu--horizontal.el-menu-demo .el-menu-item:hover,
.el-menu.el-menu--horizontal.el-menu-demo .el-menu-item.is-active {
background-color: rgb(0, 0, 0, 0);
}
/* 内容 */
#content-section {
min-height: 100vh;
padding: 100px 10%;
opacity: 0;
transform: translateY(50px);
transition: all 0.8s ease-out;
/* margin: 20px 0; */
border-radius: 10px;
display: flex;
}
#content-section.visible {
opacity: 1;
transform: translateY(0);
}
.search {
margin-top: 12px;
}
.grid-content {
text-align: center;
}
.RouterViewpage {
width: 80%;
margin-left: 5%;
margin-right: 5%;
}
/* 分页 */
.Pagination {
align-self: center;
background-color: aqua;
}
#search {
display: flex;
}
.el-button {
background-color: rgb(0, 0, 0, 0);
border: 0px;
}
/* 状态栏 */
.leftmodluepage {
width: 20%;
}
/* 开头标题样式*/
.hero {
height: 600px;
margin-top: 5%;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
color: white;
}
.hero.newhero {
height: 200px;
transition: all 0.3s ease;
}
.hero h1 {
font-size: 3.5rem;
margin-bottom: 20px;
}
.hero p {
font-size: 1.5rem;
max-width: 700px;
margin: 0 auto 30px;
}
/* 疯言疯语标题 */
.nonsensetitle {
text-align: center;
position: absolute;
top: 0;
width: 76.5%;
padding: 20px;
margin-bottom: 50px;
background: rgba(255, 255, 255, 0.1) !important;
backdrop-filter: blur(10px);
border-radius: 20px;
}
.nonsensetitle .nonsensetitleconst {
padding: 1.5rem;
flex: 1 1 auto;
box-sizing: border-box;
}
.nonsensetitle .nonsensetitleconst p {
font-size: 1rem;
}
/* 调整样式 */
.nonsensetmargintop {
margin-top: 130px;
}
/* 输入框 */
</style> -->

View File

@@ -2,7 +2,6 @@ import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import Router from './router/Router' import Router from './router/Router'
import './assets/index.css' import './assets/index.css'
const app = createApp(App) const app = createApp(App)
app.use(Router) app.use(Router)
app.mount('#app') app.mount('#app')

View File

@@ -89,11 +89,6 @@ const datas = [
] ]
</script> </script>
<style> <style>
#allstyle {
background-color: rgba(255, 255, 255, 0.85);
border-radius: 10px;
}
.header { .header {
text-align: center; text-align: center;
padding: 20px; padding: 20px;

View File

@@ -5,9 +5,11 @@
</div> </div>
<p>通过传来的{{ urls }}向服务器发送请求获取相关文章的链接</p> <p>通过传来的{{ urls }}向服务器发送请求获取相关文章的链接</p>
</div> </div>
</template> </template>
<script setup> <script setup>
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
const urls = useRoute().query const urls = useRoute().query
</script> </script>
<style></style> <style>
</style>

View File

@@ -1,33 +1,34 @@
<!-- 文章模板 --> <!-- 文章模板 -->
<template> <template>
<div> <div>
<div class="button-example" @click="aericleClick(items.aur) " v-for="items in datas"> <div
<div v-if="items.mg == ''"> class="article-card"
<h2>{{ items.title }}</h2> v-for="item in datas"
<el-text class="mx-1">{{ items.author }}</el-text> :key="item.title + item.publishedAt"
<p>{{ items.publishedAt }}</p> @click="aericleClick(item.aur)"
</div> >
<div v-else="items.mg != ''"> <h2>{{ item.title }}</h2>
<h2>{{ items.title }}</h2> <el-text class="mx-1">{{ item.author }}</el-text>
<el-text class="mx-1">{{ items.author }}</el-text> <div v-if="item.mg">mg</div>
<div>mg</div> <p>{{ item.publishedAt }}</p>
<p>{{ items.publishedAt }}</p>
</div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const router = useRouter() const router = useRouter()
// 跳转到文章详情
const aericleClick = (aur) => { const aericleClick = (aur) => {
router.push({ router.push({
path:'/articlecontents/:url', path: '/articlecontents/:url',
query:{ query: { url: aur }
url:aur })
}
})
} }
// 文章数据
const datas = [ const datas = [
{ {
title: '测试1', title: '测试1',
@@ -115,10 +116,19 @@ const datas = [
mg_b: '', mg_b: '',
publishedAt: '2016-04-12' publishedAt: '2016-04-12'
}, },
{
title: '测试2',
author: '这是img模块测试',
aur: '链接',
mg: '',
mg_b: '',
publishedAt: '2016-04-12'
},
] ]
</script> </script>
<style scoped> <style scoped>
.button-example { .article-card {
border-radius: 10px; border-radius: 10px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -126,37 +136,32 @@ const datas = [
background-color: rgba(255, 255, 255, 0.85); background-color: rgba(255, 255, 255, 0.85);
padding: 15px; padding: 15px;
margin-bottom: 30px; margin-bottom: 30px;
transition: all 0.4s ease;
position: relative;
overflow: hidden;
cursor: pointer;
} }
.article-card::before {
.button-example { content: '';
transition: all 0.4s ease; position: absolute;
position: relative; top: 0;
overflow: hidden; left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg,
rgba(255,255,255,0.6) 0%,
rgba(255,255,255,0.2) 50%,
rgba(255,255,255,0.05) 100%);
pointer-events: none;
opacity: 0;
transition: opacity 0.4s ease;
} }
.article-card:hover {
.button-example::before { transform: translateY(-5px) perspective(2000px) rotateX(0);
content: ''; box-shadow: 0 20px 40px rgba(0, 0, 0, 0.25),
position: absolute; 0 0 50px rgba(255, 255, 255, 0.3);
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg,
rgba(255,255,255,0.6) 0%,
rgba(255,255,255,0.2) 50%,
rgba(255,255,255,0.05) 100%);
pointer-events: none;
opacity: 0;
transition: opacity 0.4s ease;
} }
.article-card:hover::before {
.button-example:hover { opacity: 1;
transform: translateY(-5px) perspective(2000px) rotateX(0);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.25),
0 0 50px rgba(255, 255, 255, 0.3);
}
.button-example:hover::before {
opacity: 1;
} }
</style> </style>

View File

@@ -14,7 +14,7 @@
<p>左眼右右眼左四十五度成就美</p> <p>左眼右右眼左四十五度成就美</p>
</div> </div>
<div class="cont2"> <div class="cont2">
<el-menu class="el-menu-vertical-demo" @select="handleSelect"> <el-menu :default-active="activeIndex" class="el-menu-vertical-demo" @select="handleSelect">
<el-menu-item index="/:type"> <el-menu-item index="/:type">
<el-icon> <el-icon>
</el-icon> </el-icon>
@@ -52,127 +52,158 @@
import { reactive, ref, onMounted, onUnmounted } from 'vue' import { reactive, ref, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
// 当前激活菜单
const activeIndex = ref('/:type')
const router = useRouter() const router = useRouter()
const activeName = ref('first') const activeName = ref('first')
const state = reactive({ const state = reactive({
circleUrl: circleUrl: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png', squareUrl: 'https://cube.elemecdn.com/9/c2/f0ee8a3c7c9638a54940382568c9dpng.png',
squareUrl:
'https://cube.elemecdn.com/9/c2/f0ee8a3c7c9638a54940382568c9dpng.png',
sizeList: ['small', '', 'large'] as const, sizeList: ['small', '', 'large'] as const,
}) })
const handleSelect = (key: string, keyPath: string[]) => { // 处理菜单选择跳转
router.push({ const handleSelect = (key: string) => {
path: key router.push({ path: key })
})
} }
// 滚动事件
const scrollY = ref(false);
const handleScroll = () => {
const scrollYmo = window.scrollY;
scrollY.value = scrollYmo > 1100;
};
window.addEventListener('scroll', handleScroll);
// 路由切换时同步菜单高亮
router.beforeEach((to) => {
activeIndex.value = to.path
})
// 控制底部模块吸顶效果
const scrollY = ref(false)
const handleScroll = () => {
scrollY.value = window.scrollY > 1100
}
// 生命周期管理事件监听,防止内存泄漏
onMounted(() => {
window.addEventListener('scroll', handleScroll)
})
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll)
})
</script> </script>
<style> <style>
/* 整体布局外层每个子div底部间距 */
#alld div { #alld div {
margin-bottom: 15px; margin-bottom: 15px;
} }
/* 顶部公告栏样式 */
#top { #top {
height: 100px; height: 100px;
border-radius: 10px; border-radius: 10px;
background-color: rgb(102, 161, 216, 0.9); background-color: rgba(102, 161, 216, 0.9); /* 蓝色半透明背景 */
text-align: left; text-align: left;
padding: 15px; padding: 15px;
} }
/* 公告栏副标题字体大小 */
#top .top2 p { #top .top2 p {
font-size: 15px; font-size: 15px;
} }
/* 中部内容区整体样式 */
#cont { #cont {
padding: 15px; padding: 15px;
height: 350px; height: 350px;
border-radius: 10px; border-radius: 10px;
padding: 0; padding: 0;
} }
/* */
/* 内容区上半部分(标题) */
#cont .cont1 { #cont .cont1 {
border-radius:10px 10px 0 0; border-radius: 10px 10px 0 0;
padding: 15px; padding: 15px;
text-align: center; text-align: center;
margin-bottom: 0; margin-bottom: 0;
background-color: rgb(102, 161, 216, 0.9); background-color: rgba(102, 161, 216, 0.9); /* 蓝色半透明背景 */
}
#cont .cont2{
padding: 10px 0;
border-radius:0 0 10px 10px;
background-color: rgba(215, 224, 218, 0.9);
}
#cont .cont2 .el-menu-vertical-demo{
display: inline;
}
#cont .cont2 .el-menu-vertical-demo .el-menu-item:hover {
background-color: rgb(255, 255, 255 , 0.7);
}
.el-menu-vertical-demo {
background-color: rgb(0, 0, 0, 0);
border-right: 0px;
} }
/* 内容区下半部分(菜单) */
#cont .cont2 {
padding: 10px 0;
border-radius: 0 0 10px 10px;
background-color: rgba(215, 224, 218, 0.9); /* 浅绿色半透明背景 */
}
/* 菜单整体样式 */
#cont .cont2 .el-menu-vertical-demo {
display: inline;
}
/* 菜单项悬停效果 */
#cont .cont2 .el-menu-vertical-demo .el-menu-item:hover {
background-color: rgba(255, 255, 255, 0.7); /* 白色半透明 */
}
/* 菜单背景透明,去除右边框 */
.el-menu-vertical-demo {
background-color: transparent;
border-right: 0;
}
/* 去除内容区和底部区子div的底部间距 */
#cont div, #cont div,
#bot div { #bot div {
margin-bottom: 0%; margin-bottom: 0;
} }
/* */
/* 底部模块样式 */
#bot { #bot {
padding: 15px; padding: 15px;
border-radius: 10px; border-radius: 10px;
background-color: rgb(0, 233, 70, 0.7); background-color: rgba(0, 233, 70, 0.7); /* 绿色半透明背景 */
transition: all 0.4s ease; transition: all 0.4s ease;
} }
/* 底部模块吸顶效果 */
#bot.botrelative { #bot.botrelative {
transition: all 0.4s ease; transition: all 0.4s ease;
position: sticky; position: sticky;
top: 20px; top: 20px;
} }
/* tabs整体居中字体颜色 */
.demo-tabs { .demo-tabs {
text-align: center; text-align: center;
color: #6b778c; color: #6b778c;
} }
/* tabs导航栏高度和下边距 */
.el-tabs__nav-scroll { .el-tabs__nav-scroll {
height: 45px; height: 45px;
margin-bottom: 5px; margin-bottom: 5px;
} }
/* tabs导航栏宽度 */
.el-tabs__nav { .el-tabs__nav {
width: 100%; width: 100%;
} }
/* tabs每个item宽度一半 */
.el-tabs__item { .el-tabs__item {
width: 50%; width: 50%;
} }
/* 去除tabs导航栏底部线 */
.el-tabs__nav-wrap:after { .el-tabs__nav-wrap:after {
height: 0px; height: 0;
} }
/* 头像容器,垂直水平居中 */
.mylogo { .mylogo {
height: 80px; height: 80px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
/* 头像悬停放大效果 */
.el-avatar:hover { .el-avatar:hover {
transform: scale(2); transform: scale(2);
z-index: 2; z-index: 2;

View File

@@ -1,73 +1,341 @@
<template> <template>
<div id="messahe_all"> <div class="message-board">
<div id="allstyle"> <!-- 留言内容区 -->
<div class="header"> <div class="message-list">
<h1>留言板</h1> <h3>留言板</h3>
<div class="message-item" v-for="msg in messages" :key="msg.id" @mouseenter="hoverId = msg.id"
@mouseleave="hoverId = null">
<div>
<!-- 头像 -->
<img src="https://www.gravatar.com/avatar?d=mp&s=40" alt="头像" class="message-avatar" />
</div>
<div>
<!-- 评论内容 -->
<div class="message-item-top">
<div class="message-nickname">{{ msg.nickname }}</div>
<div class="message-time">{{ msg.time }}</div>
</div>
<div class="message-content">{{ msg.content }}</div>
<!-- 回复按钮 -->
<div class="message-item-bottom">
<button class="reply-btn" @click="message_click(msg)"
:class="{ visible: hoverId === msg.id }">回复</button>
</div>
<!-- 回复列表 -->
<div v-if="msg.replies && msg.replies.length" class="replies">
<div class="reply-item" v-for="reply in msg.replies" :key="reply.id">
<div>
<!-- 头像 -->
<img src="https://www.gravatar.com/avatar?d=mp&s=40" alt="头像" class="message-avatar" />
</div>
<div>
<div class="message-item-top ">
<div class="message-nickname">{{ reply.nickname }}</div>
<div class="message-time">{{ reply.time }}</div>
</div>
<div class="message-content">{{ reply.content }}</div>
<!-- 回复按钮 -->
<div class="message-item-bottom">
<button class="reply-btn" @click="message_click(msg)"
:class="{ visible: hoverId === msg.id }">回复</button>
</div>
</div>
</div>
</div>
</div>
</div> </div>
<div v-if="messages.length === 0" class="message-empty">还没有留言快来抢沙发吧</div>
</div> </div>
<div id="allstyle" class="botom"> <!-- 留言输入区 -->
<h1>发送评论(请正确填写邮箱地址否则将会当成垃圾评论处理)</h1> <div class="message-form-section">
<el-form :model="form"> <h2>发送评论请正确填写邮箱地址否则将会当成垃圾评论处理</h2>
<!-- 输入框 --> <div v-if="message_all.id" class="reply-preview">
<el-form-item > <span>
<el-input v-model="form" placeholder="评论内容" type="textarea" /> 正在回复 <b>{{ message_all.nickname }}</b> 的评论 :
</span>
<div class="reply-preview-content">
{{ message_all.content }}
</div>
<button class="reply-cancel-btn" @click="post_comment_reply_cancel">取消回复</button>
</div>
<el-form :model="form" label-width="0">
<el-form-item>
<el-input v-model="form.content" placeholder="评论内容" type="textarea" rows="4" clearable />
</el-form-item> </el-form-item>
<div class="botom_form_input"> <div class="form-input-row">
<el-form-item > <el-form-item>
<el-input v-model="form" placeholder="昵称" clearable /> <el-input v-model="form.nickname" placeholder="昵称" clearable />
</el-form-item> </el-form-item>
<el-form-item > <el-form-item>
<el-input v-model="form" placeholder="邮箱/QQ号" clearable /> <el-input v-model="form.email" placeholder="邮箱/QQ号" clearable />
</el-form-item> </el-form-item>
<el-form-item > <el-form-item>
<el-input v-model="form" placeholder="验证码" clearable /> <el-input v-model="form.captcha" placeholder="验证码" clearable />
</el-form-item>
</div>
<div class="form-input-row">
<el-form-item>
<el-button type="primary" @click="onSubmit">发送</el-button>
</el-form-item> </el-form-item>
</div> </div>
<!-- 按钮 -->
<el-form-item>
<el-button type="primary" @click="onSubmit">发送</el-button>
</el-form-item>
</el-form> </el-form>
</div> </div>
</div> </div>
</template> </template>
<script>
import { reactive } from 'vue'
// do not use same name with ref <script setup>
import { reactive, ref } from 'vue'
const message_all = ref({})
const hoverId = ref(null)
const messages = ref([
{
id: 1,
nickname: 'A',
content: '这里是A',
time: '2025-09-26 10:00',
replies: [
{
id: 4,
nickname: 'B',
content: 'A我来回复你',
time: '2025-09-26 10:20'
}
]
},
{
id: 2,
nickname: 'B',
content: '这里是B',
time: '2025-09-26 10:05',
replies: []
},
{
id: 3,
nickname: 'C',
content: '这里是C',
time: '2025-09-26 10:10',
replies: []
}
])
const form = reactive({ const form = reactive({
name: '', replyid: null,
region: '', content: '',
type: [], nickname: '',
resource: '', email: '',
desc: '', captcha: ''
}) })
const onSubmit = () => { const onSubmit = () => {
console.log('submit!') if (!form.content || !form.nickname) return
if (form.replyid) {
// 回复模式
const parent = messages.value.find(msg => msg.id === form.replyid)
if (parent) {
parent.replies = parent.replies || []
parent.replies.push({
id: Date.now(),
nickname: form.nickname,
content: form.content,
time: new Date().toLocaleString()
})
}
} else {
// 普通留言
messages.value.push({
id: Date.now(),
nickname: form.nickname,
content: form.content,
time: new Date().toLocaleString(),
replies: []
})
}
form.replyid = null
form.content = ''
form.nickname = ''
form.email = ''
form.captcha = ''
message_all.value = {}
}
const message_click = (msg) => {
message_all.value = msg
form.replyid = msg.id
// 可选:填充回复内容到输入框
form.content = `@${msg.nickname} `
}
const post_comment_reply_cancel = () => {
message_all.value = {}
form.content = ''
form.replyid = null
} }
</script> </script>
<style>
.botom{ <style scoped>
padding: 20px; .message-board {
padding: 24px 0;
} }
#allstyle.botom{ .message-list {
margin-top: 10px; margin-bottom: 24px;
background: #f8fafd;
border-radius: 12px;
padding: 16px;
min-height: 120px;
} }
.botom_form_input{ .replies {
margin-left: 40px;
border-top: 2px solid #eee;
padding: 12px;
}
.message-item {
background: #fff;
border-radius: 10px;
padding: 14px 18px;
margin-bottom: 12px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
flex-direction: column;
gap: 4px;
position: relative;
margin-left: 1%;
}
.message-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 12px;
float: left;
}
.message-item-top {
display: flex; display: flex;
justify-content: space-between;
align-items: center;
} }
.botom_form_input .el-form-item{
width: 30%; .message-nickname {
display: block; font-weight: bold;
color: #409eff;
} }
.botom_form_input .el-form-item:nth-child(2){
margin: 0 2.5%; .message-content {
color: #333;
margin-top: 2px;
} }
.botom_form_input .el-form-item .el-input__inner {
.message-time {
font-size: 12px;
color: #aaa;
text-align: right;
}
.message-item-bottom {
height: 45px; height: 45px;
/* 固定高度以防跳动 */
text-align: center;
}
.reply-btn {
background: #409eff;
color: #fff;
border: none;
border-radius: 6px;
padding: 4px 12px;
margin-top: 4px;
transition: background 0.2s;
float: right;
visibility: hidden;
/* 默认隐藏但占位 */
}
.message-item:hover .reply-btn,
.reply-btn.visible {
visibility: visible;
}
.message-empty {
color: #bbb;
text-align: center;
padding: 32px 0;
}
.message-form-section {
background: #fff;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.message-form-section h2 {
font-size: 1.1rem;
margin-bottom: 18px;
color: #333;
}
.reply-preview {
background: #f0f9ff;
border-left: 4px solid #409eff;
padding: 10px 16px;
border-radius: 8px;
margin-bottom: 16px;
color: #333;
}
.reply-preview-content {
margin-top: 6px;
color: #666;
font-size: 0.98rem;
}
.reply-cancel-btn {
background: #fff;
color: #409eff;
border: 1px solid #409eff;
border-radius: 6px;
padding: 2px 10px;
cursor: pointer;
margin-top: 8px;
font-size: 0.95rem;
transition: background 0.2s, color 0.2s;
}
.reply-cancel-btn:hover {
background: #409eff;
color: #fff;
}
.form-input-row {
display: flex;
gap: 16px;
margin-bottom: 12px;
}
.form-input-row .el-form-item {
flex: 1;
}
.el-form-item .el-input__inner,
.el-form-item .el-textarea__inner {
min-height: 45px;
font-size: 1rem;
}
@media (max-width: 768px) {
.message-board {
padding: 8px 0;
}
.message-form-section {
padding: 12px;
}
.form-input-row {
flex-direction: column;
gap: 8px;
}
} }
</style> </style>

View File

@@ -1,7 +1,98 @@
<template> <template>
<div id="allstyle"> <div id="aericle-style">
<div class="header"> <div class="aericle-list">
<h1>疯言疯语</h1> <div
class="aericle-item"
v-for="item in aericleList"
:key="item.id"
>
<div class="aericle-meta">
<span class="aericle-time">{{ item.time }}</span>
</div> </div>
<div class="aericle-content">{{ item.content }}</div>
</div>
</div> </div>
</div>
</template> </template>
<script setup>
import { ref } from 'vue'
// 吐槽数据(仅站长可见/可发)
const aericleList = ref([
{
id: 1,
content: '嘿嘿 嘿嘿嘿流口水ing',
time: '2025-09-26 09:30'
}
])
</script>
<style scoped>
#aericle-style {
background: rgba(255,255,255,0.95);
border-radius: 12px;
padding: 32px 20px 24px 20px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
}
.aericle-header {
text-align: center;
margin-bottom: 28px;
}
.aericle-header h1 {
font-size: 2.2rem;
margin-bottom: 8px;
color: #409eff;
letter-spacing: 2px;
}
.aericle-desc {
color: #888;
font-size: 1rem;
margin-bottom: 0;
}
.aericle-list {
display: flex;
flex-direction: column;
gap: 18px;
}
.aericle-item {
background: #f8fafd;
border-radius: 10px;
padding: 18px 20px 14px 20px;
box-shadow: 0 1px 4px rgba(0,0,0,0.03);
position: relative;
transition: box-shadow 0.2s;
}
.aericle-item:hover {
box-shadow: 0 4px 16px rgba(64,158,255,0.12);
}
.aericle-meta {
font-size: 13px;
color: #aaa;
margin-bottom: 8px;
text-align: right;
}
.aericle-content {
font-size: 1.08rem;
color: #333;
line-height: 1.8;
word-break: break-all;
}
@media (max-width: 768px) {
#aericle-style {
padding: 14px 4px 10px 4px;
}
.aericle-header h1 {
font-size: 1.4rem;
}
.aericle-content {
font-size: 0.98rem;
}
}
</style>

View File

@@ -1,336 +0,0 @@
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
display: flex;
min-height: 100vh;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
color: #e6e6e6;
overflow: hidden;
}
/* 进度条样式 */
.progress-container {
width: 50px;
background: rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
align-items: center;
padding: 20px 0;
position: relative;
z-index: 100;
}
.progress-bar {
width: 20px;
height: 70vh;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
overflow: hidden;
position: relative;
}
.progress-fill {
position: absolute;
bottom: 0;
width: 100%;
background: linear-gradient(to top, #ff416c, #ff4b2b);
height: 0%;
transition: height 0.3s ease;
border-radius: 10px;
}
.progress-text {
writing-mode: vertical-rl;
text-orientation: mixed;
margin-top: 20px;
color: rgba(255, 255, 255, 0.7);
font-size: 14px;
letter-spacing: 1px;
}
/* 内容区域样式 */
.content {
flex: 1;
padding: 40px;
position: relative;
}
h1 {
font-size: 2.5rem;
margin-bottom: 20px;
color: #ff4b2b;
}
p {
font-size: 1.1rem;
line-height: 1.6;
margin-bottom: 15px;
max-width: 800px;
}
.warning {
color: #ff416c;
font-weight: bold;
}
/* 崩坏效果 */
.corruption-effect {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 50;
}
.glitch-text {
animation: glitch 1s infinite;
}
@keyframes glitch {
0% {
text-shadow: 2px 2px #ff416c, -2px -2px #2bffc2;
}
25% {
text-shadow: -2px 2px #2bffc2, 2px -2px #ff416c;
}
50% {
text-shadow: 2px -2px #2bffc2, -2px 2px #ff416c;
}
75% {
text-shadow: -2px -2px #ff416c, 2px 2px #2bffc2;
}
100% {
text-shadow: 2px 2px #2bffc2, -2px -2px #ff416c;
}
}
/*内容消融 */
.dissolve {
animation: dissolve 3s forwards;
}
@keyframes dissolve {
to {
opacity: 0;
transform: translateY(20px) rotate(5deg);
}
}
/* 模态框样式 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-content {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
padding: 30px;
border-radius: 10px;
text-align: center;
max-width: 500px;
width: 90%;
border: 2px solid #ff416c;
box-shadow: 0 0 25px #ff416c;
}
.modal h2 {
color: #ff4b2b;
margin-bottom: 20px;
font-size: 2rem;
}
.modal p {
margin-bottom: 25px;
font-size: 1.2rem;
}
.btn {
background: linear-gradient(to right, #ff416c, #ff4b2b);
color: white;
border: none;
padding: 12px 30px;
border-radius: 30px;
font-size: 1rem;
cursor: pointer;
transition: transform 0.3s, box-shadow 0.3s;
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(255, 75, 43, 0.4);
}
</style>
<template>
<!-- 进度条 -->
<div class="progress-container">
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div class="progress-text">系统稳定性进度</div>
</div>
<!-- 内容区域 -->
<div class="content">
<h1>系统稳定性控制面板</h1>
<p>欢迎访问系统控制中心本面板用于监控和维持系统稳定性</p>
<p class="warning">警告系统目前处于高度不稳定状态请勿进行任何关键操作</p>
<p>当前状态<span id="statusText">监控中...</span></p>
<p>系统完整性<span id="integrityText">98%</span></p>
<p>如果系统开始出现异常请立即保存您的工作并准备撤离</p>
<p>倒计时直到可能的不稳定事件<span id="countdown">00:30</span></p>
</div>
<!-- 崩坏效果层 -->
<div class="corruption-effect" id="corruptionEffect"></div>
<!-- 模态框 -->
<div class="modal" id="modal">
<div class="modal-content">
<h2>系统崩溃</h2>
<p>系统稳定性已降至临界水平为防止数据丢失系统将自动关闭</p>
<p>请返回主页并重新登录</p>
<button class="btn" id="homeBtn">返回主页</button>
</div>
</div>
</template>
<script>
document.addEventListener('DOMContentLoaded', function () {
const progressFill = document.getElementById('progressFill');
const statusText = document.getElementById('statusText');
const integrityText = document.getElementById('integrityText');
const countdown = document.getElementById('countdown');
const corruptionEffect = document.getElementById('corruptionEffect');
const modal = document.getElementById('modal');
const homeBtn = document.getElementById('homeBtn');
const content = document.querySelector('.content');
let progress = 0;
let countdownTime = 30;
let corruptionActive = false;
// 更新倒计时显示
function updateCountdown() {
const minutes = Math.floor(countdownTime / 60);
const seconds = countdownTime % 60;
countdown.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
if (countdownTime > 0) {
countdownTime--;
}
}
// 初始化倒计时
setInterval(updateCountdown, 1000);
// 更新进度条
const progressInterval = setInterval(() => {
progress += 1;
progressFill.style.height = `${progress}%`;
if (progress >= 70) {
statusText.textContent = "稳定性下降";
statusText.classList.add('warning');
}
if (progress >= 85) {
integrityText.textContent = "75%";
}
if (progress >= 100) {
clearInterval(progressInterval);
startCorruption();
}
}, 100);
// 开始崩坏效果
function startCorruption() {
corruptionActive = true;
statusText.textContent = "系统崩溃中!";
integrityText.textContent = "23%";
// 添加崩坏效果
document.body.classList.add('glitch-text');
// 文字颜色随机变化
const textElements = document.querySelectorAll('p, h1, span');
const colorInterval = setInterval(() => {
textElements.forEach(el => {
el.style.color = `rgb(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255})`;
});
}, 200);
// 内容逐渐消融
content.classList.add('dissolve');
// 显示模态框
setTimeout(() => {
modal.style.display = 'flex';
clearInterval(colorInterval);
}, 3000);
}
// 返回主页按钮事件
homeBtn.addEventListener('click', function () {
alert('返回主页');
// 实际应用中这里可能是 window.location.href = '/';
});
// 添加一些随机崩坏效果
function addCorruptionEffects() {
if (!corruptionActive) return;
// 创建随机闪烁元素
const effect = document.createElement('div');
effect.style.position = 'absolute';
effect.style.left = Math.random() * 100 + 'vw';
effect.style.top = Math.random() * 100 + 'vh';
effect.style.width = Math.random() * 100 + 50 + 'px';
effect.style.height = Math.random() * 10 + 2 + 'px';
effect.style.background = `linear-gradient(90deg,
rgba(255, 75, 43, ${Math.random() * 0.7}),
rgba(255, 65, 108, ${Math.random() * 0.5}))`;
effect.style.boxShadow = '0 0 10px rgba(255, 65, 108, 0.7)';
effect.style.opacity = Math.random() * 0.7;
effect.style.transform = `rotate(${Math.random() * 360}deg)`;
effect.style.pointerEvents = 'none';
corruptionEffect.appendChild(effect);
// 移除元素
setTimeout(() => {
if (effect.parentNode) {
effect.parentNode.removeChild(effect);
}
}, 2000);
}
// 当崩坏激活时,定期添加效果
setInterval(() => {
if (corruptionActive) {
for (let i = 0; i < 3; i++) {
addCorruptionEffects();
}
}
}, 300);
});
</script>