推广后台项目复盘
需求评审
需求评审时产品经理会根据原型讲述产品需求,这时就应该认真听了,稍一分心就可能漏掉重要的点,不然之后还得老老实实去找产品问,当产品经理讲完后台原型需求时,看着就几个页面,而且页面功能点还都差不多,登录也不用做(后来还是要做的),不过我还是很懵的,用vue脚手架怎么搭项目、单张图片上传、多张图片上传、排序、富文本编辑器、列表里的操作项怎么不一样等等问题,这些功能需求都不会怎么办,以前都没接触过啊,这怎么做项目啊,不会刚上来就灰溜溜的下去吧,只能硬着头皮上一点一点学,对需求不理解的地方多问问产品,自己多分析分析原型,理解好了原型需求才好开展下一步啊
设计排期
需求评审完了之后就得设计排期和写后台设计文档了,设计文档也不知道写啥啊,哪些内容要写进设计文档中呢,不懂就要多问啊,设计文档中最基本得要有项目的页面设计方案,有特殊要求的功能点最好标注一下,项目开发时要着重注意,还要有路由设计、以及我认为 很重要的接口设计,接口设计的好坏决定了在开发后你能不能请求到数据,这个很重要,最好前后端都弄一下接口设计,开技术评审会议的时候就不会是接口设计方案后端说了算,不能满足需求的自己也能及时说出来,避免最后因为接口没设计好功能需求实现不了,此外还可以写一下公共组件(富文本编辑器、上传图片等)、公共方法(时间格式、防抖等)、复杂的交互流程(批量操作)的设计,当然这些我之前都是没写的,一开始什么都不知道啊,有能力的可以根据原型先写好一下,开发的时候直接用就行了
技术评审
技术评审我们需要叫上对应的干系人一起讨论。可以讲一下自己写的设计文档,特殊的功能需求应着重讲一下,让大家一起来评审一下设计是否合理,自己迷惑的点也需及时提出来,让大家一起帮忙参考一下。与后端一起讨论的主要是接口,这时你就可以拿起你自己写的接口文档和后端写的对照一下了,有疑问的点一定要提出来,接口设计的不对,这会很影响你后续的开发。如果涉及到UI的话还会有一个UI评审会,像h5这样的就有,后台就没有UI,后台布局的不要太难看就行了。
开发排期
技术评审完了就是开发排期了,开发排期我们需要做的详细一些,功能点切割的尽量细,每个功能点的开发时间最多不要超过0.5d,这个最好根据自己的能力来排期,相对来说简单些的功能点时间少点,复杂一些的时间就长点,自己也不确定的那就长点吧,得给自己留下充足的开发时间,万一卡在哪了,也有足够的时间处理啊,这样排期下来就可以确定整个开发周期了,确定项目开始开发时间和结束时间,当然排期出来后,最长开发路径也就出来了,不巧我很幸运,最长路径就在我这,我预估的开发周期是13.5d,这也就意味着h5和后台项目的开发周期也就是最长路径的开发周期13.5d了。整个开发时间=开发+自测+联调+紧急线上问题处理。
项目开发
到了这一步也就正式进入敲代码的阶段了,当然,项目开发之前你得了解一下代码规范 ,主要看一下项目目录结构规范、VUE开发规范、Git规范,不然等Code Review之后有你要改的地方,平时就得按规范来写代码,养成良好的习惯,然而我就是个反面例子,很多没按规范来,后期修改的点那也就特别多了。了解这些规范后,项目开发就开始了,按项目目录结构规范用vue脚手架开始搭建项目,然后就是给项目配置各种环境了,安装项目需要用到的各种API依赖,后台项目主要用到的API有ElementUI组件,sortablejs(排序),ali-oss(图片上传阿里云),vue-quill-editor(富文本编辑器),这些基本工作都做好后,就可以开始根据原型需求进行功能点开发了。当然,项目开发后每天记得按Git规范提交一次代码,并写好注释,越详细越好,增加了什么新功能、修改了什么、删除了什么等,这样就可以在代码出错后快速定位到问题所在之处了,项目开发完了海哥帮着CodeReview,之后和后端联调测试接口返回数据,也就从这开始改bug了,bug一个接一个,让你每天都能过得很充实,联调后自测,bug改得差不多就可以提测了,项目开发阶段也就完成了。
项目开发踩坑点
• 开发规范:平时开发时没有按照代码规范做,Code Review时,很多代码不规范,一个一个页面修改需花很长时间
• 单文件组件应该总是让顶级标签的顺序保持一致,且标签之间留有空行
• vue页面标签中第一个类的命名应见名知意,如class=“login”,一看就知道这是登录页面
• JS文件 export default { } 中 name: ‘Login’ 写在最前并且首字母大写
• style样式标签中有 scoped 属性,防止造成样式污染,影响其它页面
• 在单文件组件中没有内容的组件应该是自闭合的。
• 标签的指令、属性和事件超过 3 个时,换行书写;小于等于3个时,一行书写
• 组件选项顺序
• input框加一个clearable属性,快速清空数据,加一个trim属性,消除空格,提高用户体验
…
VUE开发规范:https://www.yuque.com/cths8s/gnpxww/pob6dv
项目目录结构规范:https://www.yuque.com/cths8s/gnpxww/cuog19
Git规范:https://www.yuque.com/cths8s/gnpxww/tvz8zp
• API接口:接口是什么?接口有什么用?为什么要定义接口?怎么调接口?一开始什么都不知道
API是一些预先定义的接口(如函数、HTTP接口),通俗点说就是用来实现前后端数据交互的,开发过程中我们都是通过定义好的接口mock数据的(自己模拟的数据,都是假的数据),当开发完了之后,前后端进行联调,就会干掉mock的数据而使用真实的数据,这时你可能会发现,调接口mock数据还是好好的,怎么联调一使用真实数据就请求不到数据呢,造成这种情况的可能性就多了,前端代码有问题、请求参数多了或少了、请求参数格式不对、接口命名或者参数命名错误、请求方法用错了等,如果发现前端这一切都没问题的话,那问题就一定在后端了,直接把问题提给后端,让后端解决就行了。
接口配置及使用:config.js–>setup.js–>login.js–>index.js–>main.js–>login.vue文件中调接口,这是前端接口配置以及使用的一个具体流程,具体代码就不贴了。。。
请求参数
• 当请求参数小于等于三个时,用get请求方法,请求参数写在params中,会直接拼接在URL上
params参数拼接在URL后 currentPage=1&pageSize=10
http://promotion-oms.dev1.server.sdh-dev.com/web/banner/queryBanners?currentPage=1&pageSize=10
• 当请求参数大于三个时,用post请求方法,请求参数写在请求体body中,以JSON格式书写
body请求体中 {“productStatus”:1,“startTime”:null,“endTime”:null,“currentPage”:1,“pageSize”:10}
http://promotion-oms.dev1.server.sdh-dev.com/web/product/queryProduct
• 最后都是以post请求方法,调用接口(会做处理)
• layout页面布局遇到了一些问题,菜单栏的隐藏与展开,隐藏后菜单栏宽度还是没变,最后发现给el-menu加上collapse属性后,还得给侧边栏el-aside也加上 :width=“isCollapse ? ‘64px’ : ‘200px’” 才能够实现菜单栏的隐藏与展开;给el-menu加router属性,可以使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转,我这里菜单栏就只有Banner管理、商品管理、公告管理三个模块,就直接采用写死的了,按理来说菜单栏也应该定一个接口动态获取菜单项的,具体怎样做可以和后端商量,就是多一个接口的事;还有就是我使用active-text-color 属性 当前激活菜单的文字颜色,刷新后当前菜单又没有激活时的颜色了,使用:default-active="
r
o
u
t
e
.
p
a
t
h
"
当
前
激
活
菜
单
的
i
n
d
e
x
,
显
示
文
字
颜
色
就
可
以
完
美
解
决
这
个
问
题
了
。
•
打
开
弹
窗
:
我
之
前
弹
窗
的
方
式
是
模
仿
宇
石
官
网
后
台
使
用
r
e
f
直
接
操
作
D
O
M
实
现
弹
窗
关
闭
功
能
的
(
不
推
荐
)
V
u
e
不
推
荐
开
发
者
直
接
操
作
d
o
m
:
破
坏
了
代
码
模
块
化
结
构
导
致
代
码
腐
化
;
过
多
的
直
接
操
作
d
o
m
行
为
增
加
了
代
码
的
耦
合
性
;
操
作
不
属
于
自
己
的
d
o
m
时
,
d
o
m
状
态
无
法
预
知
<
a
d
d
−
p
r
o
d
u
c
t
r
e
f
=
"
a
d
d
p
r
o
d
u
c
t
"
/
>
t
h
i
s
.
route.path" 当前激活菜单的 index,显示文字颜色 就可以完美解决这个问题了。 • 打开弹窗:我之前弹窗的方式是模仿宇石官网后台使用ref直接操作DOM实现弹窗关闭功能的(不推荐) Vue不推荐开发者直接操作dom:破坏了代码模块化结构导致代码腐化;过多的直接操作dom行为增加了代码的耦合性;操作不属于自己的dom时,dom状态无法预知 <add-product ref="addproduct" /> this.
route.path"当前激活菜单的index,显示文字颜色就可以完美解决这个问题了。•打开弹窗:我之前弹窗的方式是模仿宇石官网后台使用ref直接操作DOM实现弹窗关闭功能的(不推荐)Vue不推荐开发者直接操作dom:破坏了代码模块化结构导致代码腐化;过多的直接操作dom行为增加了代码的耦合性;操作不属于自己的dom时,dom状态无法预知<add−productref="addproduct"/>this.refs.addproduct.addProductStatus = true
• 现在 使用v-model value方式 推荐
this.showAddDialog = true
• 分页pagination:分页是很常用的一个组件,很多有列表项的页面都会使用到,可以将它封装起来,在需要的页面直接引入就行了,也可以直接拿来用不需要封装,只不过每次都得重写一遍,现阶段根据自己的能力选择就行了,这个组件主要用到size-change和current-change两个方法,就可以知道当前页和每页条数了。
• 封装:封装组件,封装方法,在前端项目中时很常见的,例如封装一个分页pagination组件、上传图片组件、富文本编辑器组件等,封装一个时间格式转换方法、防抖函数等,这里写一个封装时间格式转换方法:
a. 在工具函数utils文件夹下建一个formatters.js文件封装 (封装文件名字自己随便取)
// formatter 时间格式
const formatters = {
formatterDate (row, column, cellValue, index) {
…
}
}
export default formatters
a. 然后 通过 export default formatters 导出
b. 在main.js文件中导入 挂载到原型 进行全局定义,在需要使用到这个方法的页面直接使用 (你也可以不用全局定义,在使用到的页面引入也行)
import formatters from ‘./utils/formatters’
/ vue原型挂载 - 时间格式函数
Vue.prototype.formatters = formatters
a. 在需要使用时间格式的地方 :formatter=“formatters.formatterDate”
• 时间格式:时间格式的转换也是很常用的,这里需要注意的是后端传过来的是10位时间戳,和以往的13位时间戳不同,我们这时需要做一层处理,将后端传过来的时间戳*1000然后通过时间戳转年月日时分秒展示出来就好了。需要用到时间的页面也很多,这时就可以将时间格式转换的这个方法封装起来,在用到的页面直接引入就行。
• el-date-picker时间控件:在用这个时间控件时遇到了一些问题,应用场景为商品创建时间和结束时间的选择,创建时间不能大于结束时间,布局时就碰到问题,原型上在两者间有一横杠,element组件中都是对称的,拿过来用就变不对称的了,调了好久样式终于对称了,最后又因为这个页面input框和按钮大小和其它页面不一样以及排版问题,直接把这个横杆给干掉了,白忙活一场。这时还没结束,要实现创建时间不能大于结束时间,需要picker-options属性和value-format=“timestamp”,“timestamp"这个是以13位时间戳传值的,但后端要的是10位时间戳,处理一下/1000就好了,还是没怎么简单,结束时间后端那是按年月日算的,这就导致搜索6号结束时间,实际搜索的是5号的时间,还得做一层处理,给传过去的结束时间加一天86400s,这样才是正确的搜索结束时间,
结束时间:(this.searchParams.endTime) / 1000 + 86400
• 防抖函数:在后台项目进行测试时,连续点击请求按钮,造成多次请求接口问题,这就是一个bug了,同时,这也是一个性能优化的问题,点击按钮,只调一次接口,而防抖函数刚好能做到这一点,防止用户多次重复点击请求数据,在连续的操作中,无论进行了多长时间,只有某一次的操作后在指定的时间内没有再操作,这一次才被判定有效。这个函数防抖方法也是可以封装的,因为请求数据的接口太多了,要是有一个接口就写一个这个方法,那也就太费时了,封装好后引入使用不好吗,多简便啊
• 排序:后台Banner模块有一个拖动排序功能,这时就需要安装一个插件Sortable.js,这是一款轻量级的拖放排序列表的js插件(虽然体积小,但是功能很强大),项目需求是要求能对element中 的table表格进行进行拖拽行排序,安装好后引入,这里注意,给el-table加上 row-key=“bannerId”,否则拖动是无效的,然后需要在在watch中实现拖拽方法 Sortable.create, querySelector(’.sortTableClass .el-tablebody-wrapper tbody’),其中,’.sortTableClass’这个类是自己定义的, ’ .el-tablebody-wrapper tbody’这个是固定的。
• el-select使用:应用场景为商品管理下拉框选择操作系统,我当时是直接使用element组件中的el-select
• 操作系统选项是固定的,就‘安卓-QQ’,“安卓-微信”,“苹果-QQ”,“苹果-微信"四个,这时的值是静态的 值不变化,而使用以上方式是适配绑定动态变量的,用这个我们还得在data中定义一个operationSystemList,这又增加了工作量,不推荐使用
修改后 静态 值不变化,都是已知的选项值,用label和value就行了 (值固定已知时 推荐使用)
• el-select绑定动态变量:根据后台的数据生成多个select,由于数据的数量不定,所以v-model绑定的变量名也不定。所以通过数据的
id进行变量拼接。https://blog.csdn.net/qq_25610165/article/details/89030906
• input输入框,type为number时,输入框中会有一个小箭头,这个小箭头是type为number类型时自带的,显然,为了更好的用户体验,我们需要将这个小箭头个干掉,不过根据浏览器环境不同,去除小箭头方法也会不同
//在Firefox浏览器下
.searchBox input[type=“number”]{
-moz-appearance: textfield;
}
//在Chrome浏览器下
.searchBox .deal::-webkit-inner-spin-button {
-webkit-appearance: none;
}
.deal::-webkit-outer-spin-button {
-webkit-appearance: none;
}
• 还有更多的浏览器环境,自己可以去查一下去除方法
• input输入框无法输入:这个问题出现的应用场景是给商品添加信息时,input框出现各种问题,不能输入、校验不通过,时而能输时而不能输,其实造成这个问题的原因就是在初始化绑定值得时候,给 商品信息productInfo: {}一个 空对象,由于每一个item的
v-modle =“productInfo.productTitle”,在编辑回显的时候触发了校验规则,但是productInfo.name这个属性找不到,所以就报错了,就这么简单啊,解决方法就是,在productInfo对象中对每一个字段进行初始化,虽然商品信息也就20来个字段,但也不能偷懒啊,一个个在productInfo对象中初始化就好了 如果遇见各种校验问题首先检查: • :model="productInfo" 绑定的productInfo值是否挂载成功并且操作的是否是这个表单。 • :rules="rules" 校验的规则格式绑定的rules是否定义并且格式正确为对象数组。 • el-form-item中的prop="productTitle"是否和rules中的productTitle: [{ required: true, message: '请输入标题', trigger: 'blur' }]
的名称一致,两个productTitle是相同的,element的校验就是根据这个prop找对应的输入框的。
• 的v-model=“productInfo.productTitle"确保对象productInfo中有productTitle这个属性!
关于表单校验的大部分bug的原因就是这四步绑定的值有问题,完全都是细心问题!!!
• 根据状态 已上架 已下架 操作栏中 显示不同操作类型
根据不同状态,显示不同操作,这个是怎么做到的呢,刚看到原型的时候,我是很疑惑的,怎么做到的,实现了这个功能后会发现,其实很简单吗,根据状态,使用v-if做一个简单的判断就能实现,就怎么简单,v-if=“scope.row.productStatus !== 2”
• 批量操作:批量上架、批量下架、批量删除:批量操作处理逻辑就比较复杂了,考虑的情况也多了,这时“审题”就很重要了,我就因为没理解批量操作需求,不知道在这里面绕了多久。
• 批量删除: 当未勾选时批量删除提示“请选择要删除的商品”,有勾选时先进行二次确认Alert提示"确定要全部删除吗”“删除”“取消”。 点击删除后,提示"删除成功”。选中商品包含已上架商品时,toast提示"不可删除已上架商品,请重新选择”,注意,这时多选框还是选中状态,当掉完接口后,就应该将勾选状态清空,下面操作同理。使用selection-change方法就可判断勾选状态,
clearSelection()方法可清空勾选状态。
• 批量上架: 当未勾选时批量删除提示“请选择要上架的商品”,有勾选时先进行二次确认Alert提示"确定要全部上架吗"“上架”“取消”。 点击上架后,提示"上架成功"。选中商品有已上架商品时,不做任何操作,过滤已上架商品,只对下架商品进行上架操作
• 批量下架: 当未勾选时批量删除提示“请选择要下架的商品”,有勾选时先进行二次确认Alert提示"确定要全部下架吗"“下架”“取消”。 点击下架后,提示"下架成功"。选中商品有已下架商品时,不做任何操作,过滤已下架商品,只对下架商品进行下架操作
• 富文本编辑器:富文本编辑器会在公告管理模块中使用到,它也是一个插件,是需要安装的,现阶段有很多好用的富文本编辑器插件,可以根据自己的喜好选择一个就好了,我这里使用的是vue-quill-editor,先安装,然后封装好,在需要使用的地方引入就行,我使用的时候发现一些问题,部分功能没有效果,如斜体,x^2没得用,我也没找到为什么没有效果的原因,就只好干掉了。还有一个问题就是富文本编辑器上传图片的格式是base64的,这就占很大容量了,多来几张这样的图,数据库还不得崩了,所以,就需要将base64图片转换为url,这样就小多了,可以通过图片上传组件转换为url,转化后要怎么定位到富文本编辑器上呢,我一开始直接使用模板字符串src拼接方式,但这样还是不行,因为是拼接,如果富文本只有src,传值会是undifined+图片等问题,这个方法不行,然后就找到了一个定光标的方法,完美解决了各种情况下的问题。
• 上传图片:我称之为巨坑,到现在我都还是有些迷糊的,在上传图片上不知道踩了多少坑,花了多长时间去改这方面的bug。Banner管理模块是必填单图片上传,商品管理模块是必填多图片上传,公告管理模块是非必填单图片上传,再加上富文本编辑器的一个上传图片,需要上传图片的页面很多,上传图片需要使用到element组件中的el-upload组件,图片是上传阿里云的,还需要安装ali-oss插件,上传图片这一模块很多功能都是海哥帮着解决的,图片上传阿里云,封装上传组件,实现添加图片、图片回显等都是海哥帮弄好了的,然后我根据写好的方法模仿实现其它页面的图片上传功能,不过这一模块坑是真的多,图片回显需要使用file-list属性,图片上传成功后阿里云会返回一个图片url地址,图片上传阿里云也需时间,当图片容量比较大时,在图片还没有上传成功就调了接口,会造成压根就没有图片问题,这时就需要判断图片上传完了之后才能调接口,因为每一个模块图片需求不同,实现这一功能点又是一个坑接着一个坑,刚解决完一个,又多出来几个,改这方面的bug人都要弄崩溃了
提测
项目开发自测完后就可以提给测试提测了,按照提测规范发送提测邮件,按照Git规范打好tag,从master分支上checkout一个release分支出来,再把你开发的feature分支合到release分支,tag号打在release分支上。提测后就不用心存侥幸,没有按照需求实现的就是bug,自己没测出来的bug,测试全给你测出来,让你改bug痛不欲生,我自己按照测试用例自测觉得没啥问题,测试一下给我找出十几个来