工作记录(7):评测和排行榜的前端的逻辑实现以及页面实现
一、页面和逻辑主要技术实现
1. QuestionSubmitView.vue
搜索表单实现
这部分实现了一个灵活的搜索界面,允许用户按题号和编程语言进行筛选。使用了 Arco Design 的表单组件,实现了双向数据绑定。当用户输入或选择时,searchParams 会自动更新,触发数据重新加载。这种设计既保证了用户操作的实时响应,又避免了频繁的后端请求。表单布局采用 inline 样式,使界面更加紧凑美观。
<!-- 搜索表单,内联布局 -->
<form>
<!-- 题号输入框 -->
<input v-model="searchParams.questionId" placeholder="请输入题号" />
<!-- 编程语言下拉选择 -->
<select v-model="searchParams.language">
<option>java</option>
<option>cpp</option>
<option>python</option>
</select>
</form>
统计卡片实现
统计卡片部分展示了提交记录的核心指标:总提交数、通过数和通过率。这些数据通过实时计算得出,而不是直接存储,确保了数据的实时性和准确性。通过率的计算考虑了除零情况,确保了显示的稳定性。卡片采用了现代化的设计风格,使用阴影和渐变效果提升视觉体验。
//除零问题
const getAcceptRate = () => {
if (total.value === 0) return 0;
return Math.round((getAcceptedCount() / total.value) 100);
};
提交记录表格
表格实现了提交记录的详细展示,包括提交号、编程语言、判题结果等信息。使用自定义插槽来处理不同状态的显示样式,通过状态显示绿色,错误状态显示红色等。同时实现了时间的格式化显示,提升了数据的可读性。表格支持分页,优化了大数据量的展示性能。

2. RankAcceptedView.vue
排行榜表格实现
这个组件实现了通过题目数量的排行榜功能。表格的实现考虑了分页加载和排名计算的问题。排名序号是基于当前页码和每页条数动态计算的,确保了排名的连续性和准确性。
- 如果接口返回成功,则将数据列表赋值到本地变量。
- 遍历每条数据,根据当前页码和每页数量,计算出全局排名序号(index),用于表格展示。
if (res.code === 0) {
// 更新数据列表
dataList = res.data.records;
// 为每条数据计算排名序号
for (每一条数据 i in dataList) {
dataList[i].index = (当前页码 - 1) * 每页数量 + (i + 1);
}
}
3. RanksPointsView.vue
积分排行实现
积分排行榜的实现与通过题目排行榜类似,但关注点转向了用户积分。这个组件复用了大量 RankAcceptedView 的逻辑,但针对积分排序进行了优化。这种设计既保证了代码的复用性,又维持了功能的独立性。
- 通过接口请求用户列表数据。
- 请求参数包含当前的搜索条件和分页信息。
- 结果按照“积分”字段从高到低排序,便于展示积分排名。
async function loadData() {
// 调用后端接口,传入当前的搜索和分页参数
// 并指定按积分字段降序排序
res = 请求用户列表({
...搜索参数,
排序字段: "points",
排序方式: "descend"
});
}
4. RanksView.vue
布局结构实现
整体页面采用了现代化的布局设计,使用 flex 布局实现左侧边栏和主内容区的响应式布局。左侧边栏固定宽度,主内容区自适应,这种设计在各种屏幕尺寸下都能保持良好的显示效果。
<div class="content-layout">
<div class="winners-sidebar">
<!-- 前三名展示卡片 -->
</div>
<div class="main-content">
<!-- 排行榜标签页 -->
</div>
</div>
动画效果实现
为提升用户体验,实现了丰富的动画效果。包括卡片的滑入动画、悬浮效果等,这些动画都经过性能优化,使用 CSS transform 和 opacity 属性。
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-20px);
}
to { opacity: 1;
transform: translateX(0);
}
}
二、技术难点和解决方案
1.数据同步问题
- 难点:子组件(RankAcceptedView/RanksPointsView)与父组件(RanksView)的数据同步
- 解决方案:使用 emit 事件(update:winners)实现子组件向父组件传递前三名数据,只有在第一页时,才会取出当前数据列表的前三名。只提取每个用户的用户名和通过题数。用事件机制将前三名信息传递给父组件,便于父组件展示获奖信息等。
if (当前页码 === 1) {
// 取出前三名用户的信息
topThree = dataList.slice(0, 3).map(user => ({
userName: user.userName,
acceptedNum: user.acceptedNum
}));
// 通过事件将前三名数据传递给父组件
emit('update:winners', topThree);
}
2.form 表单与searchParams连结
表单数据与搜索参数的双向绑定机制,包括
数据绑定
<a-form :model="searchParams" layout="inline">
- 表单通过 v-model 与 searchParams 对象进行双向绑定
- 当表单输入改变时,searchParams 自动更新
响应式更新
const searchParams = ref<UserQueryRequest>({
pageSize: 6,
current: 1,
});
- searchParams 作为响应式数据
- 当 searchParams 变化时,触发 watchEffect 重新加载数据
搜索触发机制
watchEffect(() => {
loadData();
});
- 监听 searchParams 变化
- 自动触发数据重新加载
这种设计模式实现表单输入与搜索参数的实时同步,搜索条件变化时的自动数据刷新,减少了手动同步数据的代码,提高了代码可维护性。
三、总结
完成了评测记录页面与排行榜页面的前端逻辑和页面实现。评测页面实现灵活搜索表单、动态统计卡片及带状态标识的提交记录表格;排行榜页面构建通过题目数和积分双维度排行系统。在这个过程中解决了子组件与父组件的数据同步问题,通过事件机制传递前三名数据,实现表单与搜索参数的双向绑定与响应式更新。我i学习到了 Vue 3 中组件通信的事件机制应用,掌握了复杂表格数据的动态排名计算方法,对前端的理解更近一步。

784

被折叠的 条评论
为什么被折叠?



