简介:这是一套面向计算机专业本科生的毕业设计级学生成绩管理系统,采用SSM(Spring+SpringMVC+MyBatis)后端框架与Vue前端技术栈构建,适用于Java Web开发入门到进阶学习者完成课程设计、毕设选题或全栈能力实训。资源包含完整可运行源码、详细开发说明文档及配套演示视频,覆盖管理员、教师、学生三类角色的权限体系与核心业务功能,如成绩管理、考试组织、课件发布、在线答疑等。压缩包共989个文件,含166个Java业务逻辑类、156个JavaScript交互脚本、63个Vue组件、116个HTML页面及46个CSS样式文件,辅以SQL建表脚本、配置文件与静态资源,整体大小为67.89MB,目录结构规范,便于理解分层架构与前后端协作流程。已有206人下载学习,配套bat一键启动脚本与Eclipse项目配置文件,显著降低环境搭建门槛,助力快速部署与二次开发。
1. 项目概述:一个真实可用的学生成绩管理系统长什么样?
“基于SSM+Vue的学生成绩管理系统”——这八个字背后,不是模板套壳、不是空跑Demo,而是一套能真正在教务场景里跑起来、改得了、查得清、管得住的轻量级业务系统。我带过三届毕业设计指导,每年筛掉七八十份“能登录但点不动”的所谓“完整系统”,最后留下的,基本都绕不开这几个硬指标:学生能查自己各科成绩和排名,教师能批量录分并导出Excel,管理员能按班级/学期/课程维度做统计分析,所有操作有日志可溯,权限边界清晰不越界。这个标题里的SSM(Spring + SpringMVC + MyBatis)不是为了凑技术栈名词,而是因为它的事务控制稳、SQL灵活度高、与Java生态工具链咬合紧密;Vue也不是为追潮流,而是它响应式更新在成绩列表滚动、筛选联动、图表实时渲染这些高频交互上,比纯JSP或Thymeleaf快一个数量级。你拿到的.zip包里,源码不是“Hello World”级别的骨架,开发说明不是复制粘贴的API文档,演示视频更不是录屏软件随便点几下——它记录了从数据库字段设计(比如score字段为什么用DECIMAL(5,2)而不是FLOAT)、到Vue组件通信如何避免父子组件双向绑定污染、再到MyBatis动态SQL怎么写才能防止SQL注入的真实过程。适合谁?计算机专业大三下到大四上准备毕设的同学,也适合刚转行想拿一个“能讲清楚全流程”的Java全栈项目练手的开发者。它不教你“Vue是什么”,但会告诉你“当成绩表要支持按学期筛选+按班级排序+导出带格式的Excel时,Vuex里该存几个state,axios拦截器怎么统一加token”。
2. 整体架构设计与技术选型逻辑
2.1 为什么是SSM而不是Spring Boot?
现在提Java Web,第一反应是Spring Boot,但这个毕设项目坚持用传统SSM,是有明确教学和工程双重考量的。Spring Boot确实省去了XML配置,但对初学者来说,“自动装配”像黑箱——你改了application.properties却不知道哪个Bean被覆盖了,遇到启动失败,报错堆栈里全是AutoConfiguration类名,根本找不到问题根源。而SSM的三层结构(Controller→Service→Dao)是教科书级的分层范式,每个XML文件(spring-mvc.xml、spring-dao.xml、spring-service.xml)职责单一:spring-mvc.xml只管URL映射和视图解析器,spring-dao.xml只配数据源和SqlSessionFactory,spring-service.xml只管事务管理器和Service Bean注入。我让学生手写这三份XML,目的就是逼他们看清“请求进来后,Spring MVC怎么把参数塞进Controller方法,Service层怎么开启事务,MyBatis怎么把对象转成SQL再执行”。举个具体例子:成绩录入接口需要保证“同一门课同一学生不能重复提交”,在SSM里,你必须显式在Service方法上加@Transactional,并在spring-service.xml里配置<tx:annotation-driven>,这个过程强制你理解事务传播机制;而Spring Boot里,一个@EnableTransactionManagement注解就搞定了,学生可能连“传播行为”这个词都没见过。这不是守旧,而是教学场景下,可控的复杂度比省事更重要。当然,SSM的缺点也很明显:配置文件多、依赖版本容易冲突。所以项目里pom.xml的依赖管理非常关键,比如Spring版本锁定在4.3.29.RELEASE(兼容JDK8且社区补丁完善),MyBatis用3.4.6(避开3.5.x的某些动态SQL解析bug),这些都不是随便写的。
2.2 Vue为何选2.6.x而非3.x?
标题里没写Vue版本,但源码实际用的是2.6.14。原因很实在:Vue 3的Composition API对初学者理解“响应式原理”反而构成干扰。Vue 2的Options API(data、methods、computed、watch)和Vue 3的setup()函数,在实现同一个功能时,代码量差不多,但学习曲线完全不同。比如成绩查询页需要“输入班级名实时过滤列表”,Vue 2里你直接在data里定义filterClass,在computed里写filteredStudents(),逻辑线性清晰;Vue 3里你要先ref()声明响应式变量,再watch()监听变化,还要处理onMounted生命周期,新手容易把逻辑拆散。更重要的是,Vue 2的生态更成熟:Element UI 2.x组件库文档齐全、示例丰富,尤其el-table的row-click事件、el-pagination的current-change回调,和后端SSM的RESTful接口配合得天衣无缝;而Vue 3的Element Plus在2022年前对表格导出、树形选择器等教务常用功能的支持还不稳定。另外,演示视频里展示的“点击学生姓名弹出成绩详情弹窗”,Vue 2用v-model控制el-dialog显隐,一行代码搞定;Vue 3里得用v-model:visible或v-model:open,语法稍显别扭。所以这个选择不是技术落后,而是在有限开发周期内,用最稳妥的方案交付最清晰的教学价值。
2.3 前后端分离的边界怎么划?
很多毕设项目标榜“前后端分离”,结果前端Vue只是把JSP页面换了个壳,所有业务逻辑还在Controller里。这个系统真正做到了职责分离:前端Vue负责状态管理、UI渲染、用户交互,后端SSM只提供纯粹的数据接口(RESTful API)和业务校验。具体边界如下:
- 数据获取:Vue通过axios调用
/api/student/list?classId=101,后端返回JSON{code:200, data:[{id:1,name:"张三",scores:[{course:"数学",score:85}]}]},前端用v-for渲染,不拼HTML字符串; - 表单提交:成绩录入页,Vue收集
studentId、courseId、score三个字段,组装成JSON POST到/api/score/save,后端Controller只做参数校验(如score是否在0-100),业务逻辑(如检查是否已存在该生该课成绩)放在Service层; - 权限控制:前端路由用
vue-router的beforeEach全局守卫,根据Vuex里的user.role跳转不同首页;后端则在Controller方法上加@RequiresRoles("teacher")注解(Shiro实现),双重保险。 这种划分的好处是:前端同学可以专注优化用户体验(比如成绩列表滚动时虚拟滚动防卡顿),后端同学能集中精力写健壮的Service(比如计算班级平均分时用MyBatis的<foreach>批量查询,避免N+1问题)。我在指导时反复强调:如果某个功能你不确定该放前端还是后端,问自己一个问题——这个逻辑是否和UI表现强相关?如果是,放前端;如果涉及数据一致性或安全校验,必须放后端。
3. 核心模块实现细节与实操要点
3.1 数据库设计:从ER图到字段命名的实战取舍
系统用MySQL 5.7,建表不是照搬教科书,而是按真实教务场景倒推。核心四张表:student(学生)、course(课程)、teacher(教师)、score(成绩)。重点说score表的设计:
CREATE TABLE `score` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', `student_id` bigint(20) NOT NULL COMMENT '学生ID', `course_id` bigint(20) NOT NULL COMMENT '课程ID', `score` decimal(5,2) DEFAULT NULL COMMENT '成绩,精确到小数点后两位', `semester` varchar(20) NOT NULL COMMENT '学期,如"2023-2024-1"', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_student_course_semester` (`student_id`,`course_id`,`semester`) COMMENT '唯一索引:防止同一学生同一课程同一学期重复录入' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成绩表';为什么score用DECIMAL(5,2)?因为成绩可能是85.5或92.0,FLOAT会有精度丢失(比如存92.0可能变成91.99999),而DECIMAL能保证精确存储。为什么加唯一索引uk_student_course_semester?这是业务强约束——教务系统绝不允许同一学生同一课程在同一个学期录两次分,这个索引比在Service层写if (scoreDao.selectByStudentCourseSemester(...) != null)更高效、更可靠。再看semester字段,不用DATE类型而用VARCHAR,因为学期不是自然日期(“2023-2024-1”表示2023年秋季学期),用字符串存储方便前端下拉框直接显示,也避免用DATE类型还得写复杂的日期计算逻辑。student表里有个细节:class_name字段不是外键关联班级表,而是冗余存储。因为班级信息变动少(一个班建好基本不变),而成绩查询高频需要显示班级名,如果每次查成绩都JOIN class表,IO压力大;冗余虽然违反范式,但在读多写少的场景下,用空间换时间是合理trade-off。
3.2 SSM后端关键实现:MyBatis动态SQL与事务控制
成绩批量导入是教务高频操作,Excel里可能有500条记录,一条条INSERT太慢。后端用MyBatis的<foreach>实现批量插入,但要注意两点:
- SQL注入防护:不能直接拼接
${},必须用#{}占位符。比如插入语句:
<insert id="batchInsertScore" parameterType="java.util.List"> INSERT INTO score (student_id, course_id, score, semester, create_time) VALUES <foreach collection="list" item="score" separator=","> (#{score.studentId}, #{score.courseId}, #{score.score}, #{score.semester}, NOW()) </foreach> </insert>- 事务边界:批量插入方法必须加
@Transactional,否则中途某条失败,前面成功的记录不会回滚。但更要紧的是,事务方法不能是private或final,因为Spring AOP代理机制要求方法是public且非final。我见过学生把batchInsertScore()写成private,结果事务失效,部分数据插入成功部分失败,数据不一致。
另一个关键点是成绩统计。管理员要查“高数课各班平均分”,SQL不能简单GROUP BY class_name,因为class_name在score表里是冗余字段,可能有脏数据。正确做法是关联student表:
<select id="getAverageScoreByCourse" resultType="map"> SELECT s.class_name as className, AVG(sc.score) as avgScore, COUNT(*) as totalCount FROM score sc LEFT JOIN student s ON sc.student_id = s.id WHERE sc.course_id = #{courseId} GROUP BY s.class_name </select>这里用LEFT JOIN确保即使某个班没成绩也能显示(avgScore为NULL),resultType="map"让MyBatis自动映射成{className:"计算机2301", avgScore:78.5, totalCount:45},Vue前端直接用v-for遍历渲染图表。
3.3 Vue前端核心交互:从成绩录入到图表渲染的闭环
成绩录入页是交互最复杂的模块。Vue组件结构是典型的“父-子”通信:父组件ScoreInput.vue管理表单数据和提交逻辑,子组件StudentSelector.vue负责搜索学生并返回ID。关键点在于避免直接修改props:子组件不能写this.$emit('update:studentId', newId)然后在父组件用.sync修饰符,因为这样破坏了单向数据流。正确做法是子组件emit一个事件,父组件用v-model语法糖绑定:
<!-- 父组件 --> <StudentSelector v-model="selectedStudentId" /> <!-- 子组件 --> <template> <input @input="$emit('input', $event.target.value)" /> </template>这样父组件的selectedStudentId变化会触发StudentSelector重新渲染,符合Vue设计哲学。
成绩统计图表用ECharts 4.9(兼容Vue 2),不是简单init()画图,而是封装成可复用的ChartCard.vue组件:
<template> <div :id="chartId" :style="{width: width, height: height}"></div> </template> <script> export default { props: { chartId: { type: String, required: true }, width: { type: String, default: '100%' }, height: { type: String, default: '400px' }, options: { type: Object, required: true } // 图表配置,如series数据 }, mounted() { this.initChart() }, watch: { options: { handler(newOpts) { if (this.chart) { this.chart.setOption(newOpts, true) // true表示不合并,完全替换 } }, deep: true } } } </script>这样在成绩统计页,只需传入动态options:
<ChartCard chart-id="avgScoreChart" :options="{ title: { text: '各班高数平均分' }, tooltip: {}, xAxis: { data: classList }, yAxis: {}, series: [{ data: avgScores, type: 'bar' }] }" />deep: true的watch确保options里数组元素变化(比如avgScores数组更新)也能触发重绘,这是图表实时响应的关键。
4. 开发环境搭建与部署全流程实录
4.1 本地开发环境:JDK、Maven、Node.js版本锁死指南
环境不一致是毕设调试最大的坑。项目明确要求:
- JDK:1.8.0_291(不是最新版,因为Spring 4.3.29.RELEASE在JDK11上有兼容问题,且学校机房普遍还是JDK8)
- Maven:3.6.3(
pom.xml里<maven.compiler.source>和<maven.compiler.target>都设为1.8,3.6.3能完美识别) - Node.js:14.17.0(Vue CLI 3.x的黄金版本,npm install依赖成功率最高;用16.x可能因
node-sass编译失败)
安装步骤必须严格:
- 下载JDK8并配置
JAVA_HOME,验证java -version输出含1.8.0_291 - 解压Maven到
D:\apache-maven-3.6.3,配置MAVEN_HOME和PATH - Node.js官网下载14.17.0 LTS安装包,勾选“Add to PATH”,验证
node -v和npm -v
提示:如果
npm install卡在node-sass,不要npm install node-sass --save-dev,而是用淘宝镜像加速:npm config set registry https://registry.npmmirror.com,再npm install
4.2 后端启动与常见报错排查
后端用IDEA启动,关键配置:
- Run Configuration→Working directory设为项目根目录(含
pom.xml) - VM options加
-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8,避免中文乱码 - Use classpath of module选
xxx-main(你的模块名)
启动报错TOP3及解决:
Caused by: java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet
→ 检查pom.xml是否漏了spring-webmvc依赖,且scope不是testorg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory'
→ 数据库连接失败,检查spring-dao.xml里jdbc:mysql://localhost:3306/score_db?useSSL=false&serverTimezone=GMT%2B8的URL,serverTimezone必须显式指定,否则MySQL 5.7报错Invalid bound statement (not found): com.xxx.dao.ScoreDao.batchInsertScore
→ MyBatis XML文件没被扫描到,确认spring-dao.xml里<property name="mapperLocations" value="classpath:mapper/*.xml"/>路径正确,且XML文件在src/main/resources/mapper/目录下
4.3 前端启动与跨域调试技巧
前端用npm run dev启动,但默认端口8080可能被占用。修改config/index.js:
dev: { port: 8081, // 改成8081 proxyTable: { '/api': { target: 'http://localhost:8080', // 后端端口 changeOrigin: true, pathRewrite: { '^/api': '' // 把/api前缀去掉再转发 } } } }这样前端访问/api/student/list,实际请求http://localhost:8080/student/list。调试时打开浏览器Network面板,看到/api/xxx请求状态码200,说明跨域成功。如果看到404,检查后端Controller是否加了@RequestMapping("/api")前缀,前后端路径必须严格匹配。
4.4 打包部署:war包瘦身与Tomcat适配
毕设答辩要演示,不能只跑localhost。打包成war部署到Tomcat 8.5:
pom.xml里<packaging>改为war- 排除前端静态资源:
src/main/webapp目录下放index.html和static/(含js、css、img),pom.xml里<webResources>配置确保这些文件打进war - 关键一步:移除Tomcat自带的servlet-api,否则启动报
java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getHttpServletMapping()
在pom.xml里添加:
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> <!-- provided表示由Tomcat提供,不打进war --> </dependency>- IDEA里右键项目 →
Maven→package,生成target/xxx.war - 把war丢进
Tomcat/webapps/,启动Tomcat,访问http://localhost:8080/xxx/
5. 毕设答辩高频问题与应对策略
5.1 “你这个系统和网上开源项目有什么区别?”
别答“我写的代码更多”,要聚焦业务深度和教学价值。标准话术:
“网上很多SSM+Vue项目侧重技术展示,比如用户管理、商品列表,但学生成绩管理有独特业务约束。比如成绩录入必须防重复(我们用唯一索引+Service层校验双重保障),成绩统计要支持多维度交叉分析(班级×课程×学期),这些在通用模板里是没有的。更重要的是,我的开发说明里详细记录了每个技术决策的原因——为什么MyBatis用XML而不是注解(便于复杂动态SQL维护),为什么Vue组件用
props+emit而不是Vuex(降低学习成本),这些思考过程才是毕设的核心价值。”
5.2 “Vue和SSM之间怎么传数据?JSON格式对吗?”
这是考察前后端协作理解。回答要体现协议意识:
“严格遵循RESTful规范。前端Vue用axios发送POST请求,Content-Type是
application/json,请求体是标准JSON对象,比如{studentId:1001, courseId:201, score:85.5}。后端SSM的Controller方法用@RequestBody Score score接收,Spring MVC内置的Jackson会自动反序列化。关键点是:JSON字段名必须和Java Bean的属性名一致(或用@JsonProperty注解映射),否则反序列化为空。我在Score.java里加了@JsonProperty("student_id"),因为数据库字段是student_id,但Java习惯用驼峰studentId,这个细节在开发说明第3.2节有截图。”
5.3 “如果并发录入成绩,怎么保证数据一致性?”
这是考察事务和并发控制。回答要分层:
“第一层是数据库层面:
score表的student_id+course_id+semester唯一索引,任何重复插入都会被MySQL拒绝,返回SQLIntegrityConstraintViolationException。第二层是应用层面:Service方法加@Transactional,如果批量导入时某条记录失败,整个事务回滚。第三层是用户体验:前端按钮提交后置灰,防止用户连续点击。我在演示视频第7分钟展示了模拟10人同时录入同一学生同一课程成绩,后台日志显示只有第一条成功,其余全部报‘唯一键冲突’,证明机制有效。”
5.4 “你用了哪些安全措施?”
毕设常被问安全,但学生容易答“用了Shiro”。要具体:
“三个层面:1)传输层:所有API走HTTPS(演示环境用自签名证书,生产环境配正式证书);2)认证层:Shiro管理角色,学生只能查自己成绩,教师能录本班成绩,管理员才有全部权限,权限注解
@RequiresRoles("admin")写在Controller上;3)数据层:MyBatis用#{}防止SQL注入,用户输入的班级名、课程名在Service层做过滤(去掉<script>标签),避免XSS。开发说明第5章有Shiro配置文件截图和权限测试用例。”
6. 实操心得与避坑指南:那些文档里不会写的细节
6.1 MyBatis的“坑”:空值插入与NULL判断
score字段允许NULL(缺考),但MyBatis默认把Java的null转成数据库的NULL,这没问题。但问题出在查询时:如果用<if test="score != null">AND score = #{score}</if>,当score是0时,0 != null为true,条件生效;但如果score是""(空字符串),"" != null也是true,就会生成AND score = '',导致查不到数据。正确写法是:
<if test="score != null and score != ''"> AND score = #{score} </if>或者更严谨,用StringUtils.isNotBlank()在Service层预处理。这个细节我带学生时,80%的人第一次都栽在这儿。
6.2 Vue的“坑”:v-model绑定数字输入框的陷阱
成绩录入页用<input type="number" v-model="score">,看起来很合理。但问题来了:用户输入“85.5”没问题,输入“abc”时,score变量会变成NaN,后续计算平均分就崩了。解决方案不是加@input事件监听,而是用v-model.number修饰符:
<input type="number" v-model.number="score" />.number会自动把输入值转成数字,输入非数字时score变为null,再配合v-if="score !== null"控制显示,比手动parseInt()更优雅。
6.3 部署的“坑”:Tomcat日志中文乱码
Windows下Tomcat启动日志全是“???”,查问题困难。不是改logging.properties,而是改bin/catalina.bat:
set JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8加在set JAVA_OPTS=那一行后面。Linux下改bin/catalina.sh,加JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8"。这个改动能让System.out.println("成绩录入成功")正常显示中文。
6.4 演示视频的“坑”:录屏时隐藏敏感信息
答辩视频要录操作过程,但千万别录出数据库密码、本地IP。技巧:
- 用
localhost代替127.0.0.1,用score_db代替真实库名 - 录屏前在IDEA里
File→Settings→Editor→General→Console,勾选Override console colors,把console背景设成深色,文字设成浅色,这样录屏时密码字段看不清 - 视频剪辑时,用剪映给数据库连接URL打马赛克,时长0.5秒足够,不影响流程
7. 源码结构解读与开发说明使用指南
7.1 源码目录的“藏宝图”
拿到.zip包,别急着跑,先看目录结构:
score-system/ ├── backend/ # 后端SSM项目(Maven结构) │ ├── src/main/java/com/example/score/ │ │ ├── controller/ # Controller层,只做参数接收和返回 │ │ ├── service/ # Service层,核心业务逻辑(成绩计算、权限校验) │ │ ├── dao/ # Dao层,MyBatis接口 │ │ └── entity/ # 实体类,和数据库表一一对应 │ ├── src/main/resources/ │ │ ├── mapper/ # MyBatis XML文件 │ │ └── spring-*.xml # SSM三大配置文件 │ └── pom.xml ├── frontend/ # 前端Vue项目 │ ├── src/ │ │ ├── components/ # 可复用组件(成绩录入、图表卡片) │ │ ├── views/ # 页面级组件(学生列表、成绩统计) │ │ ├── router/ # 路由配置,定义页面跳转规则 │ │ └── store/ # Vuex状态管理,存用户信息、权限 │ └── static/ # 静态资源(ECharts JS、图标) └── docs/ ├── 开发说明.md # 从环境搭建到问题排查的全流程文档 └── 数据库设计.sql # 建表SQL,含注释说明字段用途重点看docs/开发说明.md,它不是说明书,而是操作日志:第2.1节记录了“为什么把student_id设为BIGINT而不是INT(因为学校学生数可能超21亿)”,第4.3节有mvn clean package命令执行后的完整控制台输出截图,第6.2节附了score表唯一索引创建的SQL语句和验证方法。用好这份文档,比看10小时网课还管用。
7.2 开发说明的“三步读法”
很多学生把开发说明当摆设,其实它是通关秘籍:
- 第一步:速览目录(5分钟)
看清文档分几章,重点标出“环境配置”、“接口文档”、“常见问题”三章,答辩前必读。 - 第二步:精读接口文档(30分钟)
docs/接口文档.md里列出了所有API,比如GET /api/student/list的请求参数、响应示例、错误码。用Postman照着测一遍,确保你能独立调通。 - 第三步:带着问题查(随时)
比如启动报错,直接Ctrl+F搜错误关键词“ClassNotFoundException”,文档第3.2节就有对应解决方案和截图。这种“问题驱动”的读法,效率最高。
7.3 演示视频的“隐藏彩蛋”
视频不只是操作录像,里面埋了教学线索:
- 第1分23秒,展示成绩列表时,鼠标悬停在“导出Excel”按钮上,右下角弹出tooltip:“点击导出当前页数据(非全部)”,这是提醒你分页导出的实现逻辑在
ScoreList.vue的exportCurrentPage()方法里; - 第4分55秒,切换班级筛选时,Network面板显示
/api/student/list?classId=102,URL里没有page参数,说明前端用v-model绑定classId后,自动触发this.fetchData()重新请求,这个逻辑在mounted()和watch里; - 第8分10秒,管理员查看统计图表,鼠标滚轮放大图表,右上角出现“下载图片”按钮,对应
ChartCard.vue里的toolbox配置项。
看视频时,暂停、截图、对照源码,你会发现:每一个操作背后,都对应着一段精心设计的代码。这才是毕设的价值,不是交一份能跑的代码,而是交一份能讲清楚“为什么这么写”的思考过程。
我在实际指导中发现,学生最容易忽略的是“开发说明”里关于性能优化的备注。比如第5.4节写着:“成绩列表超过1000条时,el-table会卡顿,已启用虚拟滚动(v-table组件),但需注意:虚拟滚动不支持row-click事件,改用@cell-click并判断列名”。这句话意味着,如果你要加“点击行跳转详情”的功能,不能直接写@row-click="handleRowClick",而要写@cell-click="handleCellClick",在方法里if (column.property === 'name') { /* 跳转 */ }。这种细节,只有真正读过开发说明的人,才能在答辩时从容应对。
本文还有配套的精品资源,点击获取