前言
- 表单校验错误时,自动滚动到第一个错误的位置,以便用户快速定位到错误的表单项,可提升用户体验
- 以下是基于
uni-ui组件
实现的方案
效果展示
使用
1、在main.ts
中引入FormPlugin
插件
ts
import { createSSRApp } from 'vue';
import App from './App.vue';
import { FormPlugin } from './plugin/form';
export function createApp() {
const app = createSSRApp(App);
// 注册插件
app.use(FormPlugin);
return {
app,
};
}
2、在页面组件中使用
注意需要LayoutPage
、FormItem
组件和useForm
hook配合使用:
xml
<template>
<LayoutPage>
<uni-card is-full>
<uni-forms ref="formRef" :modelValue="formData" :rules="rules">
<FormItem required label="姓名" name="name">
<uni-easyinput type="text" v-model="formData.name" />
</FormItem>
<view style="margin-top: 70vh">
<FormItem required label="年龄" name="age">
<uni-easyinput type="text" v-model="formData.age" />
</FormItem>
</view>
<view style="margin-top: 70vh">
<FormItem required label="兴趣1" name="hobby">
<uni-easyinput type="text" v-model="formData.hobby" />
</FormItem>
</view>
</uni-forms>
</uni-card>
<template #footer>
<view class="page-footer">
<button type="primary" @click="submitForm">提交</button>
</view>
</template>
</LayoutPage>
</template>
<script setup lang="ts">
import LayoutPage from '@/components/layout-page.vue'
import { useForm } from '@/hooks/form'
import FormItem from '@/components/form-item.vue'
import { ref } from 'vue'
const formData = ref({
name: '',
age: '',
hobby: ''
})
const rules = {
name: {
rules: [
{
required: true,
errorMessage: '请输入姓名',
}
]
},
age: {
rules: [
{
required: true,
errorMessage: '请输入年龄',
}
]
},
hobby: {
rules: [
{
required: true,
errorMessage: '请输入兴趣',
}
]
},
}
const { formRef, validate } = useForm()
const submitForm = async () => {
try {
const model = await validate()
console.log(model)
} catch (error) {
console.error('表单错误', error)
}
}
</script>
<style scoped lang="scss">
.page-footer {
display: flex;
background-color: #f8f8f8;
button {
flex: 1;
margin: 10rpx;
}
}
</style>
实现思路
- 用一个
全局响应式变量
保存表单错误消息, 表单项监听这个变量的变化 - 当表单校验失败时,将错误消息保存到这个变量中
- 通过表单项的
name
属性和错误消息的key
字段判断哪个表单项有错误 - 在
滚动距离 0
位置设置一个锚点
,当有错误时,通过表单项的位置和锚点的位置计算出滚动距离,然后滚动到错误的位置
表单错误消息示例
json
[
{
"name": "name",
"errorMessage": "请输入姓名"
},
{
"name": "age",
"errorMessage": "请输入年龄"
},
{
"name": "hobby",
"errorMessage": "请输入兴趣"
}
]
核心逻辑流程图
- 注1:重置错误消息可以防止重复执行,并且释放内存
- 注2:计算目标滚动距离原理如下:
平台差异说明
App | H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 抖音小程序、飞书小程序 | QQ小程序 | 快手小程序 | 京东小程序 |
---|---|---|---|---|---|---|---|---|
未测试 | √ | √ | 未测试 | 未测试 | 未测试 | 未测试 | 未测试 | 未测试 |
总结
通过nodesRef.boundingClientRect(callback)
api配合锚点
可计算出表单项的滚动距离,然后使用uni.pageScrollTo(OBJECT)
可滚动相应位置。
但是由于小程序的限制,需要封装layout-page
组件、二次封装uni-forms-item
组件还有useForm
hook配合,才能实现这个功能,实现方式和使用方式都较为复杂。
源码地址
结语
感谢您耐心阅读这篇文章。如果您觉得内容对您有帮助或启发,请不吝点赞支持。如果您发现文章中的任何错误或需要改进的地方,欢迎您指正批评。