我正在构建类似输入内容的可编辑div。您应该单击div外部的一些标签以将其添加到div中,同时也可以在所述标签周围输入内容。
我正在使用用户选择:none(正常和webkit)使标签按钮不被选中,因此失去了插入符号的位置。它可以在Firefox和Chrome中使用,但不能在Safari中使用(我知道-webkit-前缀并正在使用它)。
Here is a fiddle where you can reproduce the problem.
我的问题的根源是保持插入符号的位置,同时使内容的div可编辑。
我以前曾尝试使用rangy,但在有关Firefox的某些限制中陷入困境。从UX的角度来看,这些限制非常令人讨厌。您可以针对此用户选择的内容检查我以前的问题及其解决方法:无解-Caret disappears in Firefox when saving its position with Rangy
这就是我采用用户选择的解决方案的方式:无。
我的组件/ JS:
new Vue({
el: "#app",
data(){
return {
filters_toggled: false,
fake_input_content: '',
input_length: 0,
typed: false,
boolean_buttons: [{
type: '1',
label: 'ȘI',
tag: 'ȘI',
img: 'https://i.imgur.com/feHin0S.png'
}, {
type: '2',
label: 'SAU',
tag: 'SAU',
img: 'https://i.imgur.com/vWJeJwb.png'
}, {
type: '3',
label: 'NU',
tag: 'NU',
img: 'https://i.imgur.com/NNg1spZ.png'
}],
saved_sel: 0,
value: null,
options: ['list', 'of', 'options']
}
},
name: 'boolean-input',
methods: {
inputLength($event){
this.input_length = $event.target.innerText.length;
if(this.input_length == 0)
this.typed = false;
},
addPlaceholder(){
if(this.input_length == 0 && this.typed == false){
this.$refs.divInput.innerHTML = 'Cuvinte cheie, cautare booleana..'
}
},
clearPlaceholder(){
if(this.input_length == 0 && this.typed == false){
this.$refs.divInput.innerHTML = '';
}
},
updateBooleanInput($event){
this.typed = true;
this.inputLength($event);
},
saveCursorLocation($event){
/*
if($event.which != 8){
if(this.saved_sel)
rangy.removeMarkers(this.saved_sel)
this.saved_sel = rangy.saveSelection();
}
*/
// if(this.input_length == 0 && this.typed == false){
// var div = this.$refs.divInput;
// var sel = rangy.getSelection();
// sel.collapse(div, 0);
// }
},
insertNode: function(node){
var selection = rangy.getSelection();
var range = selection.getRangeAt(0);
range.insertNode(node);
range.setStartAfter(node);
range.setEndAfter(node);
selection.removeAllRanges();
selection.addRange(range);
},
addBooleanTag($event){
// return this.$refs.ChatInput.insertEmoji($event.img);
if (!this.$refs.divInput.contains(document.activeElement)) {
this.$refs.divInput.focus();
}
console.log(this.input_length);
if(this.typed == false & this.input_length == 0){
this.$refs.divInput.innerHTML = ''
var space = '';
this.typed = true
//this.saveCursorLocation($event);
}
//rangy.restoreSelection(this.saved_sel);
console.log(getSelection().anchorNode, getSelection().anchorOffset, getSelection().focusNode, getSelection().focusOffset)
var node = document.createElement('img');
node.src = $event.img;
node.className = "boolean-button--img boolean-button--no-margin";
node.addEventListener('click', (event) => {
// event.currentTarget.node.setAttribute('contenteditable','false');
this.$refs.divInput.removeChild(node);
})
this.insertNode(node);
this.saveCursorLocation($event);
},
clearHtmlElem($event){
var i = 0;
var temp = $event.target.querySelectorAll("span, br");
if(temp.length > 0){
for(i = 0; i < temp.length; i++){
if(!temp[i].classList.contains('rangySelectionBoundary')){
if (temp[i].tagName == "br"){
temp[i].parentNode.removeChild(temp[i]);
} else {
temp[i].outerHTML = temp[i].innerHTML;
}
}
}
}
},
pasted($event){
$event.preventDefault();
var text = $event.clipboardData.getData('text/plain');
this.insert(document.createTextNode(text));
this.inputLength($event);
this.typed == true;
},
insert(node){
this.$refs.divInput.focus();
this.insertNode(node);
this.saveCursorLocation($event);
},
fixDelete(){
}
},
props: [ 'first'],
mounted() {
this.addPlaceholder()
}
})
我的HTML
<div id="app">
<div class="input__label-wrap">
<span class="input__label">Cauta</span>
<div style="user-select: none; -webkit-user-select: none">
<span readonly v-on:click="addBooleanTag(b_button)" v-for="b_button in boolean_buttons" class="boolean-buttons">{{b_button.label}}</span>
</div>
</div>
<div class="input__boolean input__boolean--no-focus">
<div
@keydown.enter.prevent
@blur="addPlaceholder"
@keyup="saveCursorLocation($event); fixDelete(); clearHtmlElem($event);"
@input="updateBooleanInput($event); clearHtmlElem($event);"
@paste="pasted"
v-on:click="clearPlaceholder(); saveCursorLocation($event);"
class="input__boolean-content"
ref="divInput"
contenteditable="true">Cuvinte cheie, cautare booleana..</div>
</div>
</div>
我的CSS
.filters__toggler
{
cursor: pointer;
padding: 2px;
transition: all 0.2s ease-in-out;
margin-left: 10px;
}
.filters__toggler path
{
fill: #314964;
}
.filters__toggler-collapsed
{
transform: rotate(-180deg);
}
.input__label
{
font-family: $roboto;
font-size: 14px;
color: #314964;
letter-spacing: -0.13px;
text-align: justify;
}
.input__boolean
{
width: 100%;
background: #FFFFFF;
border: 1px solid #AFB0C3;
border-radius: 5px;
padding: 7px 15px 7px;
font-family: $opensans;
font-size: 14px;
color: #082341;
min-height: 40px;
box-sizing: border-box;
margin-top: 15px;
display: flex;
flex-direction: row;
align-items: center;
line-height: 22px;
overflow: hidden;
}
.input__boolean-content
{
width: 100%;
height: 100%;
outline: none;
border: none;
position: relative;
padding: 0px;
word-break: break-word;
}
.input__boolean img
{
cursor: pointer;
margin-bottom: -6px;
}
.input__boolean--no-focus
{
color: #9A9AA6
}
.input__label-wrap
{
display: flex;
justify-content: space-between;
width: 100%;
position: relative;
}
.boolean-buttons
{
background-color: #007AFF;
padding: 3px 15px;
border-radius: 50px;
color: #fff;
font-family: $roboto;
font-size: 14px;
font-weight: 300;
cursor: pointer;
margin-left: 10px;
}
.boolean-button--img
{
height: 22px;
margin-left: 10px;
}
.boolean-button--no-margin
{
margin: 0;
}
.popper
{
background-color: $darkbg;
font-family: $opensans;
font-size: 12px;
line-height: 14px;
color: #fff;
padding: 4px 12px;
border-color: $darkbg;
box-shadow: 0 5px 12px 0 rgba(49,73,100,0.14);
border-radius: 8px;
}
.filters__helper
{
cursor: pointer;
margin-left: 10px;
margin-bottom: -3px;
}
.popper[x-placement^="top"] .popper__arrow
{
border-color: #082341 transparent transparent transparent;
}
注意:忽略新的Vue,它是从Fiddle粘贴的。我建议使用小提琴来检查代码,重现问题。
在Safari(最新版本)中,如果我键入一个单词,然后单击该单词的某个位置,或者通过键盘箭头将该插入符号移动到该单词中,然后单击输入右侧的标签之一,则该标签应会被添加到被点击单词的中间(在此处进行选择),但会被添加到单词的开头。
tl; dr:单击其中一个标签时,Safari不尊重插入符号的位置。它将标签添加到内容可编辑div的开头,而不是插入符号之前的位置。
答案 0 :(得分:1)
看来您基本上已经找到了答案。这是一个时间问题。
如果您将事件更改为mousedown,则插入符号的位置不会丢失,并且标签会插入正确的位置。
<div id="app">
<div class="input__label-wrap">
<span class="input__label">Cauta</span>
<div style="user-select: none; -webkit-user-select: none">
<span readonly v-on:mousedown="addBooleanTag(b_button)" v-for="b_button in boolean_buttons" class="boolean-buttons">{{b_button.label}}</span>
</div>
</div>
<div class="input__boolean input__boolean--no-focus">
<div
@keydown.enter.prevent
@blur="addPlaceholder"
@keyup="saveCursorLocation($event); fixDelete(); clearHtmlElem($event);"
@input="updateBooleanInput($event); clearHtmlElem($event);"
@paste="pasted"
v-on:click="clearPlaceholder(); saveCursorLocation($event);"
class="input__boolean-content"
ref="divInput"
contenteditable="true">Cuvinte cheie, cautare booleana..</div>
</div>
</div>
https://jsfiddle.net/xmuzp20o/
如果您不想在mousedown上添加实际标签,则可以至少在该事件中保存脱字号的位置,以便在click事件中仍具有正确的位置。