更新样式和功能:添加背景图、打字机效果,优化留言板和吐槽区布局

This commit is contained in:
qingfeng1121
2025-09-29 18:39:10 +08:00
parent ade67e4411
commit aaf326ed1f
8 changed files with 519 additions and 422 deletions

View File

@@ -72,6 +72,7 @@
/* 页面背景设置 */ /* 页面背景设置 */
body { body {
background-image: url('../img/8.21.1.jpg');
background-size: 120% 120%; background-size: 120% 120%;
/* 背景图片缩放比例 */ /* 背景图片缩放比例 */
background-repeat: no-repeat; background-repeat: no-repeat;
@@ -179,7 +180,11 @@ p {
display: flex; display: flex;
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 +236,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 +300,7 @@ p {
--content-margin: 0; --content-margin: 0;
--leftmodlue-width: 100%; --leftmodlue-width: 100%;
--nonsense-title-width: 95%; --nonsense-title-width: 95%;
--nav-padding-small: 0 8px;
} }
.elrow-top { .elrow-top {

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,7 +33,7 @@
</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 }">
@@ -54,309 +52,161 @@
</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';
classnonsenset.value = url === '/nonsense';
};
/**
* 路由切换时处理页面状态和滚动
*/
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;
}
}; };
/**
* 添加滚动监听
*/
const addScrollListener = () => { const addScrollListener = () => {
window.addEventListener('scroll', handleScroll); window.addEventListener('scroll', handleScroll);
}; };
/**
* 移除滚动监听
*/
const removeScrollListener = () => { const removeScrollListener = () => {
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 {
windowwidth.value = true;
addScrollListener(); addScrollListener();
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();
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

@@ -1,18 +1,16 @@
<!-- 文章模板 --> <!-- 文章模板 -->
<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>
@@ -20,14 +18,16 @@
<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 +115,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 +135,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,29 +1,36 @@
<template> <template>
<div id="messahe_all"> <div id="message_all">
<div id="allstyle"> <!-- 标题区 -->
<div class="header"> <div class="message-header">
<h1>留言板</h1> <h1>留言板</h1>
</div>
</div> </div>
<div id="allstyle" class="botom"> <!-- 留言内容区 -->
<h1>发送评论(请正确填写邮箱地址否则将会当成垃圾评论处理)</h1> <div class="message-list">
<el-form :model="form"> <div class="message-item" v-for="msg in messages" :key="msg.id">
<!-- 输入框 --> <div class="message-nickname">{{ msg.nickname }}</div>
<el-form-item > <div class="message-content">{{ msg.content }}</div>
<el-input v-model="form" placeholder="评论内容" type="textarea" /> <div class="message-time">{{ msg.time }}</div>
</div>
<div v-if="messages.length === 0" class="message-empty">还没有留言快来抢沙发吧</div>
</div>
<!-- 留言输入区 -->
<div class="message-form-section">
<h2>发送评论请正确填写邮箱地址否则将会当成垃圾评论处理</h2>
<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> </el-form-item>
</div> </div>
<!-- 按钮 -->
<el-form-item> <el-form-item>
<el-button type="primary" @click="onSubmit">发送</el-button> <el-button type="primary" @click="onSubmit">发送</el-button>
</el-form-item> </el-form-item>
@@ -31,43 +38,128 @@
</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 messages = ref([
{ id: 1, nickname: 'A', content: '这里是A', time: '2025-09-26 10:00' },
{ id: 2, nickname: 'B', content: '这里是B', time: '2025-09-26 10:05' },
{ id: 3, nickname: 'C', content: '这里是C', time: '2025-09-26 10:10' }
])
const form = reactive({ const form = reactive({
name: '', content: '',
region: '', nickname: '',
type: [], email: '',
resource: '', captcha: ''
desc: '',
}) })
const onSubmit = () => { const onSubmit = () => {
console.log('submit!') if (!form.content || !form.nickname) return
messages.value.push({
id: messages.value.length + 1,
nickname: form.nickname,
content: form.content,
time: new Date().toLocaleString()
})
} }
</script> </script>
<style>
.botom{ <style scoped>
padding: 20px; #message_all {
width: var(--content-width);
margin: var(--content-margin);
} }
#allstyle.botom{ .message-header {
margin-top: 10px; background: rgba(102, 161, 216, 0.9);
border-radius: 12px;
padding: 20px 0;
text-align: center;
margin-bottom: 20px;
} }
.botom_form_input{ .message-list {
margin-bottom: 24px;
background: #f8fafd;
border-radius: 12px;
padding: 16px;
min-height: 120px;
}
.message-item {
background: #fff;
border-radius: 10px;
padding: 14px 18px;
margin-bottom: 12px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}
.message-nickname {
font-weight: bold;
color: #409eff;
margin-bottom: 4px;
}
.message-content {
margin-bottom: 4px;
color: #333;
}
.message-time {
font-size: 12px;
color: #aaa;
text-align: right;
}
.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;
}
.form-input-row {
display: flex; display: flex;
gap: 16px;
margin-bottom: 12px;
} }
.botom_form_input .el-form-item{
width: 30%; .form-input-row .el-form-item {
display: block; flex: 1;
} }
.botom_form_input .el-form-item:nth-child(2){
margin: 0 2.5%; .el-form-item .el-input__inner,
.el-form-item .el-textarea__inner {
min-height: 45px;
font-size: 1rem;
} }
.botom_form_input .el-form-item .el-input__inner {
height: 45px; @media (max-width: 768px) {
#message_all {
padding: 8px 0;
}
.message-form-section {
padding: 12px;
}
.form-input-row {
flex-direction: column;
gap: 8px;
}
} }
</style> </style>

View File

@@ -1,7 +1,114 @@
<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: '今天写代码写到怀疑人生bug像是无穷无尽的海洋……',
time: '2025-09-26 09:30'
},
{
id: 2,
content: '前端样式调到崩溃,为什么不同浏览器都不一样!',
time: '2025-09-26 10:12'
},
{
id: 3,
content: 'AI 说得都对,但我还是想摸鱼。',
time: '2025-09-26 11:00'
},
{
id: 4,
content: '有时候觉得自己像个 bug 生产机。',
time: '2025-09-26 13:14'
}
])
</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;
margin: 10px 0 0 0;
}
.aericle-header h1 {
font-size: 1.4rem;
}
.aericle-content {
font-size: 0.98rem;
}
}
</style>