VueJS开发字母分组表格通讯录时新行覆盖其他表格条目问题
Vue按姓氏首字母分组生成联系人表格异常解决
问题场景
VueJS初学者需要实现按姓氏首字母分组的联系人目录,要求每个首字母对应独立表格:
- 表头展示当前分组首字母(如A、B、C)
- 表体展示姓氏以该首字母开头的员工姓名、PhoneCode信息
原有实现逻辑
最初的实现思路分为三步:
- 在Vue实例
created生命周期钩子中调用checkLastNames方法,提取所有员工姓氏首字母,通过Set去重、排序后得到首字母数组arr2 - 调用
createHeader方法遍历arr2,手动动态创建table、thead、tbodyDOM元素追加到容器#vueBody2中,表头展示当前遍历的首字母 - 调用
updateTemp2方法筛选当前首字母对应的员工列表赋值给全局变量temp2,在tbody的innerHTML中写入v-for指令,期望遍历temp2渲染员工行
异常表现
- 所有分组表格的表体都仅渲染最后一个C分组的员工Cuzco, Caitlyn的信息
- 尝试调整方案:给全量员工列表的
v-for添加v-if判断,通过compareIndexes方法比对员工姓氏首字母和当前表头首字母过滤条目,但方法内获取到的表头首字母参数为undefined - 调试发现
updateTemp2的调用日志仅在处理最后一个首字母C时触发,初步怀疑forEach循环中之前生成的innerHTML被后续C分组的循环逻辑覆盖,无法逐个生成A、B、C分组对应的表格行
问题根源
原有实现完全不符合Vue的响应式渲染设计逻辑,核心错误有三点:
- 手动操作DOM写入Vue指令无效:Vue的指令编译只在实例首次挂载阶段执行,后续手动插入到DOM中的带
v-for、v-if的innerHTML只是普通字符串,不会被Vue解析识别,无法实现响应式渲染。 - 全局变量覆盖问题:整个实现只定义了一个全局响应式变量
temp2存储当前分组员工,forEach是同步执行逻辑,循环执行完成后temp2只会保留最后一次赋值的C分组数据,之前插入的所有tbody都绑定同一个temp2,渲染时自然全部显示最后一组内容。 - 上下文丢失问题:手动动态生成的DOM没有经过Vue模板的上下文绑定,循环过程中的首字母参数无法传递到指令对应的方法中,自然会拿到
undefined。
正确实现方案
完全抛弃手动DOM操作的思路,使用Vue原生的两层v-for即可实现需求,代码更简洁且符合响应式设计规范:
第一步:脚本部分处理数据
在Vue的响应式配置中初始化数据,在生命周期钩子中完成首字母提取、排序逻辑,不需要手动操作DOM:
export default { data() { return { // 原始员工列表,每条数据包含id、lastName(姓氏)、name(全名)、phoneCode字段 employeeList: [], // 去重排序后的首字母列表 firstLetterList: [], // 可选:数据量大时提前分组,提升渲染性能 empGroupMap: {} } }, created() { // 替换为实际的员工数据接口请求/本地初始化逻辑 this.employeeList = [ // 示例数据格式 // {id:1, lastName:'Adams', name:'Adams, John', phoneCode:'1001'}, // {id:2, lastName:'Baker', name:'Baker, Alice', phoneCode:'1002'}, // {id:3, lastName:'Cuzco', name:'Cuzco, Caitlyn', phoneCode:'1003'} ] // 提取、去重、排序首字母 const letterSet = new Set() this.employeeList.forEach(emp => { const firstLetter = emp.lastName.charAt(0).toUpperCase() letterSet.add(firstLetter) }) this.firstLetterList = Array.from(letterSet).sort() // 可选:提前按首字母分组,避免模板中重复执行过滤 this.firstLetterList.forEach(letter => { this.empGroupMap[letter] = this.employeeList.filter(emp => { return emp.lastName.charAt(0).toUpperCase() === letter }) }) } }
第二步:模板部分双层循环渲染
直接在模板中通过两层v-for遍历生成表格,不需要任何手动DOM拼接:
<div id="vueBody2"> <!-- 第一层:遍历首字母,每个首字母生成一个独立表格 --> <table v-for="letter in firstLetterList" :key="letter" class="contact-group-table" border="1" cellpadding="8" > <thead> <tr> <th colspan="2">{{ letter }}</th> </tr> </thead> <tbody> <!-- 第二层:遍历当前首字母对应的员工列表,渲染行 --> <!-- 数据量小可以直接内联filter:v-for="emp in employeeList.filter(item => item.lastName.charAt(0).toUpperCase() === letter)" --> <tr v-for="emp in empGroupMap[letter]" :key="emp.id"> <td>{{ emp.name }}</td> <td>{{ emp.phoneCode }}</td> </tr> </tbody> </table> </div>
内容的提问来源于stack exchange,提问作者Tyler P
相关产品推荐
相关产品推荐

