feat: 实现文章搜索功能并优化留言系统

- 添加文章标题搜索功能,支持通过路由参数搜索
- 重构留言板组件,优化留言嵌套结构和交互
- 新增评论演示页面展示嵌套留言功能
- 调整主布局样式和导航菜单路由
- 修复留言板样式问题和数据字段不一致问题
This commit is contained in:
qingfeng1121
2025-10-16 16:11:58 +08:00
parent ed09611d02
commit 266310dea3
9 changed files with 501 additions and 33 deletions

View File

@@ -9,7 +9,7 @@
<el-col :span="14" justify="center">
<div class="grid-content ep-bg-purple-dark">
<el-menu :default-active="activeIndex" class="el-menu-demo" :collapse="false" @select="handleSelect">
<el-menu-item index="/:type">
<el-menu-item index="/home">
首页
</el-menu-item>
<el-menu-item index="/article-list">
@@ -28,7 +28,21 @@
</div>
</el-col>
<el-col :span="2" class="search-container" v-if="windowwidth">
<!-- 搜索框可以在这里添加 -->
<!-- 搜索功能 -->
<div class="search-wrapper">
<button class="search-icon-btn" @click="toggleSearchBox" :class="{ 'active': isSearchBoxOpen }">
<i class="el-icon-search">1</i>
</button>
<div class="search-box-container" :class="{ 'open': isSearchBoxOpen }">
<el-input
v-model="searchKeyword"
placeholder="搜索文章..."
class="search-input"
@keyup.enter="performSearch"
@blur="closeSearchBoxWithDelay"
/>
</div>
</div>
</el-col>
</el-row>
</div>
@@ -75,7 +89,14 @@ const isScrollingleftmodlue = ref(false);
const elrowtop = ref('transparent');
const classnonsenset = ref(false);
const windowwidth = ref(true);
const activeIndex = ref('/:type');
const activeIndex = ref('/home');
const localhome= '/home';
// 搜索相关状态
const isSearchBoxOpen = ref(false);
const searchKeyword = ref('');
let searchCloseTimer: number | undefined;
// 打字机效果相关
const fullHeroText = '测试打字机效果';
@@ -107,11 +128,59 @@ const handleSelect = (key: string) => {
router.push({ path: key });
};
/**
* 切换搜索框显示/隐藏
*/
const toggleSearchBox = () => {
isSearchBoxOpen.value = !isSearchBoxOpen.value;
// 如果打开搜索框,清除之前的延时关闭定时器
if (isSearchBoxOpen.value && searchCloseTimer) {
clearTimeout(searchCloseTimer);
}
};
/**
* 关闭搜索框
*/
const closeSearchBox = () => {
isSearchBoxOpen.value = false;
};
/**
* 带延迟关闭搜索框(处理点击搜索按钮后的情况)
*/
const closeSearchBoxWithDelay = () => {
if (searchCloseTimer) {
clearTimeout(searchCloseTimer);
}
searchCloseTimer = window.setTimeout(() => {
isSearchBoxOpen.value = false;
}, 300);
};
/**
* 执行搜索操作
*/
const performSearch = () => {
if (searchKeyword.value.trim()) {
// 这里可以根据实际需求实现搜索逻辑
console.log('搜索关键词:', searchKeyword.value);
router.push({ path: `/home/aericletitle/${searchKeyword.value}`});
}
// 搜索后保持搜索框打开状态
if (searchCloseTimer) {
clearTimeout(searchCloseTimer);
}
};
/**
* 根据路由路径设置页面状态
*/
const updatePageState = (url: string) => {
classhero.value = url !== '/:type';
classhero.value = url !== localhome;
classnonsenset.value = url === '/nonsense';
};
@@ -129,7 +198,7 @@ const handleResize = () => {
windowwidth.value = window.innerWidth > 768;
// 根据屏幕大小调整内容区可见性
if (route.path === '/:type') {
if (route.path === localhome) {
isconts.value = window.innerWidth <= 768 ? true : false;
}
};
@@ -152,7 +221,7 @@ const handleScroll = () => {
}
// 首页内容区滚动动画
if (route.path === '/:type') {
if (route.path === localhome) {
isconts.value = window.scrollY > 200;
isScrollingleftmodlue.value = window.scrollY > 600;
}
@@ -169,13 +238,13 @@ watch(() => route.path, (newPath) => {
window.scrollTo({ top: 0, behavior: 'smooth' });
// 首页内容区滚动动画仅大屏下生效
if (newPath === '/:type') {
if (newPath === localhome) {
isconts.value = window.innerWidth <= 768 ? true : false;
// 首页时启动打字机
startTypewriter();
} else {
isconts.value = true;
heroText.value = '';
heroText.value =fullHeroText;
if (heroTimer) clearInterval(heroTimer);
}
}, { immediate: true });
@@ -185,6 +254,8 @@ watch(() => route.path, (newPath) => {
*/
onMounted(() => {
// 初始化窗口大小
handleResize();
// 添加事件监听器
@@ -203,4 +274,80 @@ onUnmounted(() => {
</script>
<style scoped>
/* 搜索框样式 */
.search-wrapper {
position: relative;
display: flex;
align-items: center;
height: 100%;
}
.search-icon-btn {
background: none;
border: none;
color: #fff;
font-size: 18px;
cursor: pointer;
/* padding: 8px; */
border-radius: 4px;
transition: all 0.3s ease;
}
.search-icon-btn:hover,
.search-icon-btn.active {
background-color: rgba(255, 255, 255, 0.1);
}
.search-box-container {
position: absolute;
right: 100%;
top: 50%;
transform: translateY(-50%);
display: flex;
align-items: center;
background-color: #fff;
border-radius: 4px;
/* box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); */
overflow: hidden;
width: 0;
opacity: 0;
transition: all 0.3s ease;
z-index: 1000;
}
.search-box-container.open {
width: 100%;
opacity: 1;
}
.search-input {
border: none;
outline: none;
width: 100%;
height: 36px;
/* padding: 0 8px; */
border: none;
}
.search-btn,
.close-btn {
background: none;
border: none;
padding: 8px;
cursor: pointer;
color: #606266;
transition: color 0.3s ease;
}
.search-btn:hover,
.close-btn:hover {
color: #409eff;
}
/* 防止搜索框在小屏幕上重叠 */
@media screen and (max-width: 1200px) {
.search-box-container.open {
width: 250px;
}
}
</style>