卿¬ç« ä¸ï¼æä»¬å°ä»ç»ææ¡£ä¸ç鿩以åå¨è¡¨ååæ®µï¼å¦ <input>ï¼ä¸çéæ©ã
JavaScript å¯ä»¥è®¿é®ç°æçéæ©ï¼éæ©/åæ¶å ¨é¨æé¨å DOM èç¹çéæ©ï¼ä»ææ¡£ä¸å 餿éé¨åï¼å°å ¶å è£ å°ä¸ä¸ªæ ç¾ï¼tagï¼ä¸ï¼çã
ä½ å¯ä»¥å¨æ¬ç« æ«å°¾çâæ»ç»âé¨åæ¾å°ä¸äºå¸¸è§çä½¿ç¨æ¹å¼ãå¯è½å°±å·²ç»æ»¡è¶³äºä½ å½åçéæ±ï¼ä½å¦æä½ é è¯»å ¨æï¼å°ä¼ææ´å¤æ¶è·ã
åºå±çï¼underlyingï¼Range å Selection 对象å¾å®¹æææ¡ï¼å æ¤ï¼ä½ ä¸éè¦ä»»ä½è¯çªä¾¿å¯ä»¥ä½¿ç¨å®ä»¬åä½ æ³è¦åçäºå¿ã
èå´
éæ©çåºæ¬æ¦å¿µæ¯ Rangeï¼æ¬è´¨ä¸æ¯ä¸å¯¹âè¾¹çç¹âï¼èå´èµ·ç¹åèå´ç»ç¹ã
卿²¡æä»»ä½åæ°çæ
åµä¸ï¼å建ä¸ä¸ª Range 对象ï¼
let range = new Range();
ç¶åï¼æä»¬å¯ä»¥ä½¿ç¨ range.setStart(node, offset) å range.setEnd(node, offset) æ¥è®¾ç½®éæ©è¾¹çã
æ£å¦ä½ å¯è½çå°ç飿 ·ï¼æä»¬å°è¿ä¸æ¥ä½¿ç¨ Range 对象è¿è¡éæ©ï¼ä½é¦å
让æä»¬å建ä¸äºè¿æ ·ç对象ã
éæ©é¨åææ¬
æè¶£çæ¯ï¼è¿ä¸¤ç§æ¹æ³ä¸ç第ä¸ä¸ªåæ° node é½å¯ä»¥æ¯ææ¬èç¹æå
ç´ èç¹ï¼è第äºä¸ªåæ°çå«ä¹ä¾èµäºæ¤ã
妿 node æ¯ä¸ä¸ªææ¬èç¹ï¼é£ä¹ offset åå¿
é¡»æ¯å
¶ææ¬ä¸çä½ç½®ã
ä¾å¦ï¼å¯¹äºç»å®ç <p>Hello</p>ï¼æä»¬å¯ä»¥åä¸é¢è¿æ ·å建ä¸ä¸ªå
å«åæ¯ âllâ çèå´ï¼
<p id="p">Hello</p>
<script>
let range = new Range();
range.setStart(p.firstChild, 2);
range.setEnd(p.firstChild, 4);
// 对 range è¿è¡ toString å¤çï¼range å伿å
¶å
å«çå
å®¹ä»¥ææ¬çå½¢å¼è¿å
console.log(range); // ll
</script>
å¨è¿éï¼æä»¬è·å <p> ç第ä¸ä¸ªåèç¹ï¼å³ææ¬èç¹ï¼å¹¶æå®å
¶ä¸çææ¬ä½ç½®ï¼
éæ©å ç´ èç¹
æè
ï¼å¦æ node æ¯ä¸ä¸ªå
ç´ èç¹ï¼é£ä¹ offset åå¿
é¡»æ¯åå
ç´ çç¼å·ã
è¿å¯¹äºå建å 嫿´ä¸ªèç¹çèå´å¾æ¹ä¾¿ï¼è䏿¯å¨å ¶ææ¬ä¸çæå¤åæ¢ã
ä¾å¦ï¼æä»¬æä¸ä¸ªæ´å¤æçææ¡£ç段ï¼
<p id="p">Example: <i>italic</i> and <b>bold</b></p>
è¿æ¯å®ç DOM ç»æï¼å å«å ç´ åææ¬èç¹ï¼
让æä»¬ä¸º "Example: <i>italic</i>" 设置ä¸ä¸ªèå´ã
æ£å¦æä»¬æçå°çï¼è¿ä¸ªçè¯æ£å¥½ç± <p> çç´¢å¼ä¸º 0 å 1 ç两个åå
ç´ ç»æã
-
èµ·ç¹ä»¥
<p>ä½ä¸ºç¶èç¹nodeï¼0ä½ä¸ºåç§»éãå æ¤ï¼æä»¬å¯ä»¥å°å ¶è®¾ç½®ä¸º
range.setStart(p, 0)ã -
ç»ç¹ä¹æ¯ä»¥
<p>ä½ä¸ºç¶èç¹nodeï¼ä½ä»¥2ä½ä¸ºåç§»éï¼å®æå®æå¤§èå´ï¼ä½ä¸å æ¬offsetï¼ãå æ¤ï¼æä»¬å¯ä»¥å°å ¶è®¾ç½®ä¸º
range.setEnd(p, 2)ã
示ä¾å¦ä¸ï¼å¦æä½ è¿è¡å®ï¼ä½ å¯ä»¥çå°ææ¬è¢«éä¸ï¼
<p id="p">Example: <i>italic</i> and <b>bold</b></p>
<script>
let range = new Range();
range.setStart(p, 0);
range.setEnd(p, 2);
// èå´ç toString ä»¥ææ¬å½¢å¼è¿åå
¶å
容ï¼ä¸å¸¦æ ç¾
console.log(range); // Example: italic
// å°æ¤èå´åºç¨äºææ¡£éæ©ï¼åææè§£é
document.getSelection().addRange(range);
</script>
è¿æ¯ä¸ä¸ªæ´çµæ´»çæµè¯å°ï¼ä½ å¯ä»¥å¨å ¶ä¸è®¾ç½®èå´å¼å§/ç»æç¼å·ï¼å¹¶æ¢ç´¢åç§æ åµï¼
<p id="p">Example: <i>italic</i> and <b>bold</b></p>
From <input id="start" type="number" value=1> â To <input id="end" type="number" value=4>
<button id="button">Click to select</button>
<script>
button.onclick = () => {
let range = new Range();
range.setStart(p, start.value);
range.setEnd(p, end.value);
// åºç¨éæ©ï¼åææè§£é
document.getSelection().removeAllRanges();
document.getSelection().addRange(range);
};
</script>
ä¾å¦ï¼å¨åä¸ä¸ª <p> ä¸ä»åç§»é 1 å° 4 éæ©å¾å°çèå´ä¸º <i>italic</i> and <b>bold</b>ï¼
æä»¬ä¸æ¯å¿
é¡»å¨ setStart å setEnd ä¸ä½¿ç¨ç¸åçèç¹ãä¸ä¸ªèå´å¯è½ä¼è·¨è¶å¾å¤ä¸ç¸å
³çèç¹ãå¯ä¸è¦æ³¨æçæ¯ç»ç¹è¦å¨èµ·ç¹ä¹åã
éæ©æ´å¤§ççæ®µ
让æä»¬å¨ç¤ºä¾ä¸éæ©ä¸ä¸ªæ´å¤§ççæ®µï¼åè¿æ ·ï¼
æä»¬å·²ç»ç¥éå¦ä½å®ç°å®äºãæä»¬åªéè¦å°èµ·ç¹åç»ç¹è®¾ç½®ä¸ºææ¬èç¹ä¸çç¸å¯¹åç§»éå³å¯ã
æä»¬éè¦å建ä¸ä¸ªèå´ï¼å®ï¼
- ä»
<p>ç第ä¸ä¸ªåèç¹çä½ç½® 2 å¼å§ï¼éæ© "Example: " ä¸é¤åä¸¤ä¸ªåæ¯å¤çææåæ¯ï¼ - å°
<b>ç第ä¸ä¸ªåèç¹çä½ç½® 3 ç»æï¼éæ© âboldâ çåä¸ä¸ªåæ¯ï¼å°±è¿äºï¼ï¼
<p id="p">Example: <i>italic</i> and <b>bold</b></p>
<script>
let range = new Range();
range.setStart(p.firstChild, 2);
range.setEnd(p.querySelector('b').firstChild, 3);
console.log(range); // ample: italic and bol
// ä½¿ç¨æ¤èå´è¿è¡éæ©ï¼åææè§£éï¼
window.getSelection().addRange(range);
</script>
æ£å¦ä½ æçå°çï¼éæ©æä»¬æ³è¦çèå´å ¶å®å¾å®¹æå®ç°ã
妿æä»¬æ³å°èç¹ä½ä¸ºä¸ä¸ªæ´ä½ï¼æä»¬å¯ä»¥å°å
ç´ ä¼ å
¥ setStart/setEndãå¦åï¼æä»¬å¯ä»¥å¨ææ¬å±çº§ä¸è¿è¡æä½ã
range 屿§
æä»¬å¨ä¸é¢ç示ä¾ä¸å建ç range 对象å
·æä»¥ä¸å±æ§ï¼
startContainerï¼startOffsetââ èµ·å§èç¹ååç§»éï¼- å¨ä¸ä¾ä¸ï¼å嫿¯
<p>ä¸ç第ä¸ä¸ªææ¬èç¹å2ã
- å¨ä¸ä¾ä¸ï¼å嫿¯
endContainerï¼endOffsetââ ç»æèç¹ååç§»éï¼- å¨ä¸ä¾ä¸ï¼å嫿¯
<b>ä¸ç第ä¸ä¸ªææ¬èç¹å3ã
- å¨ä¸ä¾ä¸ï¼å嫿¯
collapsedââ å¸å°å¼ï¼å¦æèå´å¨åä¸ç¹ä¸å¼å§åç»æï¼æä»¥èå´å 没æå 容ï¼å为trueï¼- å¨ä¸ä¾ä¸ï¼
false
- å¨ä¸ä¾ä¸ï¼
commonAncestorContainerââ å¨èå´å çææèç¹ä¸æè¿çå ±åç¥å èç¹ï¼- å¨ä¸ä¾ä¸ï¼
<p>
- å¨ä¸ä¾ä¸ï¼
éæ©èå´çæ¹æ³
æè®¸å¤ä¾¿å©çæ¹æ³å¯ä»¥æçºµèå´ã
æä»¬å·²ç»è§è¿äº setStart å setEndï¼è¿è¿æå
¶ä»ç±»ä¼¼çæ¹æ³ã
设置èå´çèµ·ç¹ï¼
setStart(node, offset)å°èµ·ç¹è®¾ç½®å¨ï¼nodeä¸çä½ç½®offsetsetStartBefore(node)å°èµ·ç¹è®¾ç½®å¨ï¼nodeåé¢setStartAfter(node)å°èµ·ç¹è®¾ç½®å¨ï¼nodeåé¢
设置èå´çç»ç¹ï¼ç±»ä¼¼çæ¹æ³ï¼ï¼
setEnd(node, offset)å°ç»ç¹è®¾ç½®ä¸ºï¼nodeä¸çä½ç½®offsetsetEndBefore(node)å°ç»ç¹è®¾ç½®ä¸ºï¼nodeåé¢setEndAfter(node)å°ç»ç¹è®¾ç½®ä¸ºï¼nodeåé¢
仿æ¯ä¸è®²ï¼setStart/setEnd å¯ä»¥åä»»ä½äºï¼ä½æ¯æ´å¤çæ¹æ³æä¾äºæ´å¤çä¾¿æ·æ§ã
卿æè¿äºæ¹æ³ä¸ï¼node é½å¯ä»¥æ¯ææ¬æè
å
ç´ èç¹ï¼å¯¹äºææ¬èç¹ï¼åç§»é offset è·¨è¶çæ¯å¾å¤åæ¯ï¼è对äºå
ç´ èç¹åè·¨è¶çæ¯å¾å¤åèç¹ã
æ´å¤å建èå´çæ¹æ³ï¼
selectNode(node)设置èå´ä»¥éæ©æ´ä¸ªnodeselectNodeContents(node)设置èå´ä»¥éæ©æ´ä¸ªnodeçå 容collapse(toStart)妿toStart=trueå设置 end=startï¼å¦å设置 start=endï¼ä»èæå èå´cloneRange()å建ä¸ä¸ªå ·æç¸åèµ·ç¹/ç»ç¹çæ°èå´
ç¼è¾èå´çæ¹æ³
å建èå´åï¼æä»¬å¯ä»¥ä½¿ç¨ä»¥ä¸æ¹æ³æä½å ¶å 容ï¼
deleteContents()ââ ä»ææ¡£ä¸å é¤èå´ä¸çå 容extractContents()ââ ä»ææ¡£ä¸å é¤èå´ä¸çå 容ï¼å¹¶å°å é¤çå 容ä½ä¸º DocumentFragment è¿åcloneContents()ââ å¤å¶èå´ä¸çå 容ï¼å¹¶å°å¤å¶çå 容ä½ä¸º DocumentFragment è¿åinsertNode(node)ââ å¨èå´çèµ·å§å¤å°nodeæå ¥ææ¡£surroundContents(node)ââ 使ç¨nodeå°æéèå´ä¸çå 容å 裹起æ¥ãè¦ä½¿æ¤æä½ææï¼å该èå´å¿ é¡»å å«å ¶ä¸ææå ç´ çå¼å§åç»ææ ç¾ï¼ä¸è½å<i>abcè¿æ ·çé¨åèå´ã
使ç¨è¿äºæ¹æ³ï¼æä»¬åºæ¬ä¸å¯ä»¥å¯¹éå®çèç¹æ§è¡ä»»ä½æä½ã
è¿æ¯å¨æµè¯å°ä¸çå°å®ä»¬çå®é ææï¼
ç¹å»æé®è¿è¡æéå
容ä¸çæ¹æ³ï¼ç¹å» "resetExample" è¿è¡éç½®ã
<p id="p">Example: <i>italic</i> and <b>bold</b></p>
<p id="result"></p>
<script>
let range = new Range();
// ä¸é¢æ¼ç¤ºäºä¸è¿°çæ¯ä¸ªæ¹æ³ï¼
let methods = {
deleteContents() {
range.deleteContents()
},
extractContents() {
let content = range.extractContents();
result.innerHTML = "";
result.append("extracted: ", content);
},
cloneContents() {
let content = range.cloneContents();
result.innerHTML = "";
result.append("cloned: ", content);
},
insertNode() {
let newNode = document.createElement('u');
newNode.innerHTML = "NEW NODE";
range.insertNode(newNode);
},
surroundContents() {
let newNode = document.createElement('u');
try {
range.surroundContents(newNode);
} catch(e) { console.log(e) }
},
resetExample() {
p.innerHTML = `Example: <i>italic</i> and <b>bold</b>`;
result.innerHTML = "";
range.setStart(p.firstChild, 2);
range.setEnd(p.querySelector('b').firstChild, 3);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
};
for(let method in methods) {
document.write(`<div><button onclick="methods.${method}()">${method}</button></div>`);
}
methods.resetExample();
</script>
è¿ææ¯è¾èå´çæ¹æ³ï¼ä½æ¯å¾å°ä½¿ç¨ãå½ä½ éè¦å®ä»¬æ¶ï¼è¯·åè è§è æ MDN æåã
éæ©
Range æ¯ç¨äºç®¡çéæ©èå´çéç¨å¯¹è±¡ã尽管å建ä¸ä¸ª Range 并䏿å³çæä»¬å¯ä»¥å¨å±å¹ä¸çå°ä¸ä¸ªå
容鿩ã
æä»¬å¯ä»¥å建 Range å¯¹è±¡å¹¶ä¼ éå®ä»¬ ââ ä½å®ä»¬å¹¶ä¸ä¼å¨è§è§ä¸éæ©ä»»ä½å
容ã
ææ¡£éæ©æ¯ç± Selection 对象表示çï¼å¯éè¿ window.getSelection() æ document.getSelection() æ¥è·åãä¸ä¸ªéæ©å¯ä»¥å
æ¬é¶ä¸ªæå¤ä¸ªèå´ãè³å°ï¼Selection API è§è æ¯è¿ä¹è¯´çãä¸è¿å®é
ä¸ï¼åªæ Firefox å
è®¸ä½¿ç¨ Ctrl+click (Mac ä¸ç¨ Cmd+click) å¨ææ¡£ä¸éæ©å¤ä¸ªèå´ã
è¿æ¯å¨ Firefox ä¸åçä¸ä¸ªå ·æ 3 个èå´çéæ©çæªå¾ï¼
å
¶ä»æµè§å¨æå¤æ¯æ 1 个èå´ãæ£å¦æä»¬å°çå°çï¼æäº Selection æ¹æ³æç¤ºå¯è½æå¤ä¸ªèå´ï¼ä½åæ ·ï¼å¨é¤ Firefox ä¹å¤çæææµè§å¨ä¸ï¼è崿夿¯ 1ã
è¿æ¯ä¸ä¸ªå°ä¾åï¼å°å½åçéæ©ï¼éæ©ä¸äºå 容ç¶åç¹å»æé®ï¼ä»¥ææ¬ç形弿¾ç¤ºåºæ¥ï¼
鿩屿§
å¦åæè¿°ï¼ç论ä¸ä¸ä¸ªéæ©å¯è½å å«å¤ä¸ªèå´ãæä»¬å¯ä»¥ä½¿ç¨ä¸é¢è¿ä¸ªæ¹æ³è·åè¿äºèå´å¯¹è±¡ï¼
getRangeAt(i)ââ è·å第i个èå´ï¼iä»0å¼å§ãå¨é¤ Firefox ä¹å¤çæææµè§å¨ä¸ï¼ä» 使ç¨0ã
æ¤å¤ï¼è¿ææ´æ¹ä¾¿ç屿§ã
ä¸èå´ç±»ä¼¼ï¼éæ©çèµ·ç¹è¢«ç§°ä¸ºâéç¹ï¼anchorï¼âï¼ç»ç¹è¢«ç§°ä¸ºâç¦ç¹ï¼focusï¼âã
主è¦ç鿩屿§æï¼
anchorNodeââ éæ©çèµ·å§èç¹ï¼anchorOffsetââ éæ©å¼å§çanchorNodeä¸çåç§»éï¼focusNodeââ éæ©çç»æèç¹ï¼focusOffsetââ éæ©ç»æå¤focusNodeçåç§»éï¼isCollapsedââ 妿æªéæ©ä»»ä½å 容ï¼ç©ºèå´ï¼æä¸åå¨ï¼å为trueãrangeCountââ éæ©ä¸çèå´æ°ï¼é¤ Firefox å¤ï¼å ¶ä»æµè§å¨æå¤ä¸º1ã
éæ©ï¼selectionï¼çéç¹/ç¦ç¹å Range çèµ·ç¹åç»ç¹æä¸ä¸ªå¾éè¦çåºå«ã
æ£å¦æä»¬æç¥éçï¼Range 对象çèµ·ç¹å¿
é¡»å¨å
¶ç»ç¹ä¹åã
ä½å¯¹äºéæ©ï¼å¹¶ä¸æ»æ¯è¿æ ·çã
æä»¬å¯ä»¥å¨ä¸¤ä¸ªæ¹åä¸ä½¿ç¨é¼ æ è¿è¡éæ©ï¼âä»å·¦å°å³âæâä»å³å°å·¦âã
æ¢å¥è¯è¯´ï¼å½æä¸é¼ æ æé®ï¼ç¶åå®å¨ææ¡£ä¸ååç§»å¨æ¶ï¼å®ç»æçä½ç½®ï¼ç¦ç¹ï¼å°å¨å®å¼å§çä½ç½®ï¼éç¹ï¼ä¹åã
ä¾å¦ï¼å¦æç¨æ·ä½¿ç¨é¼ æ ä» âExampleâ å¼å§éæ©å° âitalicâï¼
使¯ï¼æä»¬ä¹å¯ä»¥ä»åååè¿è¡ç¸åçéæ©ï¼ä» âitalicâ å° âExampleâï¼ä»åååï¼ï¼è¿æ ·å®ç»æçä½ç½®ï¼ç¦ç¹ï¼å°å¨å®å¼å§çä½ç½®ï¼éç¹ï¼ä¹åã
éæ©äºä»¶
æä¸äºäºä»¶å¯ä»¥è·è¸ªéæ©ï¼
elem.onselectstartââ å½å¨å ç´elemä¸ï¼æå¨å ¶å é¨ï¼å¼å§éæ©æ¶ãä¾å¦ï¼å½ç¨æ·å¨å ç´elem䏿ä¸é¼ æ æé®å¹¶å¼å§ç§»å¨æéæ¶ã- 黿¢é»è®¤è¡ä¸ºåæ¶äºéæ©çå¼å§ãå æ¤ï¼ä»è¯¥å ç´ å¼å§éæ©åå¾ä¸å¯è½ï¼ä½è¯¥å ç´ ä»ç¶æ¯å¯éæ©çãç¨æ·åªéè¦ä»å ¶ä»å°æ¹å¼å§éæ©ã
document.onselectionchangeââ å½éæ©åçååæå¼å§æ¶ã- 请注æï¼æ¤å¤çç¨åºåªè½å¨
documentä¸è®¾ç½®ãå®è·è¸ªçæ¯documentä¸çææéæ©ã
- 请注æï¼æ¤å¤çç¨åºåªè½å¨
éæ©è·è¸ªæ¼ç¤º
ä¸é¢æ¯ä¸ä¸ªå°ä¾åï¼å®è·è¸ªäº document ä¸å½åçéæ©ï¼å¹¶å°éæ©è¾¹çæ¾ç¤ºåºæ¥ï¼
<p id="p">Select me: <i>italic</i> and <b>bold</b></p>
From <input id="from" disabled> â To <input id="to" disabled>
<script>
document.onselectionchange = function() {
let selection = document.getSelection();
let {anchorNode, anchorOffset, focusNode, focusOffset} = selection;
// anchorNode å focusNode éå¸¸æ¯ææ¬èç¹
from.value = `${anchorNode?.data}, offset ${anchorOffset}`;
to.value = `${focusNode?.data}, offset ${focusOffset}`;
};
</script>
éæ©å¤å¶æ¼ç¤º
å¤å¶æéå 容æä¸¤ç§æ¹å¼ï¼
- æä»¬å¯ä»¥ä½¿ç¨
document.getSelection().toString()æ¥è·åå ¶ææ¬å½¢å¼ã - æ¤å¤ï¼æ³è¦å¤å¶æ´ä¸ª DOM èç¹ï¼ä¾å¦ï¼å¦ææä»¬éè¦ä¿æå
¶æ ¼å¼ä¸åï¼æä»¬å¯ä»¥ä½¿ç¨
getRangeAt(...)è·ååºå±çï¼underlyingï¼èå´ãRange对象è¿å ·æcloneContents()æ¹æ³ï¼è¯¥æ¹æ³ä¼æ·è´èå´ä¸çå 容并以DocumentFragmentçå½¢å¼è¿åï¼æä»¬å¯ä»¥å°è¿ä¸ªè¿åå¼æå ¥å°å ¶ä»ä½ç½®ã
ä¸é¢æ¯å°æéå 容å¤å¶ä¸ºææ¬å DOM èç¹çæ¼ç¤ºï¼
<p id="p">Select me: <i>italic</i> and <b>bold</b></p>
Cloned: <span id="cloned"></span>
<br>
As text: <span id="astext"></span>
<script>
document.onselectionchange = function() {
let selection = document.getSelection();
cloned.innerHTML = astext.innerHTML = "";
// ä»èå´å¤å¶ DOM èç¹ï¼è¿éæä»¬æ¯æå¤éï¼
for (let i = 0; i < selection.rangeCount; i++) {
cloned.append(selection.getRangeAt(i).cloneContents());
}
// è·åä¸ºææ¬å½¢å¼
astext.innerHTML += selection;
};
</script>
éæ©æ¹æ³
æä»¬å¯ä»¥éè¿æ·»å /ç§»é¤èå´æ¥å¤çéæ©ï¼
getRangeAt(i)ââ è·åä»0å¼å§ç第 i 个èå´ãå¨é¤ Firefox ä¹å¤çæææµè§å¨ä¸ï¼ä» 使ç¨0ãaddRange(range)ââ å°rangeæ·»å å°éæ©ä¸ã妿鿩已æå ³èçèå´ï¼åé¤ Firefox å¤çæææµè§å¨é½å°å¿½ç¥è¯¥è°ç¨ãremoveRange(range)ââ ä»éæ©ä¸å é¤rangeãremoveAllRanges()ââ å 餿æèå´ãempty()ââremoveAllRangesçå«åã
è¿æä¸äºæ¹ä¾¿çæ¹æ³å¯ä»¥ç´æ¥æä½éæ©èå´ï¼èæ éä¸é´ç Range è°ç¨ï¼
collapse(node, offset)ââ ç¨ä¸ä¸ªæ°çèå´æ¿æ¢éå®çèå´ï¼è¯¥æ°èå´ä»ç»å®çnodeå¤å¼å§ï¼å°åç§»offsetå¤ç»æãsetPosition(node, offset)ââcollapseçå«åãcollapseToStart()ââ æå ï¼æ¿æ¢ä¸ºç©ºèå´ï¼å°éæ©èµ·ç¹ï¼collapseToEnd()ââ æå å°éæ©ç»ç¹ï¼extend(node, offset)ââ å°éæ©çç¦ç¹ï¼focusï¼ç§»å°ç»å®çnodeï¼ä½ç½®åç§»offsetï¼setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset)ââ ç¨ç»å®çèµ·ç¹anchorNode/anchorOffsetåç»ç¹focusNode/focusOffsetæ¥æ¿æ¢éæ©èå´ãéä¸å®ä»¬ä¹é´çææå 容ãselectAllChildren(node)ââ éæ©nodeçææåèç¹ãdeleteFromDocument()ââ ä»ææ¡£ä¸å 餿鿩çå 容ãcontainsNode(node, allowPartialContainment = false)ââ æ£æ¥éæ©ä¸æ¯å¦å å«nodeï¼è¥ç¬¬äºä¸ªåæ°æ¯trueï¼ååªéå å«nodeçé¨åå 容å³å¯ï¼
对äºå¤§å¤æ°éæ±ï¼è¿äºæ¹æ³å°±å¤äºï¼æ é访é®åºå±çï¼underlyingï¼Range 对象ã
ä¾å¦ï¼éæ©æ®µè½ <p> çå
¨é¨å
容ï¼
<p id="p">Select me: <i>italic</i> and <b>bold</b></p>
<script>
// ä» <p> ç第 0 个åèç¹éæ©å°æåä¸ä¸ªåèç¹
document.getSelection().setBaseAndExtent(p, 0, p, p.childNodes.length);
</script>
使ç¨èå´æ¥å®æåä¸ä¸ªæä½ï¼
<p id="p">Select me: <i>italic</i> and <b>bold</b></p>
<script>
let range = new Range();
range.selectNodeContents(p); // æè
ä¹å¯ä»¥ä½¿ç¨ selectNode(p) æ¥éæ© <p> æ ç¾
document.getSelection().removeAllRanges(); // æ¸
é¤ç°æéæ©ï¼å¦ææçè¯ï¼
document.getSelection().addRange(range);
</script>
å¦æå¨ææ¡£ä¸å·²åå¨éæ©ï¼åé¦å
ä½¿ç¨ removeAllRanges() å°å
¶æ¸
空ãç¶åæ·»å èå´ãå¦åï¼é¤ Firefox å¤çæææµè§å¨é½å°å¿½ç¥æ°èå´ã
æäºéæ©æ¹æ³ä¾å¤ï¼å®ä»¬ä¼æ¿æ¢ç°æçéæ©ï¼ä¾å¦ setBaseAndExtentã
è¡¨åæ§ä»¶ä¸çéæ©
è¯¸å¦ input å textarea ç表åå
ç´ æä¾äº ä¸ç¨çéæ© APIï¼æ²¡æ Selection æ Range 对象ãç±äºè¾å
¥å¼æ¯çº¯ææ¬è䏿¯ HTMLï¼å æ¤ä¸éè¦æ¤ç±»å¯¹è±¡ï¼ä¸åé½å徿´å ç®åã
屿§ï¼
input.selectionStartââ éæ©çèµ·å§ä½ç½®ï¼å¯åï¼ï¼input.selectionEndââ éæ©çç»æä½ç½®ï¼å¯åï¼ï¼input.selectionDirectionââ éæ©æ¹åï¼å ¶ä¸ä¹ä¸ï¼âforwardâï¼âbackwardâ æ ânoneâï¼ä¾å¦ä½¿ç¨é¼ æ åå»è¿è¡çéæ©ï¼ï¼
äºä»¶ï¼
input.onselectââ å½æä¸ªä¸è¥¿è¢«éæ©æ¶è§¦åã
æ¹æ³ï¼
-
input.select()ââ éæ©ææ¬æ§ä»¶ä¸çææå 容ï¼å¯ä»¥æ¯textareaè䏿¯inputï¼ï¼ -
input.setSelectionRange(start, end, [direction])ââ å¨ç»å®æ¹åä¸ï¼å¯éï¼ï¼ä»startä¸ç´éæ©å°endã -
input.setRangeText(replacement, [start], [end], [selectionMode])ââ ç¨æ°ææ¬æ¿æ¢èå´ä¸çææ¬ãå¯éåæ°
startåendï¼å¦ææä¾çè¯ï¼å设置èå´çèµ·ç¹åç»ç¹ï¼å¦å使ç¨ç¨æ·çéæ©ãæåä¸ä¸ªåæ°
selectionModeå³å®æ¿æ¢ææ¬åå¦ä½è®¾ç½®éæ©ãå¯è½çå¼ä¸ºï¼"select"ââ å°éæ©æ°æå ¥çææ¬ã"start"ââ éæ©èå´å°å¨æå ¥çææ¬ä¹åæå ï¼å æ å°å¨å ¶ä¹åï¼ã"end"ââ éæ©èå´å°å¨æå ¥çææ¬ä¹åæå ï¼å æ å°ç´§éå ¶åï¼ã"preserve"ââ å°è¯ä¿çéæ©ãè¿æ¯é»è®¤å¼ã
ç°å¨ï¼è®©æä»¬ççè¿äºæ¹æ³çå®é 使ç¨ã
示ä¾ï¼è·è¸ªéæ©
ä¾å¦ï¼æ¤æ®µä»£ç ä½¿ç¨ onselect äºä»¶æ¥è·è¸ªéæ©ï¼
<textarea id="area" style="width:80%;height:60px">
Selecting in this text updates values below.
</textarea>
<br>
From <input id="from" disabled> â To <input id="to" disabled>
<script>
area.onselect = function() {
from.value = area.selectionStart;
to.value = area.selectionEnd;
};
</script>
请注æï¼
onselectæ¯å¨æé¡¹è¢«éæ©æ¶è§¦åï¼èå¨éæ©è¢«å 餿¶ä¸è§¦åã- æ ¹æ® è§èï¼è¡¨åæ§ä»¶å
çéæ©ä¸åºè¯¥è§¦å
document.onselectionchangeäºä»¶ï¼å 为å®ä¸documentéæ©åèå´ä¸ç¸å ³ãä¸äºæµè§å¨ä¼çæå®ï¼ä½æä»¬ä¸åºè¯¥ä¾èµå®ã
示ä¾ï¼ç§»å¨å æ
æä»¬å¯ä»¥æ´æ¹ selectionStart å selectionEndï¼äºè
设å®äºéæ©ã
ä¸ä¸ªéè¦çè¾¹çæ
嵿¯ selectionStart å selectionEnd å½¼æ¤ç¸çã飿£æ¯å
æ ä½ç½®ãæè
ï¼æ¢å¥è¯è¯´ï¼å½æªéæ©ä»»ä½å
容æ¶ï¼éæ©ä¼æå å¨å
æ ä½ç½®ã
å æ¤ï¼éè¿å° selectionStart å selectionEnd 设置为ç¸åçå¼ï¼æä»¬å¯ä»¥ç§»å¨å
æ ã
ä¾å¦ï¼
<textarea id="area" style="width:80%;height:60px">
Focus on me, the cursor will be at position 10.
</textarea>
<script>
area.onfocus = () => {
// 设置é¶å»¶è¿ setTimeout 以卿µè§å¨ "focus" è¡ä¸ºå®æåè¿è¡
setTimeout(() => {
// æä»¬å¯ä»¥è®¾ç½®ä»»ä½éæ©
// 妿 start=endï¼åå
æ å°±ä¼å¨è¯¥ä½ç½®
area.selectionStart = area.selectionEnd = 10;
});
};
</script>
示ä¾ï¼ä¿®æ¹éæ©
å¦è¦ä¿®æ¹éæ©çå
å®¹ï¼æä»¬å¯ä»¥ä½¿ç¨ input.setRangeText() æ¹æ³ãå½ç¶ï¼æä»¬å¯ä»¥è¯»å selectionStart/Endï¼å¹¶å¨äºè§£éæ©çæ
åµä¸æ´æ¹ value çç¸åºåå符串ï¼ä½æ¯ setRangeText åè½æ´å¼ºå¤§ï¼éå¸¸æ´æ¹ä¾¿ã
飿¯ä¸ä¸ªæç¹å¤æçæ¹æ³ã使ç¨å ¶æç®åçååæ°å½¢å¼ï¼å®å¯ä»¥æ¿æ¢ç¨æ·éæ©çèå´å¹¶å é¤è¯¥éæ©ã
ä¾å¦ï¼è¿éçç¨æ·çéæ©å°è¢«å
è£
å¨ *...* ä¸ï¼
<input id="input" style="width:200px" value="Select here and click the button">
<button id="button">Wrap selection in stars *...*</button>
<script>
button.onclick = () => {
if (input.selectionStart == input.selectionEnd) {
return; // ä»ä¹é½æ²¡é
}
let selected = input.value.slice(input.selectionStart, input.selectionEnd);
input.setRangeText(`*${selected}*`);
};
</script>
ä½¿ç¨æ´å¤åæ°ï¼æä»¬å¯ä»¥è®¾ç½®èå´ start å endã
å¨ä¸é¢è¿ä¸ªç¤ºä¾ä¸ï¼æä»¬å¨è¾å
¥ææ¬ä¸æ¾å° "THIS"ï¼å°å
¶æ¿æ¢ï¼å¹¶ä¿ææ¿æ¢ææ¬çéä¸ç¶æï¼
<input id="input" style="width:200px" value="Replace THIS in text">
<button id="button">Replace THIS</button>
<script>
button.onclick = () => {
let pos = input.value.indexOf("THIS");
if (pos >= 0) {
input.setRangeText("*THIS*", pos, pos + 4, "select");
input.focus(); // èç¦ï¼focusï¼ï¼ä»¥ä½¿éæ©å¯è§
}
};
</script>
示ä¾ï¼å¨å æ å¤æå ¥
妿æªéæ©ä»»ä½å
å®¹ï¼æè
æä»¬å¨ setRangeText ä¸ä½¿ç¨äºç¸åç start å endï¼åä»
æå
¥æ°ææ¬ï¼ä¸ä¼å é¤ä»»ä½å
容ã
æä»¬ä¹å¯ä»¥ä½¿ç¨ setRangeText å¨âå
æ å¤âæå
¥ä¸äºä¸è¥¿ã
è¿æ¯ä¸ä¸ªæé®ï¼æä¸åä¼å¨å
æ ä½ç½®æå
¥ "HELLO"ï¼ç¶åå
æ ç´§éå
¶åã妿鿩ä¸ä¸ºç©ºï¼åå°å
¶æ¿æ¢ï¼æä»¬å¯ä»¥éè¿æ¯è¾ selectionStart!=selectionEnd æ¥è¿è¡æ£æ¥ï¼ä¸ºç©ºåæ§è¡å
¶ä»æä½ï¼ï¼
<input id="input" style="width:200px" value="Text Text Text Text Text">
<button id="button">Insert "HELLO" at cursor</button>
<script>
button.onclick = () => {
input.setRangeText("HELLO", input.selectionStart, input.selectionEnd, "end");
input.focus();
};
</script>
使ä¸å¯é
è¦ä½¿æäºå 容ä¸å¯éï¼æä¸ç§æ¹å¼ï¼
-
ä½¿ç¨ CSS 屿§
user-select: noneã<style> #elem { user-select: none; } </style> <div>Selectable <div id="elem">Unselectable</div> Selectable</div>è¿æ ·ä¸å è®¸éæ©ä»
elemå¼å§ã使¯ç¨æ·å¯ä»¥å¨å ¶ä»å°æ¹å¼å§éæ©ï¼å¹¶å°elemå å«å¨å ãç¶å
elemå°æä¸ºdocument.getSelection()çä¸é¨åï¼å æ¤éæ©å®é åçäºï¼ä½æ¯å¨å¤å¶ç²è´´ä¸ï¼å ¶å 容é常ä¼è¢«å¿½ç¥ã -
鲿¢
onselectstartæmousedownäºä»¶ä¸çé»è®¤è¡ä¸ºã<div>Selectable <div id="elem">Unselectable</div> Selectable</div> <script> elem.onselectstart = () => false; </script>è¿æ ·å¯ä»¥é²æ¢å¨
elemä¸å¼å§éæ©ï¼ä½æ¯è®¿é®è å¯ä»¥å¨å¦ä¸ä¸ªå ç´ ä¸å¼å§éæ©ï¼ç¶åæ©å±å°elemãå½åä¸è¡ä¸ºä¸æå¦ä¸ä¸ªäºä»¶å¤çç¨åºè§¦åéæ©æ¶ï¼ä¾å¦
mousedownï¼ï¼è¿ä¼å¾æ¹ä¾¿ãå æ¤æä»¬ç¦ç¨éæ©ä»¥é¿å å²çªï¼ä»ç¶å 许å¤å¶elemå 容ã -
æä»¬è¿å¯ä»¥ä½¿ç¨
document.getSelection().empty()æ¥å¨éæ©åç忏 é¤éæ©ãå¾å°ä½¿ç¨è¿ç§æ¹æ³ï¼å 为è¿ä¼å¨éæ©é¡¹æ¶å¤±æ¶å¯¼è´ä¸å¿ è¦çéªçã
åè
- DOM è§èï¼èå´ï¼Rangeï¼
- éæ©ï¼Selectionï¼API
- HTML è§èï¼ç¨äºææ¬æ§ä»¶éæ©ç API
æ»ç»
æä»¬ä»ç»äºç¨äºéæ©ç两ç§ä¸åç APIï¼
- å¯¹äºææ¡£ï¼
SelectionåRange对象ã - 对äº
inputï¼textareaï¼å ¶ä»æ¹æ³å屿§ã
第äºä¸ª API é常ç®åï¼å 为å®å¤ççæ¯ææ¬ã
æå¸¸ç¨çæ¹æ¡ä¸è¬æ¯ï¼
- è·åéæ©ï¼
let selection = document.getSelection(); let cloned = /* è¦å°æéçèç¹å éå°çå ç´ */; // ç¶åå° Range æ¹æ³åºç¨äº selection.getRangeAt(0) // æè ï¼åè¿æ ·ï¼ç¨äºææèå´ï¼ä»¥æ¯æå¤é for (let i = 0; i < selection.rangeCount; i++) { cloned.append(selection.getRangeAt(i).cloneContents()); } - è®¾ç½®éæ©
let selection = document.getSelection(); // ç´æ¥ï¼ selection.setBaseAndExtent(...from...to...); // æè æä»¬å¯ä»¥å建ä¸ä¸ªèå´å¹¶ï¼ selection.removeAllRanges(); selection.addRange(range);
æåï¼å
³äºå
æ ãå¨è¯¸å¦ <textarea> ä¹ç±»çå¯ç¼è¾å
ç´ ä¸ï¼å
æ çä½ç½®å§ç»ä½äºéæ©çèµ·ç¹æç»ç¹ãæä»¬å¯ä»¥éè¿è®¾ç½® elem.selectionStart å elem.selectionEnd æ¥è·åå
æ ä½ç½®æç§»å¨å
æ ã
è¯è®º
<code>æ ç¾æå ¥åªæå 个è¯ç代ç ï¼æå ¥å¤è¡ä»£ç å¯ä»¥ä½¿ç¨<pre>æ ç¾ï¼å¯¹äºè¶ è¿ 10 è¡ç代ç ï¼å»ºè®®ä½ ä½¿ç¨æ²ç®±ï¼plnkrï¼JSBinï¼codepenâ¦ï¼