vant
大约 7 分钟
vant
1.
vant使用过程中的记录
1.van-tab一直默认选中第一个tab
1.1 通过 v-model:active实现选中, 官网说明支持 number | string,但是使用出现数字无法实现默认选中,需要讲绑定的字段转为字符串
<van-tabs v-model:active="activeMonth" @change="changeMonth">
<van-tab v-for="item in DateList[activeYearIndex].months" :title="item + '月'" :name="item"></van-tab>
</van-tabs>
不加 name 属性,则是通过下标
1.2.van-tab 数据更新后,赋值后又被改回默认选择第一个tab,因为没有初始化好,可以通过$nextTick
this.activeMonthIndex=activeMonthIndex;// 不在这里赋值,会导致数据赋值滞后
var this_=this;
this.$nextTick(() => {
this_.activeMonthIndex=activeMonthIndex;// 需要重新赋值,否则会被赋值为 0 默认加载第一个tab
})
2. vant 下拉刷新数据加载2次
原因是在于下拉刷新的时候触发了上拉加载,所以执行了两次
解决方法是:先将list组价的finished=true,数据加载完了在判断该值应该是true还是false,这样可以避免在下拉刷新的时候触发上拉加载。

3.DatetimePicker 时间选择
初始化时间插件,如果出现没有默认选中,可能是 时间格式 :new Date(xxxxx)
this.currentDate=new Date('2022-06-16');
van-tabs 嵌入的内容如果是自定义表单,则不能使用循环
van-tabs 下面的这种写法是错误的
在使用
this.$refs.listRef就会发现 会出现多个
<van-tabs v-model:active="active" sticky :offset-top="offsetTop" class="page-tabs" ><!--swipeable-->
<van-tab v-for="item in tabs" :title="item.name" :name="item.listType">
<act-task-list procDefKey="zj_user_flow" dataType="task" v-if="listType == '1'" />
<act-task-list procDefKey="zj_user_flow" dataType="hisTask" v-if="listType == '2'" />
<apply-list v-if="listType == '3'" />
</van-tab>
</van-tabs>
- 正确
<van-tabs v-model:active="listType" sticky :offset-top="offsetTop" class="page-tabs" @change="changeTab"><!--swipeable-->
<van-tab title="待处理" name="1" >
<act-task-list key="zj_user_flow-task" procDefKey="zj_user_flow" dataType="task" ref="listRef" v-if="listType=='1'"/>
</van-tab>
<van-tab title="已处理" name="2" >
<act-task-list key="zj_user_flow-hisTask" procDefKey="zj_user_flow" dataType="hisTask" ref="listRef" v-if="listType=='2'" />
</van-tab>
<van-tab title="全部" name="3" >
<apply-list ref="listRef" v-if="listType=='3'" />
</van-tab>
</van-tabs>
表单验证
表单验证
this.$refs.xxx.validate().then(()=>{
// 验证通过
}).catch(()=>{
//验证失败
})
如果想单独校验某个输入框,则需要指定name 属性否则找到不到
<van-field v-model="form.unitName" name="unitName"
:rules="rules.unitName" label="监督单位" placeholder="请选择监督单位"/>
// 必填校验
rules: {
unitName: [{ required: true, message: "请选择监督单位", trigger: "blur" }],
applyRemarks: [{ required: true, message: "请输入", trigger: "blur" }],
},
this.$refs.xxx.validate('unitName').then(()=>{
// 验证通过
}).catch(()=>{
//验证失败
})
自定义表单校验
将表单校验提示信息放到
export default {
data() {
return { };
},
methods: {
/**
* 自定义 表单校验
* 1. van-field 标签需要使用name 属性
* 2. 需要指定ref :命名- rield+'Ref'
* 3. 可以使用 @blur focus update:model-value
*/
setFieldPlaceholder(prop) {
const field = this.$refs[prop + 'Ref'];
if (field) { // 如果存在字段,则设置占位文本
this.$refs.form.validate(prop).catch(error => {
if (error) {
const message = error.message || '';
field.$el.querySelector('.van-field__value').classList.add('error')
field.$el.querySelector('.van-field__body .van-field__control').setAttribute('placeholder', message);
} else {
field.$el.querySelector('.van-field__value').classList.remove('error');
field.$el.querySelector('.van-field__body .van-field__control').setAttribute('placeholder', field.placeholder)
}
})
}
},
/**
* 表单校验 ---submit时
*/
showValidationErrors(){
Object.keys(this.rules).forEach(key => {
this.setFieldPlaceholder(key);
});
}
}
};
<van-field v-model="form.unitName" name="unitName" @blur="setFieldPlaceholder('unitName')" ref="unitNameRef"
required :rules="rules.unitName" label="监督单位"
placeholder="请选择监督单位" />
this.$refs.form.validate().then((res) => {
// 校验成功
}).catch(error => {
// 表单校验失败
this.showValidationErrors(); // 迁移到 混入mixin里面
})
身份证校验
data () {
let validateIdNumber = (idNumber) => {
debugger
if (!idNumber) {
return false;
}
if (idNumber.length === 15) {
// 一代身份证号码格式:
// 地址码(6位) + 生日(6位) + 顺序码(3位)
if (!/^[1-9]\d{5}\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}$/.test(idNumber)) {
return false;
}
// 校验出生日期
const year = parseInt(idNumber.substr(6, 2)) + 1900;
const month = parseInt(idNumber.substr(8, 2)) - 1;
const day = parseInt(idNumber.substr(10, 2));
const date = new Date(year, month, day);
if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {
return false;
}
} else if (idNumber.length === 18) {
// 二代身份证号码格式:
// 地址码(6位) + 生日(8位) + 顺序码(3位) + 校验码(1位)
if (!/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/.test(idNumber)) {
return false;
}
// 校验出生日期
const year = parseInt(idNumber.substr(6, 4));
const month = parseInt(idNumber.substr(10, 2)) - 1;
const day = parseInt(idNumber.substr(12, 2));
const date = new Date(year, month, day);
if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {
return false;
}
// 校验校验码:参考 GB 11643-1999 标准
const checkCodes = '10X98765432';
let sum = 0;
for (let i = 0; i < 17; i++) {
sum += parseInt(idNumber[i]) * Math.pow(2, 17 - i);
}
const checkCode = checkCodes.charAt(sum % 11);
if (checkCode !== idNumber.charAt(17).toUpperCase()) {
return false;
}
} else {
// 非法长度
return false;
}
// 校验地区码
const regionCodes = [
'11', '12', '13', '14', '15', '21', '22', '23', '31', '32', '33', '34', '35', '36', '37', '41',
'42', '43', '44', '45', '46', '50', '51', '52', '53', '54', '61', '62', '63', '64', '65', '71',
'81', '82', '91'
];
const regionCode = idNumber.substr(0, 2);
if (!regionCodes.includes(regionCode)) {
return false;
}
// 校验顺序码
const seqCode = idNumber.substr(-4, 3);
if (!/^\d{3}$/.test(seqCode)) {
return false;
}
return true;
}
return {
isDisabled: false,
// 人员状态status(user_status1:正常;2:失效,例如离职等;3:待审核;4:审核未通过)字典
statusOptions: [],
sexOptions: [], // 性别 0-男 1-女 2 未知
moduleName: 'user_files',
// 表单参数
form: {},
testingCompanyList: [],// 检测公司 下拉选数据
rules: {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
identity: [
{ required: true, message: '请输入身份证号码', trigger: 'blur' },
{
pattern: /(^\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$)|(^\d{6}(18|19|20)\d{2}(0\d|10|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)$)/,
message: '请输入正确的证件号'
},
{
validator: (value, rule) => validateIdNumber(value),
message: '请输入正确的身份证号码'
}
],
},
}
},
列表+侧滑菜单
https://blog.csdn.net/m0_49529959/article/details/125087941
输入框限定数字限定
<van-field v-model="form.flBlqNum" label="避雷器" placeholder="请输入防雷避雷器数量(个)" @keyup="formatValidationNumber($event, 'flBlqNum')"/>
formatValidationNumber(event, fieldKey) {
const obj = event.target;
obj.value = obj.value.toString().match(/^\d{0,8}(?:\.\d{0,4})?/);
this.form[fieldKey] = obj.value;
},
整数或小数
<van-field v-model="form.pileLength" label="桩长/m" placeholder="请填写桩长"
@keyup="formatInportData($event.target.value,'10,2','pileLength',form)"/>
/**
* 针对 input 对数字格式化 -- 限定只能输入整数和指定格式的小数
* 分为 小数/整数
* @param value : 需要校验的数字
* @param format:指定格式 小数或者整数 "8,4"|| "8"
* @param field:需要跟新的自动
* @param Obj:实体对象 例如表单对象--form
*/
export const formatInportData = (value,format,field,Obj) =>{
const formatArr = format.split(",");
let regx2 = '';
if (formatArr.length == 1) { // 说明当前校验的是整数
// value = value.replace(/[^\d]/g,'');
regx2=new RegExp(`^\\d{0,${formatArr[0]}}`);
} else { // 小数
regx2=new RegExp(`^\\d{0,${formatArr[0]}}(?:\\.\\d{0,${formatArr[1]}})?`);
// value = value.toString().match(/^\d{0,8}(?:\.\d{0,4})?/);
}
value = value.toString().match(regx2);
value = value[0];
Obj[field] = value;
// 如果 数据不刷新,使用 set方法,目前使用没遇到问题
// Vue.set([Obj],field,value)// 不能直接使用 this.$set
}
/**
* 限定输入的是数字
* @param value
* @param maxLenght
* @param field:需要跟新的自动
* @param Obj:实体对象 例如表单对象--form
*/
export const formatInportNum = (value, maxLength, field, Obj) => {
let regx = new RegExp(`^(\\-|\\+)?\\d{0,}(?:\\.\\d{0,})?`);//new RegExp(`^(\\-|\\+)?\\d+(\\.\\d+)?$`);
value = value.toString().match(regx);
value = value[0];
// 控制输入的最多位数
if (maxLength && value.length > maxLength) {
value = value.slice(0, maxLength);
}
Obj[field] = value;
}
输入框支持输入也可以 弹窗选择
类似于 el-autocomplete 功能

