You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bloggingplatform/src/views/HomeView.vue

480 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<el-container class="home">
<!-- 头部 -->
<el-header class="header">
<el-row type="flex" justify="space-between" align="middle" style="width:100%;">
<el-col :span="6" class="logo-container">
<img src="@/assets/logo.png" alt="Logo" class="logo">
</el-col>
<el-col :span="12" class="search-col">
<el-input placeholder="搜索..." prefix-icon="el-icon-search" size="large" class="search-input"></el-input>
</el-col>
<el-col :span="6" class="auth-buttons">
<div class="auth-content">
<div v-if="!isLogin">
<el-button link @click="handleLogin" class="login-button">登录</el-button>
<el-button type="primary" @click="handleRegister" class="register-button">注册</el-button>
</div>
<div v-else>
<el-link type="primary" :underline="false" @click="gotoHome" class="username-link">
管理员
</el-link>
<el-link type="primary" :underline="false" @click="gotoHome2" class="username-link">
</el-link>
<el-button type="danger" @click="handleLogout" class="logout-button">退出登录</el-button>
</div>
</div>
</el-col>
</el-row>
</el-header>
<!-- 轮播图 -->
<el-container>
<el-main>
<el-carousel trigger="click" height="400px" arrow="always" class="carousel">
<el-carousel-item v-for="(item, index) in images" :key="index">
<img :src="item" class="carousel-img" />
</el-carousel-item>
</el-carousel>
</el-main>
</el-container>
<!-- 文章内容部分 -->
<el-container class="content-container">
<el-aside width="400px" class="sidebar">
<h3 class="section-title">最新文章</h3>
<el-menu class="menu">
<el-menu-item v-for="post in latestPosts" :key="post.id">
<router-link :to="'/post/' + post.id" class="link-item">{{ post.title }}</router-link>
</el-menu-item>
</el-menu>
<h3 class="section-title">热门文章</h3>
<el-menu class="menu">
<el-menu-item v-for="post in popularPosts" :key="post.id">
<router-link :to="'/post/' + post.id" class="link-item">{{ post.title }}</router-link>
</el-menu-item>
</el-menu>
<h3 class="section-title">推荐文章</h3>
<el-menu class="menu">
<el-menu-item v-for="post in recommendedPosts" :key="post.id">
<router-link :to="'/post/' + post.id" class="link-item">{{ post.title }}</router-link>
</el-menu-item>
</el-menu>
<el-divider></el-divider>
</el-aside>
<el-main class="posts-container">
<div v-for="post in posts" :key="post.id" class="blog-post">
<router-link :to="'/post/' + post.id">
<h3>{{ post.title }}</h3>
</router-link>
<p><strong>Author:</strong> {{ post.author }} | <strong>Published:</strong> {{ post.date }}</p>
<p>{{ post.excerpt }}</p>
</div>
</el-main>
</el-container>
<!-- 底部 -->
<el-footer class="footer">
<span>&copy; 2024 My Blog. All rights reserved.</span>
</el-footer>
</el-container>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useUserStore } from '../stores/user';
import { IUserInfo } from '../model/model';
import img1 from '@/assets/carousel/1.jpg';
import img2 from '@/assets/carousel/2.jpg';
import img3 from '@/assets/carousel/3.jpg';
import img4 from '@/assets/carousel/4.jpg';
import img5 from '@/assets/carousel/5.jpg';
import img6 from '@/assets/carousel/6.jpg';
const images = ref([img1, img2, img3, img4, img5, img6]);
const posts = ref([
{ id: 1, title: 'Vue 3 入门教程', author: 'John Doe', date: '2024-11-29', excerpt: '这是一篇关于 Vue 3 的入门教程,适合初学者阅读。' },
{ id: 2, title: 'Vue 3 响应式系统解析', author: 'Jane Doe', date: '2024-11-28', excerpt: '深入浅出地解析 Vue 3 中的响应式系统。' },
{ id: 3, title: 'Vue 3 性能优化技巧', author: 'Alice Smith', date: '2024-11-27', excerpt: '如何在 Vue 3 中实现性能优化,提升应用效率。' },
{ id: 4, title: 'Vue 3 Composition API 实战', author: 'Bob Brown', date: '2024-11-26', excerpt: '详细讲解 Vue 3 的 Composition API 并通过案例演示。' },
{ id: 5, title: 'Vue 3 路由详解', author: 'Carol White', date: '2024-11-25', excerpt: '讲解如何在 Vue 3 中配置和使用 Vue Router。' },
{ id: 6, title: 'Vue 3 状态管理Pinia vs Vuex', author: 'Dave Black', date: '2024-11-24', excerpt: '比较 Vue 3 中的 Pinia 和 Vuex帮助你选择最适合的状态管理工具。' },
{ id: 7, title: 'Vue 3 与 TypeScript 的完美结合', author: 'Eve Green', date: '2024-11-23', excerpt: '教你如何在 Vue 3 中使用 TypeScript 开发应用。' },
{ id: 8, title: 'Vue 3 表单验证最佳实践', author: 'Frank Blue', date: '2024-11-22', excerpt: '介绍如何在 Vue 3 中进行表单验证,提升用户体验。' },
{ id: 9, title: 'Vue 3 与 Webpack 配置优化', author: 'Grace Purple', date: '2024-11-21', excerpt: '讲解如何优化 Vue 3 与 Webpack 配合使用时的配置。' }
]);
const latestPosts = ref([
{ id: 1, title: '如何使用 Vue 3 构建高效的前端应用' },
{ id: 2, title: '深入浅出 Vue 3 响应式系统' },
{ id: 3, title: 'Vue 3 中的 Composition API 使用技巧' },
]);
const popularPosts = ref([
{ id: 4, title: 'Vue 3 性能优化实战' },
{ id: 5, title: '如何构建 Vue 3 + TypeScript 项目' },
{ id: 6, title: 'Vue 3 Router 动态路由实践' },
]);
const recommendedPosts = ref([
{ id: 7, title: 'Vue 3 状态管理Pinia vs Vuex' },
{ id: 8, title: '如何在 Vue 3 中使用 Vue CLI' },
{ id: 9, title: '从 Vue 2 到 Vue 3升级指南' },
]);
const router = useRouter();
const userStore = useUserStore();
const currentUser = reactive<IUserInfo>({ username: '', nickname: '', signature: '', phone: '', birthday: '', isAdmin: false, password: '' });
const isLogin = ref(false);
const init = () => {
const user = userStore.getCurrentUser();
if (user) {
currentUser.username = user.username || '';
currentUser.nickname = user.nickname || '';
currentUser.signature = user.signature || '';
currentUser.phone = user.phone || '';
currentUser.birthday = user.birthday || '';
currentUser.isAdmin = user.isAdmin || false;
currentUser.password = user.password || '';
isLogin.value = true;
} else {
isLogin.value = false;
}
};
onMounted(() => {
init();
});
const handleLogin = () => {
router.push({ "name": "Login" });
};
const handleRegister = () => {
router.push("/register");
};
const handleLogout = () => {
userStore.logoutUser();
init();
router.push("/");
};
const gotoHome = () => {
//if panduan
router.push("/admin");
};
const gotoHome2 = () => {
//if panduan
router.push("/user");
};
</script>
<style scoped>
/* 页面基础样式 */
.home {
height: 100%;
width: 100%;
font-family: 'Arial', sans-serif;
background-image: url('@/assets/bg1.jpg'); /* Path to your background image */
background-size: cover; /* Ensures the image covers the entire page */
background-position: center; /* Centers the image */
background-repeat: no-repeat;
/* 设置背景色 */
overflow-x: hidden;
/* 防止内容横向溢出 */
}
/* Header 样式 */
.header {
height: 100px;
background-color: rgba(255, 255, 255, 0.8);;
border-bottom: 1px solid #ddd;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding: 0 20px;
display: flex;
align-items: center;
justify-content: space-between;
/* 确保元素分布 */
overflow: hidden;
}
.logo {
height: 120px;
object-fit: contain;
overflow: hidden;
/* 防止 logo 超出容器 */
}
.search-input {
width: 100%;
border-radius: 20px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
padding: 10px 20px;
font-size: 16px;
}
/* 登录注册按钮 */
.auth-buttons {
display: flex;
justify-content: flex-end;
align-items: center;
}
.login-button,
.register-button,
.logout-button {
margin-left: 15px;
}
.username-link {
margin-right: 15px;
}
/* 轮播图样式 */
.carousel {
margin-bottom: 20px;
overflow: hidden;
/* 遮住轮播图超出的部分 */
}
.carousel-img {
width: 100%;
height: 400px;
object-fit: cover;
border-radius: 8px;
max-height: 100%;
/* 确保图片不会溢出容器 */
}
/* 内容容器 */
.content-container {
display: flex;
justify-content: space-between;
margin-top: 20px;
padding: 0 20px;
}
.sidebar {
background-color: rgba(255, 255, 255, 0.8);;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
width: 280px;
/* 控制侧边栏的宽度 */
overflow: hidden;
/* 遮住超出部分 */
}
.menu {
background-color: rgba(255, 255, 255, 0);;
margin-bottom: 15px;
}
.section-title {
font-size: 20px;
color: #333;
margin-bottom: 10px;
border-bottom: 2px solid #ddd;
padding-bottom: 10px;
font-weight: 600;
word-wrap: break-word;
/* 防止标题溢出 */
white-space: normal;
/* 保证标题文本正常换行 */
overflow: hidden;
/* 遮住超出部分 */
}
.link-item {
text-decoration: none;
color: #333;
font-size: 16px;
transition: color 0.3s ease, padding-left 0.3s ease;
display: block;
/* 使链接成为块级元素 */
padding: 8px 0;
/* 给链接增加上下内边距 */
overflow: hidden;
/* 遮住超出部分 */
}
.link-item:hover {
color: #1a73e8;
padding-left: 10px;
}
/* 帖子列表容器 */
.posts-container {
flex: 1;
padding: 20px;
background-color:rgba(255, 255, 255, 0.8);;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
/* 遮住超出部分 */
}
/* 博客文章样式 */
.blog-post {
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid #ddd;
padding-left: 20px;
padding-right: 20px;
overflow: hidden;
/* 遮住超出部分 */
transition: background-color 0.3s ease, transform 0.2s ease;
}
.blog-post:hover {
background-color: #f9f9f9;
/* 鼠标悬浮时背景色变化 */
transform: translateY(-5px);
/* 鼠标悬浮时向上浮动 */
}
/* 文章标题样式 */
.blog-post h3 {
font-size: 22px;
color: #1a73e8;
margin-top: 10px;
margin-bottom: 10px;
transition: color 0.3s ease;
word-wrap: break-word;
/* 防止标题溢出 */
white-space: normal;
/* 保证标题文本正常换行 */
overflow: hidden;
/* 遮住超出部分 */
}
.blog-post h3:hover {
color: #0066cc;
/* 悬浮时标题颜色变化 */
cursor: pointer;
}
/* 文章元数据样式 (作者和发布时间) */
.blog-post p {
color: #555;
font-size: 14px;
line-height: 1.6;
margin: 5px 0;
}
.blog-post p strong {
font-weight: 600;
color: #333;
}
/* 文章摘要样式 */
.blog-post .excerpt {
color: #666;
font-size: 16px;
line-height: 1.8;
margin-top: 10px;
display: -webkit-box;
-webkit-line-clamp: 3;
/* 限制显示的行数 */
-webkit-box-orient: vertical;
overflow: hidden;
/* 超出的部分隐藏 */
text-overflow: ellipsis;
/* 省略号 */
}
.blog-post .excerpt:hover {
text-decoration: underline;
/* 悬浮时摘要增加下划线 */
}
/* 响应式布局:适应小屏幕 */
@media (max-width: 768px) {
.posts-container {
padding: 10px;
}
.blog-post {
padding-left: 10px;
padding-right: 10px;
}
.blog-post h3 {
font-size: 20px;
}
.blog-post p {
font-size: 13px;
}
}
/* Footer 样式 */
.footer {
background-color: #ffffff;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
color: #333;
font-size: 14px;
border-top: 1px solid #ddd;
}
.footer span {
padding: 10px;
}
/* 响应式布局:适应小屏幕 */
@media (max-width: 768px) {
.header {
height: 80px;
}
.logo-container {
display: block;
text-align: center;
}
.content-container {
flex-direction: column;
}
.sidebar {
width: 100%;
margin-bottom: 20px;
}
.posts-container {
width: 100%;
}
.carousel-img {
height: 300px;
}
.menu {
padding: 0 10px;
}
}
a {
text-decoration: none;
}
</style>