vue-input-contenteditable
vue-input-contenteditable copied to clipboard
设置输入最长20字后,ios输入超过20字时,光标错乱
ios输入超过20字时,虽然输入不了,但是光标一直在走,在往前走,请问这个怎么解决
When ios input more than 20 characters, although the input cannot be made, the cursor keeps moving, and it is moving forward. How can I solve this?
The cursor keeps moving forward, like, literally moving in the x direction but no characters are input?
I will hopefully have an iOS device in 1 week and maybe I can test then. Can you maybe send a video of the issue?
你好,我改了一下代码,主要就是加了一个变量isChange,以下是我的代码:
<!-- Created by dreamsqin on 2019/9/5 -->
<template>
<div
class="div-editable"
contenteditable="true"
v-html="innerText"
ref='contenteditable'
@input="changeText"
@focus="isChange = false"
@change="changeFunc"
@blur="blurFunc"></div>
</template>
<script>
export default {
name: 'DivEditable',
props: {
value: {
type: String,
default: ''
},
maxlength: {
type: Number,
default: -1
}
},
data() {
return {
innerText: this.value,
isChange: true,
lastText: this.value //Initally set to value if exists
}
},
watch: {
value() {
if (this.isChange) {
this.innerText = this.value
}
}
},
methods: {
async changeText (e) {
let text = this.$refs.contenteditable.textContent;
if (this.maxlength !== -1) {
//I chose this instead of preventDefault on 'keydown', 'paste', 'drop' as if we preventDefault
//we need to check a bunch of specific valid cases to pass through like backspace, delete
//Ctrl+A, A Ctrl+V that makes the text shorter, arrow keys, etc. which may be impossible...
//
//Instead, retroactively trimming the string after 'input' and setting the cursor properly
//(as changing the text string will change the cursor in some browsers... :( ) is a better bet
//IMO. Current method was tested in Chrome, FF, and Android
let selection = window.getSelection();
let { anchorNode, anchorOffset } = selection;
if (text.length > this.maxlength) {
//Find the cursor position inside the contenteditable. Can't use anchorOffset
//because Firefox will add multiple text nodes when pasting sometimes
//(and then collapse them later? it's kind of weird...)
const textNodes = Array.from(this.$refs.contenteditable.childNodes);
const realAnchorOffset = textNodes.length <= 1 ? anchorOffset : (
textNodes
//Collect all nodes up to, but not including, anchorNode
.slice(0, textNodes.indexOf(anchorNode))
//Map them all to their length
.map(n => n.textContent.length)
//Sum them together
.reduce((acc, itm) => acc + itm, 0) +
//And then add the final offset in the final node
anchorOffset);
//Use either the lastText if exists, or the current text but trimmed
const newTextToSet = this.lastText || text.slice(0,this.maxlength);
//Find the last position of the cursor before the input event. Use the
//current cursor position, and remove the difference between the untrimmed text
//and the trimmed text (to back the cursor up to the position the
//input event happened at)
//We can't use anchorOffset because FF likes to make new text nodes
//for pasted text for some reason??
let newOffsetToSet = realAnchorOffset - (text.length - newTextToSet.length);
newOffsetToSet = Math.min(newOffsetToSet, this.maxlength); // Make sure not over maxlength
//console.log(realAnchorOffset, anchorOffset, text.length, newTextToSet.length, this.$refs.contenteditable.childNodes.length);
//This will reset the cursor to the start of the contenteditable _and_
//make a new text node (so don't use anchorNode for selection.collapse())
this.$refs.contenteditable.textContent = newTextToSet;
//Set selection using last valid offset
selection.collapse(this.$refs.contenteditable.childNodes[0], newOffsetToSet);
this.lastText = newTextToSet;
return;
} else {
this.lastText = text;
}
}
// this.$emit('input', this.$el.innerHTML)
this.$emit('input', text);
},
blurFunc() {
this.isChange = true
this.$emit('blurFunc')
},
changeFunc(e){
console.log(e.target.value)
if(e.target.value.length>20){
alert("error")
}
}
}
}
</script>
<style lang="scss">
.div-editable{
width: 100%;
height: 100%;
overflow-y: auto;
word-break: break-all;
outline: none;
user-select: text;
white-space: pre-wrap;
text-align: left;
&[contenteditable=true]{
user-modify: read-write-plaintext-only;
&:empty:before {
content: attr(placeholder);
display: block;
color: #ccc;
}
}
}
</style>
Hmm, okay, thank you for the solution.
This should be replaced with something more robust when I next loop back to this project.