一直想把一大篇的总结写完、写好,感觉自己拖延太严重还总想写完美,然后好多笔记都死在编辑器里了,以后还按照一个小节一个小节的更新吧,小步快跑😂,先发出来,以后再迭代吧。
最近我们参与开发了一个(年前了)BI项目,前端使用vue全家桶,项目功能基本开发完成,剩下的修修补补,开发过程还算顺畅,期间遇到好多问题,也记录了一下,发出来一起交流,主要是思路,怎么利用vue给的API实现功能,避免大家在同样的坑里待太长时间,如果有更好实现思路可以一起交流讨论😎🤗。
前后端分离形式开发,vue+vueRouter+vueX+iviewUI+elementUI
,大部分功能我们都用的iviewUI,有部分组件我们用了elementUI,比如表格、日历插件,我们没接mock工具,接口用文档的形式交流,团队氛围比较和谐,三个PHP三个前端,效率还可以,两个前端伙伴比较厉害,第一次使用vue,就承担了90%的开发工作任务,我没到上线就跑回家休陪产假了,特别感谢同事们的支持,我才能回家看娃。
前端其实不太复杂,但是只要用vue开发基本上都会遇到的几个问题,比如菜单组件多级嵌套、刷新后选中当前项、
涉及几个点,表格表头表体合并、文件上传、富文本编辑器、权限树等等。
项目介绍
系统的主要功能就是面向各个部门查看报表数据,后端同学们很厉害,能汇总到一个集团的所有数据,各种炫酷大数据技术;
菜单功能:
数据看板: 筛选、展示日期和表格分页
业务报表: 报表类型,日期筛选、表格分页
数据检索: 筛选项联动、表格分页
损耗地图: 筛选项、关系图插件
展开分析: 筛选项、分类、卡片、表格
系统信息: 版本发布、步骤条、富文本编辑
数据源上传: 手动上传、表格展示
权限管理: 用户管理、角色管理(权限菜单配置)
项目预览图:
对勾为已更新。
1. 使用v-if解决异步传参
2. 使用$refs调用子组件方法
3. 组件递归实现多级菜单
4. 使用watch监听路由参数重新获取数据
5. 页面刷新后Menu根据地址选中当前菜单项
6. 使用Axios统一状态码判断、统一增加token字段
7. 点击左侧菜单选中项点击刷新页面
8. 使用Axios.CancelToken切换路由取消请求
9. 使用element的table组件实现 表头表体合并
10. iview的Menu组件+vuex实现面包屑导航
11. iview上传组件手动上传与富文本编辑器接入
12. 使用cheerio获取表格数据
13. keep-live组件缓存
14. 先准备数据,再指向
this.data
15. 不要操作单向数据流
16. 禁止浏览器保存密码 回车登录
17. 水印效果
1. 使用v-if解决异步传参组件重绘
大部分的交互的流程都是 “ajax请求数据=>传入组件渲染”,很多属性需要异步传入子组件然后进行相关的计算,如果绑定很多computed或者watch,性能开销会很大,而且有些场景并不需要使用computed和watch,我们只需要在最贱创建的时候获取一次就够了。
如下gif例子,点击上方TAB后重新刷新折线组件:
<mapBox v-if="mapData" :data="mapData">mapBox>
let This = this// setp1 重点this.mapData = falsethis.$http.post('/api/show/mapcondition',{key:key,type:type}).then(function(response){
// setp2 重点 this.mapData = response.data})
有时候会出现DOM元素与数据不同步,可以使用使用其他方式让DOM强刷
- setTimeou- $forceUpdate()- $nextTick()- $set()
2. 使用$refs调用子组件方法
有时候会涉及到父组件调用子组件方法的情况,例如,iview的Tree组件暴露出来的getCheckedAndIndeterminateNodes
方法,详见官网文档link。
<Tree v-if="menu" :data="menu" show-checkbox multiple ref="Tree">Tree>
let rules = this.$refs.Tree.getCheckedAndIndeterminateNodes();
3. 组件递归实现多级菜单
递归组件用的很多,我们的左侧菜单还有无限拆分的表格合并,都用到了递归组件,详见官网链接:https://cn.vuejs.org/v2/guide/components-edge-cases.html#%E9%80%92%E5%BD%92%E7%BB%84%E4%BB%B6
效果图:
大致思路就是先创建一个子组件,然后再创建一个父组件,循环引用,拿左侧菜单说明,代码如下,数据结构也在父组件中。
<template> <Menu width="auto" theme="dark" :active-name="activeName" :open-names="openNames" @on-select="handleSelect" :accordion="true" > <template v-for="(item,index) in items"> <side-menu-item v-if="item.children&&item.children.length!==0" :parent-item="item" :name="index+''" :index="index" > side-menu-item> <menu-item v-else :name="index+''" :to="item.path" > <Icon :type="item.icon" :size="15"/> <span>{
{ item.title }}span> menu-item> template> Menu>template><script>import sideMenuItem from '@/components/Menu/side-menu-item.vue'export default {
name: 'sideMenu', props: {
activeName: {
type: String, default: 'auth' }, openNames: {
type: Array, default: () => [ 'other', 'role', 'auth' ] }, items: {
type: Array, default: () => [ {
name : 'system', title : '数据看板', icon : 'ios-analytics', children: [ { name : 'user', title : '用户管理', icon : 'outlet', children : [ { name : 'auth', title : '权限管理1', icon : 'outlet' }, { name : 'auth', title : '权限管理', icon : 'outlet', children:[ { name : '334', title : '子菜单', icon : 'outlet' }, { name : '453', title : '子菜单', icon : 'outlet' } ]