发布初衷 :
记录在移动端项目中使用 Vant 2 组件库时遇到的各种问题 ,
方便以后再次遇到类似问题 , 能够快时查阅解决 ,
大家要是觉得有帮助的话 , 可以收藏一下 , 博主会不定时更新文章的
Popup 弹出层
介绍
弹出层容器,用于展示弹窗、信息提示等内容,支持多个弹出层叠加展示。
问题记录 : Field 输入框 和 Popup 弹出层 两个 结合 使用 时 ,
在 iPhone 真机上测试的时候 出现的一个小 bug :
点击 Field 输入框 的时候 , 第一次会 弹出 一个 手机的键盘输入框 ,
点击第二次的时候 才出来 Popup 弹出层 里面的内容 ( 比如 日期选择器 )
解决方案 :
**给 Field 输入框 设置 readonly ,通过
readonly
将输入框设置为只读状态**
输入框 **
van-field
** 必须得加入
**readonly**
这个 只读属性 ,
不然会导致 用户手机 触发 默认键盘 遮挡 你的弹窗和选择器内容 影响体验
也不要用
disabled
来禁用输入框 , 样式会变成禁用状态下的样式很难改动
只需要设置为只读即可 , 也不会触发手机键盘
DatetimePicker 时间选择
介绍
时间选择器,支持日期、年月、时分等维度,通常与弹出层组件配合使用。
**确认选择的时间数据是需要自己处理的,详见
confirmPicker
方法 **
<template>
<div class="seller">
<van-cell
title="开始时间"
is-link
:value-class="className"
:value="timeValue"
@click="showPopup" />
<van-popup v-model="show" position="bottom">
<van-datetime-picker
v-model="currentDate"
type="datetime"
title="选择时间"
:loading="isLoadingShow"
:min-date="minDate"
:max-date="maxDate"
:formatter="formatter"
@cancel="show = false"
@confirm="confirmPicker"
/>
</van-popup>
</div>
</template>
<script>
export default {
name: 'Seller',
data () {
return {
msg: '商家页面',
timeValue: '请选择时间',
show: false,
isLoadingShow: true,
currentDate: new Date(),
minDate: new Date(),
maxDate: new Date(2020, 12, 31),
className: ''
}
},
methods: {
// 显示弹窗
showPopup () {
this.show = true
this.isLoadingShow = true
setTimeout(() => {
this.isLoadingShow = false
}, 500)
},
// 确认选择的时间
confirmPicker (val) {
let year = val.getFullYear()
let month = val.getMonth() + 1
let day = val.getDate()
let hour = val.getHours()
let minute = val.getMinutes()
if (month >= 1 && month <= 9) { month = `0${month}` }
if (day >= 1 && day <= 9) { day = `0${day}` }
if (hour >= 0 && hour <= 9) { hour = `0${hour}` }
if (minute >= 0 && minute <= 9) { minute = `0${minute}` }
this.className = 'timeClass'
this.timeValue = `${year}-${month}-${day} ${hour}:${minute}`
this.show = false
},
// 选项格式化函数
formatter (type, value) {
if (type === 'year') {
return `${value}年`
} else if (type === 'month') {
return `${value}月`
} else if (type === 'day') {
return `${value}日`
} else if (type === 'hour') {
return `${value}时`
} else if (type === 'minute') {
return `${value}分`
} else if (type === 'second') {
return `${value}秒`
}
return value
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus" scoped>
.seller
.timeClass {
color: #333;
}
</style>
Field 输入框
介绍
表单中的输入框组件。
问题记录 : Field 输入框 和 Popup 弹出层 两个 结合 使用 时 ,
在 **iPhone 真机 **上测试的时候 出现的一个小 bug :
点击 Field 输入框 的时候 , 第一次会 弹出 一个 手机的键盘输入框 ,
点击第二次的时候 才出来 Popup 弹出层 里面的内容 ( 比如 日期选择器 )
解决方案 :
**给 Field 输入框 设置 readonly ,通过
readonly
将输入框设置为只读状态**
输入框 **
van-field
** 必须得加入
**readonly**
这个 只读属性 ,
不然会导致 用户手机 触发 默认键盘 遮挡 你的弹窗和选择器内容 影响体验
也不要用
disabled
来禁用输入框 , 样式会变成禁用状态下的样式很难改动
只需要设置为只读即可 , 也不会触发手机键盘
Picker 选择器
介绍
提供多个选项集合供用户选择,支持单列选择和多列级联,通常与弹出层组件配合使用。
业务场景 :
一开始以为只能渲染纯数组
但后来用的时候 , 后端返回来的数据结构是 数组嵌套对象的模式 ,
因此还特意将数组对象里面的数据专门筛选出来一个新数组用于渲染。。
但后来传参的时候需要数据结构里面的其他数据用于传参
所以又找了找这个Picker选择器可不可以渲染数组对象结构的案例 :
发现 [ { } ] , 是可以渲染的 ,只不过还要做一下处理 :
使用案例 :
<van-popup v-model="showTitle" position="bottom" > <van-picker title="标题" show-toolbar value-key="name" :columns="columns" @confirm="onConfirm" @cancel="onCancel" /> </van-popup>
export default { data() { return { showTitle: false, columns: [], // 后端请求的数据 queryFrom: { id: null, name: '', } }; }, methods: { onConfirm(value, index) { this.queryFrom.id = value.id // 需要传给后端的id值 this.queryFrom.name = value.name // 用于渲染选择器列表数据 this.showTitle = false // 关闭弹出层 }, onCancel() { this.showTitle = false }, }, };
补充知识 :
vant-ui 之 Field 输入框 和 Picker 结合使用时 ,如何绑定正确的 id 类型的值的问题 。
很常见的需求 :
表单中的一项 ,需要从 picker 控件中选择正确的值后 ,展示的是字符串 ,
然后提交到后台服务器的则是字符串对应的 value 类型的值的问题。
点击表单的档案组,弹出 Picker 选择组件 ,选择正确的值 ,填充到表单项 ,但是 ,
提交到服务器去,需要提交对应的 id ,而不是看到的字符串。
如何实现 ?
定义两个属性,id 和 name , 两个是一 一对应的关系 。
在 van-picker 中 ,绑定的 confirm 函数 ,参数获取到的是一个对象
在这个函数内,同时更新 id 和 name ,保证他俩一 一对应 。
onConfirm(value, index) {
this.queryFrom.id = value.id // 需要传给后端的id值
this.queryFrom.name = value.name // 用于渲染选择器列表数据
this.showTitle = false // 关闭弹出层
},
如何展示 默认选中项
项目使用背景 :
用户填写表单时 , 需要根据上面填写的 乘车人数 来自动让下面的 Picker 选择器
下拉时 默认值 展示 与 人数相匹配 的 车辆类型
而又由于车辆类型是后端返回的数据 , 并不是固定不变的 , 所以前端没办法写死匹配方法
1、用户输入完 乘车人数 后 , 自动发起请求 , 由后端来匹配相对应的车辆类型
2、但是这里前端 Picker 组件需要用其索引值来展示下拉默认值 , 后端又无法返给我索引
3、前端这里只能先请求车辆类型数据列表后 , 再请求匹配车型数据值 , 循环去匹配后拿到当前匹配的索引值后再赋值给 Picker 组件
代码实现 :
根据乘车人数展示默认选中项 <van-picker show-toolbar title="车辆类型" value-key="dictLabel" :default-index="defaultMatch" :columns="applyType" /> data() { return { defaultMatch: 0, // 车辆类型下拉展示默认索引值 applyType: [], // 车辆类型列表 } } methods: { // 根据乘车人数自动匹配车辆类型 async blurMatchType() { let arr = [] // 先请求车辆类型列表数据用于匹配 let res = await this.getDicts('car_apply_type') if (res.code == 200) arr = res.data // 根据乘车人数请求匹配的车辆类型值 let ret = await getMatchType(this.userCarForm.riderNum) const { code, data } = ret if (code == 200) { // 循环匹配后赋值其索引值 arr.forEach((item, index) => { if (item.dictValue == data) { this.defaultMatch = index } }) } } }
List 列表
介绍
瀑布流滚动加载,用于展示长列表,当列表即将滚动到底部时,会触发事件并加载更多列表项。
List 组件通过 **
loading
** 和 **
finished
** 两个变量控制加载状态,当组件滚动到底部时,会触发
load
事件并将
loading
设置成
true
。
此时可以发起异步操作并更新数据,数据更新完毕后,将
loading
设置成
false
即可。
若数据已全部加载完毕,则直接将
finished
设置成
true
即可。
<van-list
v-model="loading"
:finished="finished"
:finished-text="appList.length ? '没有更多了' : ''"
@load="onLoad"
>
<van-cell v-for="item in appList" :key="item" :title="item" />
</van-list>
export default {
data() {
return {
loading: false,
finished: false,
appList: [], // 用车申请列表
appQuery: {
page: '1', // 要查询的页码
rows: '10', // 每页记录数量
userId: null, // 用户 Id
}
};
},
methods: {
async onLoad() {
// 异步更新数据
let ret = await getAppList(this.appQuery)
const { code, data } = ret
if (code == 200) {
this.appList = this.appList.concat(data.rows)
// 加载状态结束
this.loading = false;
if (this.appList.length >= data.total) {
// 没有更多数据了
this.finished = true;
Notify({
message: '已加载完全部订单',
background: '#ee0a24'
})
} else {
this.appQuery.page++
}
}
},
},
};
以上是正常情况下 , onLoad 滚动到底部可以正常触发加载下一页数据
接下来就是说明一个不正常使用情况 , 此 bug 组件库还未修复
就是 和 Tab 标签页 组件 公用 :
我猜估计是包裹内容的高度它无法断定了吧 , 所以 onLoad 加载就有问题了
Tab 标签页
<van-tabs v-model="active">
<van-tab title="标签 1">
<ApprovalItem type='1' />
</van-tab>
<van-tab title="标签 2">
<ApprovalItem type='2' />
</van-tab>
<van-tab title="标签 3">
<ApprovalItem type='3' />
</van-tab>
<van-tab title="标签 4">
<ApprovalItem type='4' />
</van-tab>
</van-tabs>
data() {
return {
active: 2,
};
},
主要注意点就是子组件的高度需要设置一下 ,
一开始尝试的给 ApprovalItem 子组件一个高度 height:100% ,
但并没有解决一直触发 onLoad 加载的问题 ,
后来改成 height:100vh , 就 OK 了 。。
没别的了 , 就是记录一下 , 提醒避坑 。
版权归原作者 雨季mo浅忆 所有, 如有侵权,请联系我们删除。