Element-Plus,使用 El-form中 的 scroll-to-error 没有效果问题记录

因业务需要表单组件中嵌套着表格列表,内容比较多;

所以需要表单校验不通过时,自动定位到不通过的节点;

但发现这个像是没有起到效果一样,后面就是排查的思路了:

  1. 容器高度问题:如果表单容器的高度没有正确设置或者由于内容溢出导致的高度问题,可能会影响纵向滚动。

  2. CSS样式干扰:某些CSS样式,如overflow属性,可能会阻止纵向滚动。特别是如果表单容器或其父元素设置了overflow-y: hidden;,这将阻止纵向滚动。

  3. 浏览器兼容性:虽然不太可能,但仍然值得检查是否在不同的浏览器中表现一致,以排除浏览器特定的bug。

  4. Element UI版本:确保您使用的Element UI版本没有已知的关于scroll-to-error纵向滚动的bug。

以上是 AI 给的思路,但还是没有效果

那最后只能还是靠自己了;

删除了项目大部分不需要的节点,一点点尝试,最终功夫不负有心人;

原来是,每个表单需要校验的子项,里面的 prop 一定要有唯一性;

这样子就解决啦~~

假设你们那边还是无法解决,那我就给你们个兜底方案,请看:

使用类找到校验报错的节点,通过 scrollIntoView  将节点滚动到可视区;

使用以下方案,那 scroll-to-error 这个属性就不需要添加了;

    ruleFormRef.value?.validate((valid: boolean) => {
        if (valid) {
            // 校验通过执行逻辑
        } else { 
            // 不通过
            const firstError = ruleFormRef.value.$el.querySelector('.el-form-item.is-error');
            if (firstError) {
                firstError.scrollIntoView({ behavior: 'smooth', block: 'start' });
            }
        }
    });

