1、form组件 自定义校验
template:
<a-form-item
fieldDecoratorId="articleNumber"
label='编码:'
:fieldDecoratorOptions="{rules: [{ required: true, message: '请输入编码!'},
{max: 60, message: '编码不能超过60个字符!'},{validator: validateCode}]}"
>
<a-input class="with-count" placeholder="请输入相关内容" autocomplete="off"
v-model="addOptions.productMainVo.articleNumber">
<template slot="addonAfter">{{addOptions.productMainVo.articleNumber.length}}/60</template>
</a-input>
</a-form-item>
methods:
(1)校验不含中文字符
validateCode (rule, value, callback) {
let reg = new RegExp('[\\u4E00-\\u9FFF]+', 'g')
if (value && reg.test(value)) {
/* eslint-disable-next-line */
callback('您输入的格式有误!')
return
}
callback()
}
(2)校验金额
validateMoney (rule, value, callback) {
if (value) {
if (!isNaN(value)) {
if (Number(value) > 10000000) {
/* eslint-disable-next-line */
callback('您输入的格式有误,金额最大值为10,000,000!')
return
} else if (isNaN((value + '').charAt(0))) {
/* eslint-disable-next-line */
callback('您输入的格式有误,金额首位请替换为数字!')
return
} else if (isNaN((value + '').charAt(value.length - 1))) {
/* eslint-disable-next-line */
callback('您输入的格式有误,金额末位请替换为数字!')
return
} else if ((value + '').indexOf('.') > -1 && (value + '').length - 1 - (value + '').indexOf('.') > 2) {
/* eslint-disable-next-line */
callback('您输入的格式有误,小数点后最多两位小数!')
return
} else {
callback()
}
} else {
/* eslint-disable-next-line */
callback('您输入的格式有误,金额为数字!')
return
}
}
callback()
}
2、解决带有下拉框的组件在滚动时 下拉框不跟随滚动的问题
api中有getPopupContainer
使用如下:
template:
<a-select :getPopupContainer="getPopupContainer">
<a-select-option v-for="d in brandData" :key="d.id">{{d.brandName}}</a-select-option>
</a-select>
methods:
getPopupContainer (trigger) {
return trigger.parentElement
}
但是级联选择组件 需要升级组件库版本到1.19不然此属性不生效
3、上传图片组件 , 一次上传一张,照片墙模式,可删除预览,限制图片格式和大小
template:
<div class="upload-wrapper">
<div class="upload-tip">建议尺寸:800 x 800 像素。仅支持 gif、 jpeg、 png、 bmp 4种格式, 大小不超过3.0 MB。</div>
<div class="clearfix">
<a-upload
action="//qqq.com/upload/file"
name="file"
:data="{fileType: 'pic'}"
listType="picture-card"
:fileList="fileList"
:withCredentials="true"
@preview="handleUploadPreview"
@change="handleUploadChange"
>
<div>
<a-icon type="plus" />
<div class="ant-upload-text">添加图片</div>
</div>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleUploadCancel">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
</div>
data:
// 上传图片
previewVisible: false, // 是否可预览图片
previewImage: '', // 预览图片
fileList: [], // 上传图片数据列表
methods:
handleUploadCancel () {
this.previewVisible = false
},
handleUploadPreview (file) {
this.previewImage = file.url || file.thumbUrl
this.previewVisible = true
},
handleUploadChange ({file, fileList}) {
let pos = file.name.lastIndexOf('.')
let lastName = file.name.substring(pos, file.name.length)
let supportTypes = ['.gif', '.jpeg', '.png', '.bmp', '.jpg'] // gif、 jpeg、 png、 bmp
if (supportTypes.indexOf(lastName.toLowerCase()) <= -1) {
this.$message.error('商品图片仅支持 gif、 jpeg、 png、 bmp 4种格式!')
return
}
if (file.size / (1024 * 1024) > 3) {
this.$message.error('上传商品图片大小应小于3Mb!')
return
}
this.fileList = fileList
// 根据服务端返回数据筛选上传成功的文件
let imgUrls = []
fileList.forEach((file) => {
if (file.response && file.response.code === '0') {
imgUrls.push(file.response.data.fileInfo.url)
}
})
},
4、自己写的popover弹框 ,组件自己的弹框在页面宽高变化的时候不好控制位置,会有错位,弹框跟不上触发弹框的按钮
template:
<div class="add-btn-wrapper">
<a-button @click="" class="add-btn">
<a-icon type="plus" /> 添加
</a-button>
<div class="select-spec-val" v-show="ifCanAdd">
<div class="ant-popover-arrow"></div>
</div>
</div>
css:
.add-btn-wrapper {
position: relative;
.ant-btn {
min-width: 96px;
}
.add-btn {
border: none;
color: #40a9ff;
min-width: 96px;
}
.select-spec-val {
position: absolute;
top: 45px;
left: -92px;
z-index: 3;
padding: 12px 16px;
color: rgba(0,0,0,.65);
background-color: #fff;
background-clip: padding-box;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0,0,0,.15);
.ant-popover-arrow {
position: absolute;
top: -5px;
left: 135px;
box-shadow: -3px -3px 7px rgba(0,0,0,.07);
}
}
}
5、合并table组件单元格 ,根据不同数据动态合并行
配置的列属性信息如下:
columns: [
{
title: 'www',
dataIndex: 'we',
scopedSlots: {customRender: 'we'}
},
{
title: 'bbbb',
dataIndex: 'er',
scopedSlots: {customRender: 'er'},
customRender: (value, row, index) => {
const obj = {
children: value,
attrs: {}
}
// m为要合并的单元格数,自己定
if (index % m === 0) {
obj.attrs.rowSpan = m
} else {
obj.attrs.rowSpan = 0
}
return obj
}
}
]
6、table 组件 选择本页 和 选择全部, 以及处理禁用选择项
computed: {
rowSelection () {
const { selectedRowKeys } = this
return {
selectedRowKeys,
onChange: this.onSelectChange,
// 处理禁用选择项
getCheckboxProps: record => {
return {
props: {
disabled: this.disabledRowKeys.indexOf(record.key) > -1
}
}
},
hideDefaultSelections: true,
selections: [
{
key: 'page-data',
text: '本页全选',
onSelect: (changableRowKeys) => {
this.selectedRowKeys = changableRowKeys
this.selectWholePages = false
}
},
{
key: 'all-data',
text: '全部选择',
onSelect: (changableRowKeys) => {
this.selectedRowKeys = [...Array(this.pagination.totalCount).keys()]
}
}],
onSelection: this.onSelection
}
},
},
data:
selectedRowKeys: []
methods:
// 这个方法中只监听选择框的选中和取消, 不监听自定义的选择本页和选择全部
onSelectChange (selectedRowKeys) {
// 里面的处理逻辑 按自己需求写即可
this.selectedRowKeys = selectedRowKeys
},
7、自己再封装的分页组件
<template>
<div class="page-wrapper text-right">
<a-pagination
class="page-content"
:pageSizeOptions="['10', '20', '30', '40', '50']"
showSizeChanger
:total="total"
:pageSize="pageSize"
:current="current"
@change="onChange"
@showSizeChange="onShowSizeChange"
>
<template slot='buildOptionText' slot-scope='props'>
<span v-if="props.value!=='50'">{{props.value}}条/页</span>
<span v-if="props.value==='50'">50条/页</span>
</template>
</a-pagination>
<span class="total">共 {{total}} 条</span>
</div>
</template>
<script>
export default {
data () {
return {
}
},
props: {
total: {
require: true,
type: Number
},
pageSize: {
require: true,
type: Number
},
current: {
require: true,
type: Number
}
},
methods: {
onChange (current, pageSize) {
this.$emit('onChange', current, pageSize)
},
onShowSizeChange (current, pageSize) {
this.$emit('onShowSizeChange', current, pageSize)
}
}
}
</script>
<style lang='scss' rel="stylesheet/scss" type="text/scss">
</style>
使用如下:
template:
<custom-pagination
:total="pagination.totalCount"
:pageSize="pagination.pageSize"
:current="pagination.pageNo"
@onChange="onChangePage"
@onShowSizeChange="onShowSizeChangePage"
></custom-pagination>
script:
import CustomPagination from 'components/pagination/index.vue'
data:
pagination: {
pageNo: 1,
pageSize: 10,
totalCount: 0
},
methods:
onChangePage (pageNo, pageSize) {
this.pagination.pageNo = pageNo
// 重新请求数据
},
onShowSizeChangePage (pageNo, pageSize) {
this.pagination.pageSize = pageSize
// 重新请求数据
},
8、上传压缩包, 校验只能上传zip压缩包
template:
<a-upload :multiple="false" :fileList="fileList"
name="file"
:data="{fileType: 'zip'}"
accept="*.zip"
:withCredentials="true"
action="//qqq.com/file" @change="uploadZip">
<a-button>
<a-icon type="upload" />
</a-button>
</a-upload>
data:
fileList: [],
methods:
uploadZip (info) {
let pos = info.file.name.lastIndexOf('.')
let lastName = info.file.name.substring(pos, info.file.name.length)
if (lastName.toLowerCase() === '.zip') {
this.fileList = info.fileList.slice(-1)
this.loadedFile = info.file
let res = info.file.response
if (res) {
if (res.code === '0') {
this.$message.success('文件上传成功')
} else {
this.$message.error(res.message)
}
}
} else {
this.$message.error('只能上传zip压缩包')
}
},
9、格式化金额数字为小数点后两位,没有就补0
filters: {
money (num) {
if (!/^(\d+)(\.\d*)?$/.test(num)) {
return ''
}
let strNum = num + ''
let number = num
if (strNum.indexOf('.') > -1) {
number = num.toFixed(2)
} else {
number = num + '.00'
}
strNum = number + ''
let font = strNum.substring(0, strNum.indexOf('.'))
let back = strNum.substring(strNum.indexOf('.'))
let mod = font.length % 3
let output = (mod === 0 ? '' : (font.substring(0, mod)))
for (let i = 0; i < Math.floor(font.length / 3); i++) {
if ((mod === 0) && (i === 0)) {
output += font.substring(mod + 3 * i, mod + 3 * i + 3)
} else {
output += ',' + font.substring(mod + 3 * i, mod + 3 * i + 3)
}
}
return output + back
}
},
10、文字两端对齐,pc端
css:
.item-title {
background-color: transparent;
border: none;
font-family: PingFang-SC-Medium;
font-size: 14px;
color: #666;
padding: 0 11px;
line-height: 32px;
width: 126px;
text-align:justify;
text-justify:distribute-all-lines;/*ie6-8*/
text-align-last:justify;/* ie9*/
-moz-text-align-last:justify;/*ff*/
-webkit-text-align-last:justify;/*chrome 20+*/
}
11、model组件 确认弹框中内容使用自定义的标签
let self = this
this.$confirm({
centered: true,
maskClosable: true,
title: '确认吗?',
// 注意此处写法 JSX support
content: (
<div>
<p>信息1:{row.msg1}</p>
<p>信息2:{row.msg2}</p>
</div>
),
onOk () {
let params = {}
}
self.request(params)
},
onCancel() {}
})