问题: 菜单管理页面,打开耗时7.8秒
有2200多个菜单, 请求接口返回700k的数据, 领导说返回的数据量太大了, 让改造下.
过程:
尝试一: 想着能少改就少改的原则. 700k你嫌大, 那咱就压缩下数据传输. 修改完之后接口返回数据size60多k, 但是管理菜单打开的时间只优化了一点. 这个压缩传输的博客还没写//TODO
尝试二: 其实线上服务器资源的这个接口, 在命中缓存的情况下查询耗时也不算长, 主要时间耗费在渲染表格上面. 另外结合业务:菜单管理. 只有管理员才有权限,一般是有新功能上线新增菜单, 或者下线菜单, 并没有一次性加载所有菜单的必要.
所以我们将菜单(table)加载改为懒加载. 改需求结合ElementUi组件很容易实现, 可以去查看文档. 大体思路就是 初始化打开页面时只显示第一级菜单, 用户点击展开菜单之后往后端发送请求,然后加载出一级子菜单. 后台只用有一个根据菜单id查询他子菜单的接口就可以
<el-table
:data="tableData1"
style="width: 100%"
row-key="id"
border
lazy
:load="load"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址">
</el-table-column>
</el-table>
data() {
return {
tableData1: [{
id: 1,
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
id: 2,
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}, {
id: 3,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄',
hasChildren: true
//该字段为true的,父菜单才有下级的小箭头可以点击,代表还有子菜单
}, {
id: 4,
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}]
}
}
methods: {
load(tree, treeNode, resolve) { //tree 我们点击的行数据
...调用接口获得改菜单的子菜单
getChildMenu(tree.id).then((res) => { //getChildMenu是我们自己的调用后台的封装
resolve( //resolve是组件的
res.content //根据自己的格式,将查到的子菜单数组填充
)
})
}
}
改完很OK, 秒开, 加载很快. 子菜单加载一次之后就被缓存了,在怎么点击也不会重新去请求后台. 这个也导致了在我们增删改排序等操作菜单之后, 页面对应的菜单节点没有更新, 实际数据已变更. 整体刷新一下页面的话会显示正确, 不过不可能每次更新之后,强制刷新页面吧.
那我们要做的就很清晰了: 修改了哪一行, 就拿到这一行数据的PID, 然后去调用接口,查到这个PID下一级子菜单,查到数据之后塞回去就行了. 接口和页面加载的那个接口是复用的, 无非页面加载的时候PID传的是0.
reflushtable(crud,pid){ //解决菜单懒加载时. 更新,添加,删除 排序不更新的情况
crudMenu.getMenusByPid(pid).then((res) => {
this.$set(this.$refs.table.store.states.lazyTreeNodeMap, pid, res.content)
})
},
//this.$refs.table 注意这个table是你的table属性:ref的名字.
//没有一丝丝技巧, 全靠面向搜索引擎, 这玩意藏那么深谁能找到^^
剩下的就根据自己的实现, 在新增,删除,编辑方法之后,或钩子之后. 去拿父ID查数&set.
在提一嘴 如果有批量删除功能的话, 要注意拿PID循环调用下, 要不然会存在刷新不到的地方. 当然最好将PID去重下.