<template> <div> <div class="header"> 个人信息 </div> <div class="body"> <el-form ref="form" :model="form" label-width="20%" id="selectForm"> <el-form-item label="用户名:" prop="dispatcher_id"> <span>{{ form.user_name }}</span> <!-- <el-input v-model="form.user_name"></el-input> --> </el-form-item> <el-form-item label="真实姓名:" prop="dispatcher_name"> <span>{{ form.real_name }}</span> <!-- <el-input v-model="form.real_name"></el-input> --> </el-form-item> <el-form-item label="年龄:" prop="dispatcher_phone"> <span>{{ form.age }}</span> <!-- <el-input v-model="form.age"></el-input> --> </el-form-item> <el-form-item label="性别:" prop="dispatcher_phone"> <span>{{ form.sex }}</span> <!-- <el-input v-model="form.sex"></el-input> --> </el-form-item> <el-form-item label="电话:" prop="dispatcher_phone"> <span>{{ form.phone }}</span> <!-- <el-input v-model="form.phone"></el-input> --> </el-form-item> <el-form-item label="邮箱:" prop="dispatcher_phone"> <span>{{ form.mail }}</span> <!-- <el-input v-model="form.mail"></el-input> --> </el-form-item> </el-form> </div> </div> </template> <script> export default { created() { this.getdata() }, data() { return { form: { real_name: '', sex: '', age: '', mail: '', phone: '', user_name: '', } } }, methods: { getdata() { this.$axios.get("/api/user/usermsg").then((res) => { console.log(res.data); if (res.data.status == 200) { this.form.age = res.data.data.age; this.form.mail = res.data.data.mail; this.form.phone = res.data.data.phone; this.form.real_name = res.data.data.real_name; this.form.sex = res.data.data.sex; this.form.user_name = res.data.data.user_name; } }) } }, } </script> <style scoped> .header { width: 100%; height: 10%; text-align: center; line-height: 64px; font-size: 20px; font-weight: 800; border-bottom: 1px solid #e3e3e3; } .body { width: 40%; /* margin: auto; */ margin-top: 30px; margin-left: 30px; } #selectForm>>>.el-form-item__label { font-size: 18px; } span { font-size: 18px; } </style>
06-06
<template> <Dialog :title="dialogTitle" v-model="dialogVisible" width="70%" scroll> <el-form ref="formRef" :model="formData" label-width="120px" scroll-to-error v-loading="formLoading"> <el-row> <el-col :span="24"> <el-form-item label="客户:" prop="name"> <el-select v-model="formData.id" clearable placeholder="请选择" @change="getTalentInfo(formData.id)"> <el-option v-for="item in talentList" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="手机号:" prop="phone"> <div>{{ formData.phone }}</div> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="成本价:" prop="cost"> <div> {{ formData.cost }}元 </div> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="成交价:" prop="cost"> <div> {{ formData.cost }}元 </div> </el-form-item> </el-col> </el-row> <div class="major" v-if="formData.majorPayloadList && formData?.majorPayloadList.length"> <div class="relative major-item" v-for="(item, i) of formData?.majorPayloadList || []" :key="i"> <el-row> <el-col :span="8"> <el-form-item label="级别:"> <div>{{ item.level }}</div> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="等级:"> <div>{{ item.subLevel }}</div> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="专业:"> <div>{{ item.major }}</div> </el-form-item> </el-col> </el-row> <el-col :span="8"> <el-form-item label="三类:"> <div>{{ item.category }}</div> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="社保:"> <div>{{ item.socialSecurityInformation }}(暂时未匹配)</div> <!-- <el-select v-model="item.socialSecurityInformation" clearable placeholder="请选择"> <el-option label="唯一社保" value="1" /> <el-option label="不买社保" value="2" /> <el-option label="不唯一社保" value="3" /> <el-option label="退休" value="4" /> </el-select> --> </el-form-item> </el-col> </div> </div> </el-form> <template #footer> <el-button type="success">转入待匹配</el-button> <el-button type="warning">暂存</el-button> <el-button type="danger">特殊状态</el-button> <el-button @click="submitForm" type="primary" :disabled="formLoading"> 确 定 </el-button> <el-button @click="dialogVisible = false">取 消</el-button> </template> </Dialog> </template> <style lang="scss" scoped> .major { border: 1px solid #8a8a8a; padding: 20px 0px; } .major-item { margin-bottom: 20px; border-bottom: 1px solid #eee; &:last-child { border-bottom: none; margin-bottom: 0; } } .validity-period { width: 100%; display: flex; flex-wrap: nowrap; justify-content: space-between; } :deep(.validity-period .el-input) { width: calc(50% - 10px); } </style> 样式优化
07-12
<template> <!-- 切换主题时样式切换 --> <div v-loading="loading" :id="this.$store.state.settings.version"> <div class="nostalgia-block-table"> <div class="nostalgia-block-title"> <el-row type="flex" justify="space-between"> <el-col :span="24"> <div style="display: flex;justify-content: space-between;"> <div class="el-button--primary nostalgia-block-query"> <div class="nostalgia-round-title"> <div class="nostalgia-round el-button--primary"></div> <div class="nostalgia-round-opacity el-button--primary"></div> </div> <!-- 标题 --> <div>TUI中高低档病人量</div> <span class="el-button--primary"></span> </div> <!-- 新增 --> <el-button style="float: right;" round size="small" icon="el-icon-plus" type="primary" @click="handleAdd" class="nostalgia-button70">新增 </el-button> </div> </el-col> </el-row> </div> <div class="nostalgia-customer-table"> <el-table :data="dataList" border class="no-bottom-border" style="width: 100%" fit :row-class-name="tableRowClassName"> <!-- IB Modality --> <el-table-column label="IB Modality" prop="ibModality" align="center"/> <el-table-column label="Series" prop="series" align="center"/> <!-- 高病人(>) --> <el-table-column label="高病人(>)" prop="highCount" align="center"/> <!-- 中病人(中间包含=) --> <el-table-column label="中病人(中间包含=)" prop="mediumCount" align="center"/> <!-- 低病人(<) --> <el-table-column label="低病人(<)" prop="lowCount" align="center"/> <!-- Status 固定列 --> <el-table-column align="center" prop="status" label="Status"/> <!-- 操作 --> <el-table-column label="Action" align="center" class-name="small-padding fixed-width"> <template slot-scope="scope"> <!-- 修改操作 --> <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button> </template> </el-table-column> </el-table> </div> <!-- 分页 --> <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList()"/> </div> <!-- 添加或修改Dicount对话框 --> <el-dialog :id="this.$store.state.settings.version + '-pop'" :visible.sync="open" width="900px" append-to-body> <div class="dialog-title"> <div class="title-line left"></div> <div>{{ title }}</div> <div class="title-line right"></div> </div> <el-form ref="form" :model="form" :rules="rules" label-width="150px" :validate-on-rule-change="false"> <el-row> <el-col :span="12"> <el-form-item label="IB Modality" prop="ibModality"> <!-- <el-input v-model="form.ibModality" :disabled="true" style="width: 100%"/>--> <el-select v-model="form.ibModality" placeholder="请选择" clearable filterable :disabled="isEdit" @change="getSeries" > <el-option v-for="item in modalityList" :key="item.value" :label="item.label" :value="item.value" style="width: 280px" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="Series" prop="series"> <!-- <el-input v-model="form.series" :disabled="true" style="width: 100%"/>--> <el-select v-model="form.series" placeholder="请选择" clearable filterable multiple collapse-tags popper-class="select-popover-class" value-key="series" @change="changeSeries" > <el-checkbox v-if="seriesList.length > 0" v-model="form.allSeriesSelected" class="custom-checkbox" @change="handleSeriesSelectAll"> <i style="margin:0 3px;font-weight:600;font-size: 12px" v-show="form.allSeriesSelected" class="el-icon-check"></i> <span :style="{ fontWeight: form.allSeriesSelected ? '600' : '500', 'margin-left': form.allSeriesSelected ? '2px' : '20px' }">全选</span> </el-checkbox> <el-option v-for="item in seriesList" :key="item.value" :label="item.label" :value="item.value" style="width: 280px" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="Status" prop="status"> <el-select v-model="form.status"> <el-option v-for="item in statusList" :key="item" :label="item" :value="item"> </el-option> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="高病人(>)" prop="highCount"> <el-input-number :min="0" :max="999999999999999" :precision="0" v-model="form.highCount" style="width: 100%"/> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="低病人(<)" prop="lowCount"> <el-input-number :min="0" :max="999999999999999" :precision="0" v-model="form.lowCount" style="width: 100%"/> </el-form-item> </el-col> </el-row> </el-form> <div slot="footer" class="from-buttom"> <el-button type="primary" class="nostalgia-button70" @click="submitForm">确 定</el-button> <el-button @click="cancel" class="button-cancel-70">取 消</el-button> </div> </el-dialog> </div> </template> <script> import { getSvcTuiTieredPatientsList, submitSvcTuiTieredPatients, edit, selectSvcTuiTieredPatientsInfo, } from '@/api/svcepop/tuiPatientVolume'; import {getModality, getSeriesByModality} from '@/api/svcepop/modalityAndSeries/modalityAndSeries.js'; export default { name: "tuiPatientVolume", props: { componentName: String, }, directives: { 'el-select-loadmore': { bind(el, binding) { const scrollHandler = function () { const ratio = parseFloat((1 / window.devicePixelRatio).toFixed(2)) + 0.01; const condition = this.scrollHeight - (this.scrollTop + ratio) <= this.clientHeight; if (condition) { binding.value(); } }; const SELECTWRAP_DOM = el.querySelector( ".el-select-dropdown .el-select-dropdown__wrap" ); SELECTWRAP_DOM.addEventListener("scroll", scrollHandler); // 保存引用以便unbind时移除 el._scrollHandler = scrollHandler; el._scrollElement = SELECTWRAP_DOM; }, unbind(el) { if (el._scrollElement && el._scrollHandler) { el._scrollElement.removeEventListener("scroll", el._scrollHandler); } } } }, data() { return { // 遮罩层 loading: true, // 总条数 total: 0, // 项目流程自动化管理表格数据 manageList: [], // 弹出层标题 title: "", // 是否显示弹出层 open: false, // 查询参数 queryParams: { pageNum: 1, pageSize: 10, }, // 表单参数 form: { ibModality: '', series: '', status: 'Active' }, // 表单校验 rules: { highCount: [{ validator: (rule, value, callback) => { let lowCount = this.form.lowCount; let hasHighCount = value || value == 0; let hasLowCount = lowCount || lowCount == 0; if (!hasHighCount && hasLowCount) { callback(new Error('请输入高病人(>)')); } else if (hasHighCount && hasLowCount && lowCount > value) { callback(new Error('请输入正确的高病人(>)')); } else { callback(); } }, trigger: 'blur' }], lowCount: [{ validator: (rule, value, callback) => { let highCount = this.form.highCount; let hasHighCount = highCount || highCount == 0; let hasLowCount = value || value == 0; if (!hasLowCount && hasHighCount) { callback(new Error('请输入低病人(<)')); } else if (hasLowCount && hasHighCount && highCount < value) { callback(new Error('请输入正确的低病人(<)')); } else { callback(); } }, trigger: 'blur' }], ibModality: [{required: true, message: '请选择Modality', trigger: 'change'}], series: [{required: true, message: '请选择Series', trigger: 'change'}], status: [{required: true, message: '请选择Status', trigger: 'change'}], }, // 新增或编辑标识 isEdit: false, // 列表数据 dataList: [], // status下拉框数据 statusList: ['Active', 'Inactive'], modalityList: [], seriesList: [], }; }, created() { this.getModalityList(); this.getList(); }, methods: { getModalityList() { getModality().then((res) => { this.modalityList = res.data; }) }, async getSeries(modality) { if (!modality) { this.form.series = ""; this.seriesList = []; return } let param = { modality: modality } await getSeriesByModality(param).then((res) => { this.seriesList = res.data }) }, changeSeries() { // 更新全选状态 this.form.allSeriesSelected = this.seriesList.length > 0 && this.form.series.length === this.seriesList.length; }, handleSeriesSelectAll(val) { if (val) { this.form.series = this.seriesList.map(m => m.value); } else { this.form.series = []; } this.changeSeries(); }, // 设置奇数和偶数行样式 tableRowClassName({row, rowIndex}) { if (rowIndex % 2 === 1) { return 'warning-row'; } return ''; }, // 查询TUI中高低档病人量列表数据 getList() { this.loading = true; let query = { ...this.queryParams, ...this.query, } // 接口 getSvcTuiTieredPatientsList(query).then(response => { this.dataList = response.rows; this.total = response.total; this.loading = false; }); }, // 新增按钮操作 handleAdd() { this.reset(); this.isEdit = false; this.open = true; this.title = "添加TUI中高低档病人量"; }, // 修改按钮操作 async handleUpdate(row) { this.reset(); this.isEdit = true; let query = { groupId: row.groupId, } const response = await selectSvcTuiTieredPatientsInfo(query); this.form = response.data; if (!response.data?.highCount && response.data?.highCount != 0) { this.$delete(this.form, 'highCount'); } if (!response.data?.lowCount && response.data?.lowCount != 0) { this.$delete(this.form, 'lowCount'); } this.title = "修改TUI中高低档病人量"; await this.getSeries(this.form.ibModality); if (this.form.series) { this.form.series = this.form.series.split(","); // 更新全选状态 全选后台存All(一条) this.form.allSeriesSelected = this.seriesList.length > 0 && this.form.series.length === 1 && this.form.series[0] === 'ALL'; if (this.form.allSeriesSelected) { this.form.series = this.seriesList.map(m => m.value) } } this.open = true; }, // 提交按钮 submitForm: function () { this.$refs["form"].validate(valid => { if (valid) { let highCount = this.form.highCount; let lowCount = this.form.lowCount; if ((highCount || highCount == 0) && (lowCount || lowCount == 0)) { this.form.mediumCount = lowCount + '-' + highCount; }else{ this.form.mediumCount = ''; } let query = { ...this.form, series: this.form.series?.join(",") } // 编辑和提交调用相同接口,后端通过id判断 if (this.form.groupId) { edit(query).then(response => { if (response.code == 200) { this.$modal.msgSuccess("修改成功"); this.open = false; this.queryParams = { pageNum: 1, pageSize: 10, }; this.getList(); } else { this.$modal.msgError(response.message); } }); } else { submitSvcTuiTieredPatients(query).then(response => { if (response.code == 200) { this.$modal.msgSuccess("新增成功"); this.open = false; this.queryParams = { pageNum: 1, pageSize: 10, }; this.getList(); } else { this.$modal.msgError(response.message); } }); } } }); }, // 取消按钮 cancel() { this.open = false; this.reset(); }, // 表单重置 reset() { console.log('中高低') this.form = { ibModality: '', series: '', status: 'Active' }; this.seriesList = []; this.resetForm("form"); this.$nextTick(() => { this.$refs.form.resetFields(); // 重置表单(包括清除错误提示) }); }, }, }; </script> <style scoped lang="scss"> #public-container-pop { ::v-deep .el-input-number--medium .el-input-number__decrease, ::v-deep .el-input-number--medium .el-input-number__increase { height: 29px !important; line-height: 29px !important; margin-top: 1px !important; } } .custom-checkbox { ::v-deep .el-checkbox__inner { display: none !important; } ::v-deep .el-checkbox__label { padding-left: 0px !important; line-height: 34px !important; } } </style> 这里的表单校验, 在首次打开dialog的时候series就会被触发, 而modality则不会, 关掉再次打开就不会触发了
最新发布
12-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值