<van-field v-model="form.pileNum" maxlength="64" required :rules="rules.pileNum" label="桩号"
@update:model-value="pileNumChange" placeholder="请填写桩号">
<template #right-icon>
<van-icon name="arrow" @click="showSelectPopup('pileNumSelectRef', 'pileNum')" class="custom-van-field-icon"/>
</template>
</van-field>
// 选择桩号
pileNumSelect (item) {
this.form.pileId = item.id
this.form.pileNum = item.pileNum
},
// 监听 输入变化,进行 桩基id清除,防止数据污染
pileNumChange () {
console.log('change ')
this.form.pileId = ''
},
自定义弹窗多选组件
<multi-select-popup title="检测人员选择" :defaultOptions="personList" v-model="form.jcUserIds"
:show-picker="showPicker"
@selectObject="selectJcUser" @update:showPicker="showPicker = $event"/>
调用 @click="showPicker = true"

表单

文本左右对其
- 设置 表单公共属性
input-align="right"
<van-form input-align="right" ref="form" v-model="form">
</van-form>
- 设置单个field组件
input-align="right"
<van-field v-model="form.mName" label="主体工作" readonly required is-link input-align="right"/>
vant search 右侧的关闭icon 无法点击
.van-field__body {
position: relative;
.van-icon-clear {
z-index: 999;
position: absolute;
right: 0;
}
}
复选框
需要支持点击文本实现选中

<van-checkbox-group v-model="ids" v-if="multiMode">
<van-cell-group inset>
<van-cell v-for="(item, index) in computedOptions" clickable :key="item"
:title="item[label]" @click.stop="toggle(item.id)">
<template #right-icon>
<van-checkbox :name="item[valueKey]" shape icon-size="15px" @click.stop :ref="'checkboxRefs'+item.id" />
</template>
</van-cell>
</van-cell-group>
</van-checkbox-group>
toggle(id) {
this.$refs[`checkboxRefs${id}`][0].toggle();
},