12月快忙疯了,但是我学到了很多东西吧,由于产品经理的严格,导致我前端被逼无奈加了很多细节交互,不靠谱后端导致联调时间还在补接口,然后延期算在前端头上,很不开心。
好不容易第一个阶段结束了,抽空写一下总结。
一、关于表格的一些交互
1.表头自定义
需求分析:结合了elementUI的table组件做的一个需求,要求通过一个表头选择,触发表格的表头项的变化。
需求拆分:要把表头作为一个数组灵活导入,还要通过选项改变这个数组,就可以修改表头了。
dataHeader是灵活定义的表头数组,在 这里定义表头的属性和值,还可以设置排序、是否固定在一侧等。然后通过选择表头数据的交互,去把表头变化一下就可以实现了。
< el-table-column
:label="item.label"
:property="item.name"
min-width="150"
v-for="(item, index) in dataHeader"
:key="index"
:fixed="item.fixed"
:sortable="item.sortable"
>
</ el-table-column>
//灵活的表格代码
<div class="table">
<el-table
ref="multipleTable"
:data="tableData"
tooltip-effect="dark"
style="width: 100%"
:header-cell-style="{ background: '#FAFAFA' }"
>
<!-- 空图标显示 -->
<div slot="empty">
<div class="imgStyle">
<img
src="@/assets/img/none.png"
alt="暂无数据"
width="240"
height="208"
/>
</div>
<strong>未查询到记录</strong>
</div>
<el-table-column
:label="item.label"
:property="item.name"
min-width="150"
v-for="(item, index) in dataHeader"
:key="index"
:fixed="item.fixed"
:sortable="item.sortable"
>
</el-table-column>
<el-table-column
fixed="right"
label="操作"
width="160"
align="center"
>
<template slot-scope="scope">
<el-button
type="text"
size="small"
class="slot"
@click="handleEdit(scope.row)"
>编辑</el-button
>
<el-button
type="text"
size="small"
class="del"
@click="handleDelete(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</div>
2.合并同列的表格
需求分析:想要合并表格中相同列的数据,需求是实现第一列的数据合并
在el-table 里加上 :span-method=“objectSpanMethod”
//核心方法是下面两个
//判断第一列相同的内容,然后合并行列
flitterData(arr) {
//存储要合并的行数
let spanOneArr = []
//记录合并的索引
let concatOne = 0
arr.forEach((item, index) => {
//如果是一行的话,直接不用合并
if (index === 0) {
spanOneArr.push(1)
} else {
//item.合并列的属性
if (item.period === arr[index - 1].period) {
//第一列需合并相同内容的判断条件
spanOneArr[concatOne] += 1
//被合并的取0
spanOneArr.push(0)
} else {
//不相等就取1,并把当前索引赋值过去
spanOneArr.push(1)
concatOne = index
}
}
})
return {
one: spanOneArr
}
},
objectSpanMethod({ rowIndex, columnIndex }) {
// 判断第一列
if (columnIndex === 0) {
//拿到列数
const _row = this.flitterData(this.tableDetail).one[rowIndex]
//大于0就合并,否则就不合并
const _col = _row > 0 ? 1 : 0
return {
rowspan: _row,
colspan: _col
}
}
},
3.实现表格的单选
需求:想把表格当成选择框选中,要限制多选的样式,并及时清空选择的数组
表格设置的参数:
< el-table
class="tb"
@select="handleSelectionChange"
>
</el-table>
//记住这里的select不是selection-change,之前因为这个我改了好久的bug
//隐藏全选框的样式 css代码
.tb
::v-deep
.el-table__header
.el-table-column--selection
.cell
.el-checkbox {
display: none;
}
//表格选择方法js
handleSelectionChange(selection, row) {
//清空所有选中
this.$refs.multipleTable.clearSelection()
//选中当前checkbox
this.$refs.multipleTable.toggleRowSelection(row, true)
//保存当前选中的对象
this.templateSelection = row
},
4.对表格数据进行处理,使用插槽
需求:后端可能传的不是中文,而是id 、code的字段,所以展示的时候需要进行转化展示一下
以最难的图片为例:
//scope.row.属性 去获取表格的属性数据,通过<template slot-scope="scope"></template>放入插槽
<el-table-column label="照片" width="400">
<template slot-scope="scope">
<el-image
v-for="(item, index) in scope.row.imgsArr"
:key="index"
style="width: 50px; height: 50px; margin-right: 5px"
:src="item"
:preview-src-list="scope.row.imgsArr"
>
</el-image>
</template>
</el-table-column>
二、关于表单填写校验
1.校验输入的数字正则
让输入框只能输入大于0的数字,οnkeyup=“this.value=this.value.replace(/\D|^0/g,’’)”
校验数字要改成v-model.number=’’’
2.手机号码的校验正则
//检查手机号
isCellPhone(val) {
if (
!/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/.test(
val
)
) {
return false
} else {
return true
}
},
3.自定义校验
有时候空的校验不满足校验,可以自己写校验方法
//以判断值的大小为例
rules: {
waterVolume: [
{ required: true, message: '请输入灌溉后水位', trigger: 'change' },
{
required: true,
validator: (rules, value, callback) => {
if (value < this.farmDetail.sprayWay) {
return callback(new Error('灌溉后水位不能小于灌溉前水位'))
}
//这里callback()一定要有,否则表单校验会不返回通过
return callback()
},
trigger: ['change', 'blur']
}
]
},
4.校验的触发
<el-form
ref="farmDetail"
></el-form>
//在需要触发的地方调用该方法
this.$refs.farmDetail.validate(valid => {
if (valid) {
console.log('验证通过222')
} else {
console.log('验证不通过22')
}
})
5.表格的校验
属性这样拼 :prop="‘表格名.’ + scope.$index + ‘.属性名’"
//这样就可以对表格里的输入框进行校验了
<el-form-item
:prop="'tableForm.' + scope.$index + '.content'"
:rules="rules.content"
:inline-message="true"
>
<el-input
clearable
v-model="scope.row.content"
placeholder="含量(%)"
onkeyup="this.value=this.value.replace(/\D|^0/g,'')"
:maxlength="2"
></el-input>
</el-form-item>
三、图片的上传与回显
需求:一开始前端交互就是用element ui 里的upload组件,但是项目里的图片文件是要求先文件上传,然后再以获得的id数组传给后端;回显也一样,后端返回id数组给前端,前端通过这个id去下载对应的图片数据,然后用其src进行回显。这里有个附加需求,图片预览和文件预览都要事先,图片预览比较容易,文件预览就需要处理一下。
//是用来隐藏超出文件个数时,最后一个的上传框
//组件里的属性:
:class="{ hide: hideUpload }"
//css:
.hide .el-upload--picture-card {
display: none;
}
//组件里用来响应上传接口的
:data="updateParam"
:action="actionURL"
//具体实现代码 html
<el-upload
:on-preview="handlePictureCardPreview"
:data="updateParam"
:class="{ hide: hideUpload }"
:action="actionURL"
list-type="picture-card"
:limit="limitCountImg"
:before-upload="dealImgChange"
:file-list="fileList"
accept=".png,.jpg,.pdf"
:on-error="handleError"
:on-success="handleSuccess"
>
<i slot="default" class="el-icon-plus"></i>
<div
slot="file"
slot-scope="{ file }"
style="width: 80px; height: 80px; border-radius: 5px"
>
<img
class="el-upload-list__item-thumbnail"
:src="filterImg(file)"
alt=""
fit="contain"
style="border-radius: 5px"
/>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in"></i>
</span>
<span
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete"></i>
</span>
</span>
</div>
</el-upload>
data数据:
//文件缩略图
FileImg: require('@/assets/img/pdf.png'),
hideUpload: false, //用来隐藏最后一个上传框
limitCountImg: 10, //上传文件的最大数量
//文件上传列表
fileList: [],
//图片的url
dialogImageUrl: '',
//图片预览框显示
dialogVisible: false,
//js代码
//图片状态改变时触发,在on-change事件中判断图片数量
dealImgChange(file) {
//限制图片格式
this.idtest = file.uid
let fileName = file.name
let pos = fileName.lastIndexOf('.')
let lastName = fileName.substring(pos, fileName.length)
if (
lastName.toLowerCase() !== '.jpg' &&
lastName.toLowerCase() !== '.png' &&
lastName.toLowerCase() !== '.pdf'
) {
this.$message.error('文件必须jpg、png、pdf 类型')
return false
}
//限制文件大小
const isLt = file.size / 1024 / 1024 / 10 <= 1
if (!isLt) {
this.$message.error('上传文件大小不得大于10MB')
return false
}
return true
},
handleSuccess(response, file, fileList) {
// 上传成功
if (response.code === '0') {
this.fileList = fileList
this.hideUpload = this.fileList.length >= this.limitCountImg
} else {
if (response.code === '9') {
this.$message.error(response.msg)
}
// 上传失败重置数组
this.fileList = [...this.fileList]
}
},
//文件上传失败
handleError() {
this.$message.error('上传失败')
},
//删除文件
handleRemove(file) {
// 删除文件
if (!file.id && !file.response) {
return
}
const id = file.id || file.response.id
this.fileList.splice(
this.fileList.findIndex(item => (item.id || item.response.id) === id),
1
)
this.hideUpload = this.fileList.length >= this.limitCountImg
},
//pdf的图片回显展示
filterImg(item) {
// 判断文件类型,返回相应显示的图片
const extStart = item.name.lastIndexOf('.')
const ext = item.name.substring(extStart, item.name.length).toUpperCase()
if (ext === '.PDF') {
return this.FileImg
} else {
return item.url
}
},
//文件预览
handlePictureCardPreview(file) {
let fileName = file.name
let pos = fileName.lastIndexOf('.')
let lastName = fileName.substring(pos, fileName.length)
if (lastName.toLowerCase() === '.pdf') {
//如果是pdf打开页面进行预览
window.open(this.jointDownLoadURL(file), 'top')
} else {
//如果是图片就弹窗显示
this.dialogImageUrl = this.jointDownLoadURL(file)
this.dialogVisible = true
}
},
jointDownLoadURL(file) {
// 预览和下载,拼接URL
const url = file.url
const base_url = 环境链接
if (url.indexOf(base_url) >= 0 && file.id) {
// 若url包含base_url且有file中存在文件id,则说明该文件是网络获取的,否则为本地获取上传的
return url + 拼接url
}
return url
}
四、其他知识点
1.深拷贝的使用
深拷贝的好处:对象拷贝过来就不会相互影响了,用于区别修改前和修改后的判断
JSON.parse(JSON.stringify(深拷贝的对象))
2.excel导出
接口要加上
responseType: 'blob'
//获得了后端返回的数据res后
var blob = res
var url = window.URL.createObjectURL(blob)
var aLink = document.createElement('a')
aLink.style.display = 'none'
aLink.href = url
aLink.setAttribute('download', name + '.xlsx')
document.body.appendChild(aLink)
aLink.click()
3.watch监听数据变化实现回显功能
通过监听有变化的数据来进行回显
watch:{
监控的对象或者数据名: {
handler(val) {
//这里写回显的方法
},
deep: true //深度监听
},
}
4.content-type的两种类型前端对其的处理
需求:后端想要前端传json数据给他,之前的request的form表单就不能用了,所以就对request.js方法进行修改
// 请求参数
if (config.method === 'post') {
if (
config.data &&
config.headers['Content-Type'] === 'application/json'
) {
//转为json格式
config.data = JSON.stringify(config.data)
}
} else {
//拼接
if (config.data) {
config.url = config.url + '?' + qs.stringify(config.data)
}
}
加班确实能学到很多,但是容易过劳肥,喜欢吃辣、甜、油的东西解压,我感觉一个月我胖了2斤多了。还是要多总结,希望新的一年我能继续坚持,技术稳步上升。