contenteditable, 텍스트 끝에 캐럿 설정 (브라우저 간)


111

Chrome 에서 출력 :

<div id="content" contenteditable="true" style="border:1px solid #000;width:500px;height:40px;">
    hey
    <div>what's up?</div>
<div>
<button id="insert_caret"></button>

나는 FF 가 다음과 같이 보일 것이라고 믿습니다 .

hey
<br />
what's up?

그리고 IE에서 :

hey
<p>what's up?</p>

불행히도 모든 브라우저 <br />가 div 또는 p-tag 대신 a 를 삽입하도록 만드는 좋은 방법이 없습니다 . 또는 적어도 온라인에서 아무것도 찾을 수 없습니다.


어쨌든, 지금 하려는 것은 버튼을 눌렀을 때 캐럿이 텍스트 끝에 설정되기를 원하므로 다음과 같이 보일 것입니다.

hey
what's up?|

이 작업을 수행하는 방법은 모든 브라우저 에서 작동 합니까?

예:

$(document).ready(function()
{
    $('#insert_caret').click(function()
    {
        var ele = $('#content');
        var length = ele.html().length;

        ele.focus();

        //set caret -> end pos
     }
 }

답변:


282

다음 기능은 모든 주요 브라우저에서이를 수행합니다.

function placeCaretAtEnd(el) {
    el.focus();
    if (typeof window.getSelection != "undefined"
            && typeof document.createRange != "undefined") {
        var range = document.createRange();
        range.selectNodeContents(el);
        range.collapse(false);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    } else if (typeof document.body.createTextRange != "undefined") {
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(el);
        textRange.collapse(false);
        textRange.select();
    }
}

placeCaretAtEnd( document.querySelector('p') );
p{ padding:.5em; border:1px solid black; }
<p contentEditable>foo bar </p>

시작 부분에 캐럿을 배치하는 것은 거의 동일합니다 collapse(). 호출에 전달 된 부울을 . 다음은 시작과 끝에 캐럿을 배치하는 함수를 만드는 예입니다.

function createCaretPlacer(atStart) {
    return function(el) {
        el.focus();
        if (typeof window.getSelection != "undefined"
                && typeof document.createRange != "undefined") {
            var range = document.createRange();
            range.selectNodeContents(el);
            range.collapse(atStart);
            var sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        } else if (typeof document.body.createTextRange != "undefined") {
            var textRange = document.body.createTextRange();
            textRange.moveToElementText(el);
            textRange.collapse(atStart);
            textRange.select();
        }
    };
}

var placeCaretAtStart = createCaretPlacer(true);
var placeCaretAtEnd = createCaretPlacer(false);

createTextRange가 표준 함수가 아니기 때문에 Chrome에서 작동하지 않습니다. stackoverflow.com/a/41743191/700206을 참조하십시오 .
whitneyland

@Lee : window.getSelectiondocument.createRange. createTextRange분기 인터넷 익스플로러의 이전 버전입니다.
Tim Down

작성 당시 window.getSelection모든 브라우저의 0.29 % (IE> 8)에서 지원되지 않습니다. 참조 : caniuse.com/#search=window.getSelection
w.stoettinger 2017-10-17

@ TimDown이 작동합니다. +1. 그러나 주석을 추가하여 코드를 설명 할 수도 있습니까? 좋을 것입니다
shinobi

누구나 iframe> body 요소를 대상으로 할 때 캐럿을 끝 (이 코드 사용)으로 설정하는 방법을 알고 있습니까? 본문 요소에는 editablecontent="true"...? placeCaretAtEnd(this);나를 위해 작동하지 않습니다.
RobbTe

6

불행히도 Tim의 훌륭한 대답은 끝에 배치하는 경우에만 효과가 있었고 시작 부분에 배치하기 위해 약간 수정해야했습니다.

function setCaret(target, isStart) {
  const range = document.createRange();
  const sel = window.getSelection();
  if (isStart){
    const newText = document.createTextNode('');
    target.appendChild(newText);
    range.setStart(target.childNodes[0], 0);
  }
  else {
    range.selectNodeContents(target);
  }
  range.collapse(isStart);
  sel.removeAllRanges();
  sel.addRange(range);
  target.focus();
  target.select();
}

확실하지 경우 생각 focus()select()실제로 필요하다.


외부 라이브러리도 도입했습니다. 포커스와 선택이 필요하지 않다고 생각한다면 라인을 주석 처리하고 테스트 해보십시오.
dotnethaggis

감사합니다. jquery를 제거했습니다. 모순되는 결과가 있었음을 기억합니다. 다시 분리 해 보겠습니다.
dimid

1

이 (라이브) 예제는 setCaretAtStartEnd두 개의 인수를 사용하는 간단한 간단한 함수를 보여줍니다 . 캐럿을 배치 할 (편집 가능한) 노드 & 배치 할 위치를 나타내는 부울 (노드의 시작 또는 끝)

const editableElm = document.querySelector('[contenteditable]');

document.querySelectorAll('button').forEach((elm, idx) => 
  elm.addEventListener('click', () => {
    editableElm.focus()
    setCaretAtStartEnd(editableElm, idx) 
  })
)

function setCaretAtStartEnd( node, atEnd ){
  const sel = document.getSelection();
  node = node.firstChild;

  if( sel.rangeCount ){
      ['Start', 'End'].forEach(pos =>
        sel.getRangeAt(0)["set" + pos](node, atEnd ? node.length : 0)
      )
  }
}
[contenteditable]{ padding:5px; border:1px solid; }
<h1 contenteditable>Place the caret anywhere</h1>
<br>
<button>Move caret to start</button>
<button>Move caret to end</button>


-1

Google 클로저 컴파일러를 사용하는 경우 다음을 수행 할 수 있습니다 (Tim의 답변에서 다소 단순화 됨).

function placeCaretAtEnd(el) {
    el.focus();
    range = goog.dom.Range.createFromNodeContents(el);
    range.collapse(false);
    range.select();
}

다음은 ClojureScript에서도 마찬가지입니다.

(defn place-caret-at-end [el] 
   (.focus el)
   (doto (.createFromNodeContents goog.dom.Range el)
         (.collapse false)
         .select))

나는 이것을 Chrome, Safari 및 FireFox에서 테스트했지만 IE에 대해서는 확실하지 않습니다 ...


1
범위 = goog.dom.Range.createFromNodeContents (el); goog.dom이 무엇인가요?
Anh Tú

이것은 나를 위해 일했습니다. @ AnhTú : goog.dom은 클로저 라이브러리에서 제공하는 네임 스페이스입니다.
David Beneš
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.