前言
先看效果:
在执行步骤时,按钮的可用状态会改变,同时关闭弹窗操作也会出现二次提示。
按钮的提示文字和功能也会随步骤改变
问题分析
模拟一遍步骤,可以写出这些规则
(步骤1)上传文件时,不允许点击“下一步”;点击取消时,需要二次确认。=》“现在退出不会保存记录,是否确认退出?”
(步骤2)校验数据时,不允许点击按钮,点击X时,提示二次确认
(步骤3)写入数据时,不允许点击按钮=》写入完毕后,上一步按钮文字改变
复制代码
还有一些特殊情况的规则
(步骤1之前)“下一步”按钮禁用,为普通弹窗,关闭不需要二次确认
(从步骤2返回步骤1)“下一步”按钮禁用,此时关闭弹窗需要二次确认
复制代码
功能实现
根据上面的分析,可以使用一个变量表示当前进行到哪个步骤,然后根据这个变量改变按钮的文字、可用状态、以及该步骤应该执行的操作。
由于使用了element-ui
组件,可以通过控制弹窗的visible
属性来实现开关弹窗,还可以用自带的Message
组件实现二次确认的弹窗。
除去表示进行到哪个步骤的变量外,还需要一些其他的。
preBtn: '取消', // 两个按钮的文字
nextBtn: '下一步',
preBtnCheck: false, // 是否需要二次确认
preBtnDisabled: false, // pre按钮的禁用状态
nextBtnDisabled: false, // next按钮的禁用状态
active: 0, // 步骤条的步数
复制代码
考虑到之后的步骤不一定固定为3步,设置了常量
const stepStart = 0; // 步骤开始
const stepEnd = 2; // 步骤结束
复制代码
前进后退
先来实现前进后退步骤的功能,给前进后退的按钮绑定upsetStep
事件
<el-button
:disabled="preBtnDisabled"
@click="upsetStep('pre')">
{{preBtn}}
</el-button>
<el-button
type="primary"
:disabled="nextBtnDisabled"
@click="upsetStep('next')">
{{ nextBtn }}
</el-button>
复制代码
upsetStep
根据传入的参数对步骤变量进行加减,以及改变文字
// 更新页面
if (type === 'pre') {
this.active--;
} else {
this.active++;
}
// 根据active改变按钮的文字
if (this.active === stepStart) {
this.preBtn = '取消';
this.nextBtn = '下一步';
} else {
this.preBtn = '上一步';
}
if (this.active === stepEnd) {
this.preBtn = '关闭窗口';
this.nextBtn = '完成';
}
复制代码
还需要在每次加减步骤时,检查一下是否是最初,最后的步骤,所以在函数开头加上了
// 检查是否是最初、最后的步骤
const {checked, closeType} = this.checkStep(type);
if (checked) {
this.closeDialog(closeType);
return;
}
复制代码
checkStep(type) {
/**
* this.active === stepStart&&type==='pre' 在第一页按下取消
* this.active === stepEnd&&type==='next' 在最后一页按下完成
* this.active === stepEnd&&type==='pre' 在最后一页按下关闭窗口
*/
const checked =
(this.active === stepStart && type === 'pre') ||
(this.active === stepEnd && type === 'next') ||
(this.active === stepEnd && type === 'pre');
const closeType =
(this.active === stepStart && type === 'pre') ||
(this.active === stepEnd && type === 'pre')
? 'cancel'
: this.active === stepEnd && type === 'next'
? 'confirm'
: '';
return {checked, closeType};
}
复制代码
暂时还没想到好的优化方法,先这么写着吧,又不是不能用
按钮状态
然后来实现进行步骤时,改变按钮禁用状态。在上文“问题分析”模块可以得知,步骤一之前,由一个按钮触发步骤一,之后根据active
的值触发步骤二、三。
于是在upsetStep
函数最后加上
const handleInterfaces = ['', 'checkImportData', 'addImportData'];
const handleInterface = handleInterfaces[this.active];
if (handleInterface.length > 0) {
this[handleInterface]();
}
复制代码
这样,当点击“上传文件”按钮,执行uploadFile
;当进行到步骤二、三时,会分别执行checkImportData
和addImportData
。在这三个函数里,改变按钮的状态即可。
由于需要频繁改变按钮的状态,而实现这种操作实际上只是改变xxxBtnDisabled
的值。于是写了个函数
changeBtnClickOperate(btnStatusName, type) {
this[`${btnStatusName}`] = type;
}
复制代码
uploadFile() {
// 模拟上传文件的接口
// 将nextBtn设置为禁用
this.changeBtnClickOperate('nextBtnDisabled', true);
// 将preBtn设为需要二次确认
this.changeBtnClickOperate('preBtnCheck', true);
setTimeout(() => {
this.changeBtnClickOperate('nextBtnDisabled', false);
}, 2000);
},
checkImportData() {
// 模拟校验数据的接口
this.changeBtnClickOperate('preBtnDisabled', true);
this.changeBtnClickOperate('nextBtnDisabled', true);
setTimeout(() => {
this.changeBtnClickOperate('preBtnDisabled', false);
this.changeBtnClickOperate('nextBtnDisabled', false);
}, 2000);
},
addImportData() {
// 模拟写入数据的接口
this.changeBtnClickOperate('nextBtnDisabled', true);
this.changeBtnClickOperate('preBtnDisabled', true);
setTimeout(() => {
this.changeBtnClickOperate('nextBtnDisabled', false);
this.changeBtnClickOperate('preBtnDisabled', false);
this.changeBtnClickOperate('preBtnCheck', false);
}, 2000);
},
复制代码
最后,在步骤一没有点击“上传文件”按钮是无法进行下一步的,所以需要在upsetStep
里加上
// 根据active改变按钮的文字和可用状态
if (this.active === stepStart) {
this.preBtn = '取消';
this.nextBtn = '下一步';
this.changeBtnClickOperate('nextBtnDisabled', true);
} else {
this.preBtn = '上一步';
}
复制代码
二次确认弹窗
最后,实现二次确认的弹窗。
closeDialog(type) {
// 检查是否需要弹出二次确认框
if (this.preBtnCheck) {
this.open(() => {
this.dialogVisible = false;
});
} else {
this.$emit(type);
this.dialogVisible = false;
}
},
handleClose() {
// 这里处理点击按钮以外,关闭弹窗的情况
if (this.preBtnCheck) {
this.open(() => {
this.dialogVisible = false;
});
} else {
this.dialogVisible = false;
}
}
复制代码
open(callback) {
this.$confirm('现在取消不会保留任何更改,确认离开?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
callback: (action) => {
if (action === 'confirm') {
callback();
}
},
});
}
复制代码
一些思考
在实现改变按钮状态的功能中,我频繁操作了按钮的disable。可不可以通过一个变量,控制三种状态呢?
根据涉及到改变按钮的函数uploadFile
、addImportData
以及checkImportData
,进行分析
状态1 依赖函数uploadFile
状态改变为:
preBtnCheck:?->true
nextBtnDisabled:?->true -> false
复制代码
状态2 依赖函数checkImportData
状态改变为:
preBtnDisabled:?->true->false
nextBtnDisabled:?->true->false
复制代码
状态3 依赖函数addImportData
状态改变为:
preBtnCheck:?->false
preBtnDisabled:?->true->false
nextBtnDisabled:?->true->false
复制代码
有时候觉得好累,能用不就行了,为什么要帮产品把产品的事给干了。
不过业务仔暂时没时间想了,有缘再掘。