Много раз мы нажимаем кнопку для отправки данных, но в случае плохого состояния сети или нечетких подсказок взаимодействия пользователь будет нажимать кнопку несколько раз в течение определенного периода времени.Если кнопка не защищена, это приведет к повторным данным представление, в результате чего Если данные ненормальны, сегодня я поделюсь более общим решением.
Идея решения этой проблемы состоит в том, чтобы добавить переменную для поддержания состояния существующих кнопок, но если на странице много кнопок, то нужно объявить такое же количество переменных, что очень недружественно для обслуживания.
## Существующая проблема
<div class="button">
提交
</div>
var button = document.querySelector('.button');
button.onclick = submit;
function submit (e) {
// 模拟异步
var promiseCb = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('提交成功');
}, 1000);
})
return promiseCb.then(
function (res) {
// 处理回调
console.log(res);
}
)
}
Решение
Чтобы лучше инкапсулировать старый код, необходимо избегать добавления дополнительных переменных, поэтому функция actionDelegate пишется для инкапсуляции исходного действия, и исходный код нужно только изменить.
button.onclick = submit;
↓
button.onclick = actionDelegate(submit);
function actionDelegate (action) {
// do something
}
Затем нам нужно оценить тип действия.Если действие возвращает обычный объект, то мы считаем, что действие является синхронной функцией; если действие возвращает обещание, то мы думаем, что нам нужно дождаться окончания состояния обещания, прежде чем мы можем запустить это действие снова
function actionDelegate (action) {
// 获取函数返回值
var returnValue = action(e);
// 判断返回值是 promise
if (returnValue && returnValue.constructor &&
returnValue.constructor.name === 'Promise') {
// 保护按钮不被狂点
}
else {
// let it go
}
}
Поэтому важно в конечном итоге вернуть обещание в функции отправки.
function submit (e) {
// 模拟异步
var promiseCb = new Promise(...)
return promiseCb
}
Затем мы займемся самой важной частью, которая заключается в сохранении состояния кнопки.В этом случае я получил узел кнопки через событие и сохранил состояние по атрибуту узла.Другие методы также могут использовать здесь сохранить состояние
function actionDelegate (action) {
return function (e) {
if (e.target.getAttribute('progress-status') === 'processing') {
// 如果按钮上有处理中的状态则跳过后续逻辑
return false;
}
// 获取函数返回值
var returnValue = action(e);
// 判断返回值是 promise
if (returnValue && returnValue.constructor &&
returnValue.constructor.name === 'Promise') {
// 关键点 把按钮状态保存在 node 的属性上
e.target.setAttribute('progress-status', 'processing')
return returnValue.then(
function () {
// promise 结束后重置状态
e.target.setAttribute('progress-status', 'initial');
}
)
}
}
}
Окончательный код собирается следующим образом
var button = document.querySelector('.button');
button.onclick = actionDelegate(submit);
function submit (e) {
// 模拟异步
var promiseCb = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('提交成功');
}, 1000);
})
return promiseCb.then(
function (res) {
// 处理回调
console.log(res);
}
)
}
function actionDelegate (action) {
return function (e) {
if (e.target.getAttribute('progress-status') === 'processing') {
// 如果按钮上有处理中的状态则跳过后续逻辑
return false;
}
// 获取函数返回值
var returnValue = action(e);
// 判断返回值是 promise
if (returnValue && returnValue.constructor &&
returnValue.constructor.name === 'Promise') {
var originInnerHTML = e.target.innerHTML;
// 关键点 把按钮状态保存在 node 的属性上
e.target.setAttribute('progress-status', 'processing')
e.target.innerHTML = '提交中...';
return returnValue.then(
function () {
// promise 结束后重置状态
e.target.setAttribute('progress-status', 'initial');
e.target.innerHTML = originInnerHTML;
}
)
}
}
}
постскриптум
Изначально это была инструкция, реализованная angularjs для замены ng-click, но позже выяснилось, что она использовалась и в других проектах, поэтому логика была переделана на нативном коде. Возможно лучше реализовать в angularjs, потому что сама директива будет иметь отдельный скоуп и нет необходимости повторять объявление переменных. Когда я писал учебник сегодня, я вдруг обнаружил, что может быть удобнее использовать attr для его реализации.Если у вас есть лучший метод реализации, вы можете общаться.
Спасибо
Если вам понравилась эта статья, вы можете подписаться на колонку Пожалуйста, лайкните и поделитесь
##JSbin