自動選取某個區域的文字

最近在工作上需要一個功能,就是點選一個按鈕可以全選某個區域內的文字,由於,找了一些解法大多都是針對文 input 的 text 或 textarea 所設計,,後來總算是在 Stack Overflow 發現了完美的解法,根據這個解法我就做出來了可以選取特定區域文字的範例。

範例:select-text-demo01.html

參考:http://goo.gl/uAHGuS

HTML:

<div id="textA">點選 A 會選取我</div>
<div id="textB">點選 B 會選取我</div>
<button id="btnA">按鈕 A</button>
<button id="btnB">按鈕 B</button>

javascript:

function SelectText(element) {
  var doc = document,
    text = doc.getElementById(element),
    range, selection;
  if (doc.body.createTextRange) {
    range = document.body.createTextRange();
    range.moveToElementText(text);
    range.select();
  } else if (window.getSelection) {
    selection = window.getSelection();
    range = document.createRange();
    range.selectNodeContents(text);
    selection.removeAllRanges();
    selection.addRange(range);
  }
}

document.getElementById('btnA').addEventListener('click', function() {
  SelectText('textA');
});
document.getElementById('btnB').addEventListener('click', function() {
  SelectText('textB');
});

判斷式裡的createTextRange只有 IE 支援,所以上面這段程式碼之所以要加上判斷,主要也是區分瀏覽器使用,因為自己不用 IE 也沒辦法測試 ( mac 沒有 IE ),所以就直接忽略第一個判斷式裡頭的東西。

再來可能是自己 javascript 見識淺薄,第一次看到getSelection()createRange()這兩個方法,getSelection()目的在返回一個 selection 對象開始選取,而createRange()則定義了一個範圍 range,在上面的範例裏,使用了selectNodeContents()的方法,讓我們可以全選指定的 DOM 內的文字 ( 應該說選取整個指定的 DOM )。

除了全選,我們也可以使用setStart()以及setEnd()的方法,指定要選取的文字,不過因為這兩個方法是針對「節點 Node」的操作,所以放在裡面的,就是我們要選擇節點,以及從這個節點起算的第幾個字元,因為我們要獲取文字,所以,可以參考以下的程式碼,當我們按下 A 的按鈕,第一行會有部分文字被選取起來,當我們按下 B 的按鈕,換成第二行有部分文字被選取起來。
( 範例:select-text-demo02.html )

function SelectText(element) {
  var doc = document,
    text = doc.getElementById(element),
    range,
    selection;
  if (doc.body.createTextRange) {
    range = document.body.createTextRange();
    range.moveToElementText(text);
    range.select();
  } else if (window.getSelection) {
    selection = window.getSelection();
    range = document.createRange();
    if (element == 'textA') {
      range.setStart(text.firstChild, 1);
      range.setEnd(text.firstChild, 7);
    }
    if (element == 'textB') {
      range.setStart(text.firstChild, 5);
      range.setEnd(text.firstChild, 8);
    }
    selection.removeAllRanges();
    selection.addRange(range);
  }
}

document.getElementById('btnA').addEventListener('click', function() {
  SelectText('textA');
});
document.getElementById('btnB').addEventListener('click', function() {
  SelectText('textB');
});

除了純粹的選取之外,我們也可以使用cloneContents()的方法來同時複製並貼上,使用deleteContents()來刪除,使用extractContents()同時剪下並貼上 ( 移動 ),下面的範例做出三個按鈕,分別套用這三個方法。( 範例:select-text-demo03.html )

var p = document.getElementById('p');

function SelectText(element, check) {
  var doc = document,
    text = doc.getElementById(element),
    range,
    selection;
  if (doc.body.createTextRange) {
    range = document.body.createTextRange();
    range.moveToElementText(text);
    range.select();
  } else if (window.getSelection) {
    selection = window.getSelection();
    range = document.createRange();
    range.setStart(text.firstChild, 1);
    range.setEnd(text.firstChild, 5);
    if (check == 'A') {
      var oFragment = range.cloneContents();
    }
    if (check == 'B') {
      var oFragment = range.extractContents();
    }
    if (check == 'C') {
      var oFragment = range.deleteContents();
    }
    p.appendChild(oFragment);
    selection.removeAllRanges();
    selection.addRange(range);
  }
}

document.getElementById('btnA').addEventListener('click', function() {
  SelectText('text', 'A');
});
document.getElementById('btnB').addEventListener('click', function() {
  SelectText('text', 'B');
});
document.getElementById('btnC').addEventListener('click', function() {
  SelectText('text', 'C');
});

在實作第三個範例的時候,為了要使用innerHTML還是appendChild讓我有點頭疼,因為這邊 range 返回的是 node 對象,如果我們使用innerHTML就會發現出來的是節點的代碼,而並非相對應的內容文字,而使用appendChild是把整個節點放進去,自然就會是內容文字了,這邊其實不是很好理解,找了很多文章總算是有以下這個結論,我想這也應該是我 javascript 沒有深入學好才會出現這種問題吧!

DOM 的三種節點:

最後附上這一篇文章我的參考資料:

有興趣瞧瞧其他新文章嗎?