焦点输入时保持选中文本

这个问题已经被问过了,但直到现在还没有有效的答案,所以我很想再次打开它,希望我们能找到破解它的方法.

This question has already been asked but until now there is no working answer so I am tempting to open it again hopefully we can find a hack to it.

我有一个 contentEditable 段落和一个文本输入,当我选择一些文本并单击输入时,选择消失了.

I have a contentEditable paragraph and a text input, when I select some text and click the input, the selection is gone.

所以我尝试在输入 mousedown 时保存选择并在 mouseup 时恢复它,是的 它可以工作(正如预期的那样在 Firefox 中)但是......在 chrome 输入失去焦点 :(

So I've tried to save the selection on input mousedown and to restore it back on mouseup and yeah it works ( as expected in firefox) But... in chrome the input lose focus :(

查看实际操作(使用 chrome):https://jsfiddle.net/mody5/noygdhdu/

这是我使用的代码:

HTML

<p contenteditable="true">
    Select something up here and click the input below
    <br> on firefox the input get the focus and the text still selected.
    <br> on chrome the text still selected but the input lose focus
</p>

    <input type="text" id="special" style="border: solid blue 1px">

javascript

function saveSelection() {
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            return sel.getRangeAt(0);
        }
    } else if (document.selection && document.selection.createRange) {
        return document.selection.createRange();
    }
    return null;
}

function restoreSelection(range) {
    if (range) {
        if (window.getSelection) {
            sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        } else if (document.selection && range.select) {
            range.select();
        }
    }
}


var specialDiv = document.getElementById("special");
var savedSel = null;

specialDiv.onmousedown = function() {

    savedSel = saveSelection(); // save the selection

};

specialDiv.onmouseup = function() {

    restoreSelection(savedSel); // restore the selection

};

推荐答案

<span> 替换选择可能是最简单的方法.您还可以使用 <iframe>,这是 google 在 Google Docs 中使用的,用于在单击 UI 元素时保持对文档内文本的选择.

Replacing selection with a <span> is probably the simplest way. You can also use an <iframe>, which is what google uses in Google Docs to maintain selection of text inside document while clicking UI elements.

使用 <span>,解决方案可能是这样的(此解决方案基于您的原始代码和这里其他人的想法,尤其是 @Bekim Bacaj).

With <span>, the solution might be like this (this solution build on your original code and the ideas of the other people here, especially @Bekim Bacaj).

!function(doc, win) {
  var input = doc.getElementById('special')
  	, editable = doc.getElementById('editable')
    , button = doc.getElementById('button')
    , fragment = null
    , range = null;

	function saveSelection() {  
    if (win.getSelection) {
      sel = win.getSelection();
      if (sel.getRangeAt && sel.rangeCount) {
        return sel.getRangeAt(0);
      }
    } else if (doc.selection && doc.selection.createRange) {
      return doc.selection.createRange();
    }
    return null;
  }
  
  /* Not needed, unless you want also restore selection
  function restoreSelection() {
    if (range) {
      if (win.getSelection) {
        sel = win.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
      } else if (doc.selection && range.select) {
        range.select();
      }
    }
  }
  */
    
  function saveRangeEvent(event) {
    range = saveSelection();
    if (range && !range.collapsed) {
    	fragment = range.cloneContents();
      toggleButton();
    }
  } 
   
  function toggleButton() {
      button.disabled = !fragment || !input.value.match(/^https?:.*/);
  }
  toggleButton();
  
  editable.addEventListener('mouseup', saveRangeEvent);
  editable.addEventListener('keyup', saveRangeEvent);
  button.addEventListener('click', function(event) {
    // insert link
  	var link = doc.createElement('a');
    link.href = input.value;
    input.value = '';
    range.surroundContents(link);
    toggleButton();
  });
  input.addEventListener('keyup', toggleButton);
  input.addEventListener('change', toggleButton);
  input.addEventListener('mousedown', function(event) {
    // create fake selection
    if (fragment) {
      var span = doc.createElement('span');
      span.className = 'selected';
      range.surroundContents(span);
    }
  });
  input.addEventListener('blur', function(event) {
    // remove fake selection
  	if (fragment) {
      range.deleteContents();
      range.insertNode(fragment);  
      //restoreSelection();
    }
    fragment = null;
  }, true);
  
}(document, window)
    
    

.selected {
  background-color: dodgerblue;
  color: white;
}

<p id="editable" contenteditable="true">
  Select something up here and click the input below
  <br>on firefox the input get the focus and the text still selected.
  <br>on chrome the text still selected but the input lose focus
</p>

<table>
  <tr>
    <td>
      <input type="text" id="special" style="border: solid blue 1px" placeholder="insert valid link incl. http://">
    </td>
    <td>
      <button id="button">Add link</button>
    </td>
  </tr>
</table>

链接到 jsFiddle

相关文章