html⽂本框撤回修改内容,原⽣js实现HTML输⼊框撤销、重做
功能
HTML代码:
Document
上⼀步(撤销)
下⼀步(重做)
JS代码:
/**
* 记录输⼊框的操作记录,可以进⾏上⼀步(撤销)或下⼀步(重做)操作
*
*/
const inputEl = document.querySelectorAll('#textarea')[0]
const previousEl = document.querySelectorAll('#previous')[0]
const nextEl = document.querySelectorAll('#next')[0]
// 操作数组
const operateList = []
// 按键按下时记录的输⼊框的信息
let beforeInputInfo = null
// 当前操作的下标,范围:[-1, operateList.length - 1]。-1代表⼀开始的空状态
let operateIndex = -1
// 最⼤操作数,超过时,最前⾯的操作会被丢弃
const MAX_OPERATE_NUMBER = 200
let isComposing = false
console.log('oninput', this.value, this.value && this.value.length, e.isComposing)
if(isComposing) {
return
}
recordOperate(e)
}
// 按键按下时保存输⼊框信息
beforeInputInfo = getCurrentOperateInfo(e)
}
// 按键按下时保存输⼊框信息
beforeInputInfo = getCurrentOperateInfo(e)
}
// compositionstart和compositionend通过onxxx的⽅式⽆法绑定事件
inputEl.addEventListener('compositionstart',function(e) {
console.log('oncompositionstart')
isComposing = true
})
inputEl.addEventListener('compositionend',function(e) {
console.log('oncompositionend')
recordOperate(e)
isComposing = false
})
// 上⼀步(撤销)
recoveryOperate(true)
}
// 下⼀步(重做)
recoveryOperate(false)
}
/**
* 记录操作
* @param {Event} e 事件
*/
function recordOperate(e) {
// 操作下标不是最后的下标,证明之前有进⾏撤销或重做操作,那么重新输⼊后需要删除多余的操作if(operateIndex !== operateList.length - 1) {
// 操作下标不是最后的操作,则要删除操作下标后⾯的所有操作
operateList.splice(operateIndex + 1, operateList.length - 1 - operateIndex)
}
if(operateList.length) {
// 之前有操作
// 判断和前⾯的操作是否是连续的输⼊或删除,是的话则算⼀个操作,更新信息就好
const previousOperate = operateList[operateList.length - 1]
// e.data 返回当前输⼊的字符串
if(
previousOperate.direction === inputEl.selectionDirection &&
previousOperate.start === d &&
inputEl.selectionStart === inputEl.selectionEnd &&
(
(// 连续输⼊,⽆论是否是拼写状态
(// 当前的输⼊类型
(
e.inputType === 'insertText'
) ||
(
)
) &&
// 之前的输⼊类型
['insertText', 'compositionend'].includes(previousOperate.inputType) &&
// 光标位置
inputEl.selectionStart === previousOperate.start + (e.data ? e.data.length : 0)
) ||
(// 连续删除,包括back删除和del删除
// 当前的输⼊类型
['deleteContentBackward', 'deleteContentForward'].includes(e.inputType) &&
// 之前的输⼊类型
['deleteContentBackward', 'deleteContentForward'].includes(previousOperate.inputType) &&
// 光标位置
inputEl.selectionStart === previousOperate.start - (e.inputType === 'deleteContentBackward' ? 1 : 0) )
)
) {
updateOperateInfo(previousOperate)
} else {
addOperate(e)
}
} else {
// 之前没有操作
addOperate(e)
}
beforeInputInfo = null
}
/
**
* 新增⼀个操作
* @param {Event} e 事件
* @param {Object} operate 操作对象
*/
function addOperate(e, operate = null) {
const resultOperate = operate ? operate : getCurrentOperateInfo(e)
// 旧光标⽅向
resultOperate.oldDirection = beforeInputInfo ? beforeInputInfo.direction : resultOperate.direction // 旧光标开始位置html内容文本框
resultOperate.oldStart = beforeInputInfo ? beforeInputInfo.start : resultOperate.start
// 旧光标结束位置
resultOperate.oldEnd = beforeInputInfo ? d : d
if(operateList.length > MAX_OPERATE_NUMBER) {
// 超过最⼤操作数,最前⾯的操作会被丢弃
operateList.shift()
}
operateList.push(resultOperate)
// 更新操作下标
operateIndex = operateList.length - 1
}
/**
* 获取当前操作的信息
* @param {Event} e 事件
* @returns {Object} 操作对象信息,包括光标位置、内容、事件的输⼊类型
*/
function getCurrentOperateInfo(e) {
return {
start: inputEl.selectionStart, // 光标开始位置
end: inputEl.selectionEnd, // 光标结束位置
direction: inputEl.selectionDirection, // 光标⽅向
value: inputEl.value, // 输⼊框的内容
inputType: e.inputType ? e.inputType : e.type // 输⼊类型,只有input事件有inputType }
}
/
**
* 更新操作信息
* @param {Object} operate 更新的操作对象
*/
function updateOperateInfo(operate) {
operate.start = inputEl.selectionStart, // 光标开始位置
operate.direction = inputEl.selectionDirection, // 光标⽅向
operate.value = inputEl.value // 输⼊框的内容
}
/**
* 恢复操作
* @param {boolean} isPrevious 是否是撤销
*/
function recoveryOperate(isPrevious) {
if(isPrevious) {
// 撤销
if(operateIndex < 0) {
alert('没有操作可以撤销!')
return
} else {
const currentOperate = operateList[operateIndex]
let previousOperate = null

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。