光标处理, 需要一个总结

contenteditable的设置光标方式:

//得到selection
var sel = window.getSelection(); //这个是live的
var range = sel.getRangeAt(0);   // 这个不是live. 如果没有caret, 那么这个就拿不到


//得到光标
window.getSelection().anchorOffset;

//设置光标
window.getSelection().collapse(editor, 0);

//得到range
range = window.getSelection().getRangeAt(0); //0代表第一个拖蓝
expandedSelRange = range.cloneRange(); //range可能要改变, 比如插入node.

//设置range      
expandedSelRange.setEndAfter(lastNode);//有答案加了这一句, 因为插入range的内容是最后的node.
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);

光标处插入

function insertHtmlAtCursor(html) {
  var range=window.getSelection().getRangeAt(0);
  var node = range.createContextualFragment(html);//这个有问题.
  var newNode = document.createTextNode('不用fregment???'); //这个就OK了. 
  range.deleteContents();// 某些答案用了这个. 删除了range现有内容.
  range.insertNode(node);
}
var tagString = "<div>I am a div node</div>";
var range = document.createRange();
range.selectNode(editor); //指定插入位置editor
var documentFragment = range.createContextualFragment(tagString);
document.body.appendChild(documentFragment);

包裹选蓝内容

var range = document.getSelection().getRangeAt(0);
var nnode = document.createElement("b");
range.surroundContents(nnode);
nnode.innerHTML = "Some bold text";

得到光标所在位置和内容

var sel = document.getSelection(),
    nd = sel.anchorNode, //这里拿到node
    text = nd.textContent.slice(0, sel.focusOffset);
var line=text.split("\n").length;
var col=text.split("\n").pop().length;
alert("row:"+line+", col:"+col )

得到光标做在的node, 没有看到直接得到element的方法

var sel = window.getSelection();
var range = sel.getRangeAt(0);

//selection方法   拿到node, 然后拿到nodeValue
sel.focusNode.nodeValue 
sel.anchorNode.nodeValue  

//range方法   拿到node, 然后拿到nodeValue
range.commonAncestorContainer.nodeValue 
range.startContainer.nodeValue 
range.endContainer.nodeValue 

//selection方法   拿到具体光标在node中的位置: 
sel.focusOffset 
sel.anchorOffset

//range方法   拿到具体光标在node中的位置: 
range.startOffset
range.endOffset

背景:

range 拖蓝

创建
  • Documentvar range = document.caretRangeFromPoint(float x, float y);
  • Selection range = sel.getRangeAt(index)
  • 构造函数 range = new Range()
  • Document range = document.createRange();
关键属性
  • range.commonAncestorContainer 返回包含startContainer and endContainer的最小的node.
  • range.startContainer 返回包含range起点的node.
  • range.endContainer 返回包含range终点的node.
  • range.startOffset 在startcontianer中的range起点的位置
  • range.endOffset 在endcontianer中的range终点的位置
  • range.collapse 起点和终点是否重合
关键方法
  • range.setStart(startNode, startOffset);
  • range.setEnd(endNode, endOffset);
  • range.selectNode(referenceNode); range包含整个referenceNode, range的父元素是referenceNode的父元素
  • range.selectNodeContents(referenceNode); range包含referenceNode的内容, range的父元素是referenceNode
  • range.collapse(toStart); 参数是bool, true收缩到起点, false收缩到终点, 默认false.
  • range.insertNode(newNode);在 Range 的起点处插入节点。
  • clone = range.cloneRange(); clone一个range.
  • documentFragment = range.createContextualFragment(tagString) 纯文本没有问题.
  • Range.deleteContents()从dom删除range内容.
  • documentFragment = range.extractContents(); 把range的内容从dom移动到一个fragment
  • range.surroundContents(newParent); 把range内容包裹在newparent里面, 等于这两行语句: newNode.appendChild(range.extractContents()); range.insertNode(newNode).
  • range.detach(); 通知运行环境, 可以释放range.
  • bool = range.intersectsNode( referenceNode ) referenceNode是否在range里面.

selection 选区

拿到选区:

  • selection = window.getSelection();

textarea的选区方式(contenteditable失效):


contenteditable.focus() //失效, 加了tabindex都不行 devtools失效, 用按钮的点击事件就是有效地.
contenteditable.selectionStart = 100 //这个确实无效, 因为他是HTMLInputElement的属性(而且必须是textinput).
contenteditable.selectionEnd = 200


textarea.focus() //成功
textarea.selectionStart = 100
textarea.selectionEnd = 200

//focus之后, 如果是devtools 都不会引起outline(蓝框), 如果是button点击事件触发, 那么篮筐outline正常


api命名规则

  • anchor: 起点, 锚点
  • focus: 终点, 焦点
属性
  • focusNode返回该选区终点所在的节点。
  • focusOffset返回一个数字,其表示的是选区终点在 focusNode 中的位置偏移量。
    • 如果 focusNode 是文字节点,那么选区末尾未被选中的第一个字,在该文字节点中是第几个字(从0开始计),就返回它。
    • 如果 focusNode 是一个元素,那么返回的就是在选区末尾之后第一个节点之前的同级节点总数。
  • rangeCount返回该选区所包含的range(拖蓝)的数量。
关键函数
  • toString() 拿到纯文本.
  • sel.collapse(parentNode, offset);将当前的选区折叠为一个点。
  • sel.extend(node, offset)选区焦点扩展到指定位置, 锚点不变.
  • sel.modify(alter, direction, granularity) 改变选区
  • sel.containsNode(aNode,aPartlyContained) 判断节点aNode是否被(部分/全部)选中.
  • range处理
    • range = sel.getRangeAt(index) 返回指定的拖蓝range
    • sel.addRange(range) 添加一个range
    • sel.removeAllRanges()移除所有range, 取消所有选择.
    • sel.removeRange(range)

node

属性

  • node.textContent, 一个节点及其后代的文本内容(含不可视的), 可以用来赋值

    let text = aNode.textContent; //这个可以拿到所有文本, 完美哦.
    bNode.textContent = string; //此处有副作用, bNode里面的html标签会被抹掉.
    
  • previousNode = node.previousSibling

  • parentElement = node.parentElement

  • parentNode = node.parentNode, 父节点可能是element, 也可能是document, 也可能是documentfragment, 但是 document和documentfragment永远没有父节点.

  • let value = node.nodeValue; 对于text有用, 对于element没用.

  • var type = node.nodeType;

  • nextNode = node.nextSibling

  • var childNode = node.firstChild;

  • var ndList = elementNodeReference.childNodes; 这个live, 只读, nodelist类型

方法

  • Node.normalize()对该元素下的所有文本子节点进行整理,合并相邻的文本节点并清除空文本节点。

  • element.appendChild(aChild), 实际上能加儿子的都是element. textnode不能有儿子.

  • let newClone = node.cloneNode([deep])

  • var insertedNode = parentNode.insertBefore(newNode, referenceNode);

  • let oldChild = node.removeChild(child);//OR
    element.removeChild(child);
    
  • parentNode.replaceChild(newChild, oldChild);

  • node.contains( otherNode ) //判断

  • var root = node.getRootNode(options);

  • compareMask = node.compareDocumentPosition( otherNode )
nodelist
text
  • 继承链: EventTarget < Node < CharacterData < Text
  • 比如某个div的childNodes就包含了它内部的文字.
  • newNode = textNode.splitText(offset), 这个函数就是拆分textnode
  • document.createTextNode( “some text” )
  • innerhtml也可以添加text
ParentNode

这个接口描述了所有有子元素的node, 他在element, document, documentfragment上面实现.

属性

  • var count = node.childElementCount;
  • let children = node.children; live的htmlcollection of elements
  • var element = node.firstElementChild;
  • const element = node.lastElementChild

方法

  • ParentNode.append(…nodesOrDOMStrings) //插到最后一个子node之后, 可以是元素.
  • ParentNode.prepend(…nodesToPrepend); //插到第一个子node之前, 可以是元素.
  • element = parentNode.querySelector(selectors);
  • elementList = parentNode.querySelectorAll(selectors);
element
  • innerHTML

    const content = element.innerHTML;
    element.innerHTML = htmlString; //没有副作用
    
  • var cName = elementNodeReference.className; //空格分隔的class字符串
    elementNodeReference.className = cName;
    
  • const DOMTokenList = elementNodeReference.classList;

  • element.setAttribute(name, value);
htmlelement
  • innerText 得到可见文本内容

    var renderedText = HTMLElement.innerText;
    HTMLElement.innerText = string; //有副作用, 会删除element包含的所有html标签
    
  • element.focus(options) 设置焦点到某个元素

  • HTMLElement.style.cssText = “color: blue; border: 1px solid black”;

HTMLInputElement
  • HTMLInputElement.selectionStart 只对input的text类元素生效

  • var labelElements = input.labels; 返回input的label, 比如checkbox和radiobox

  • HTMLInputElement.multiple 是否有多值, 目前就是file有这个属性

  • 事件invalid event, 页面可以直接校验

  • element.setSelectionRange(selectionStart, selectionEnd [, selectionDirection]);

  • element.select(); 选择元素的所有内容

  • //替换range的所有内容
    element.setRangeText(replacement);
    element.setRangeText(replacement, start, end [, selectMode]);
    
  • element.stepDown( [ stepDecrement ] ); 步进/步退

  • element.stepUp( [ stepIncrement ] ); 步进/步退
document 和 window

window是个很特殊的对象, 他是document的window.

  • focused = document.hasFocus(); 判断是否得到焦点.
  • var element = DocumentOrShadowRoot.activeElement 拿到当前焦点元素.
    • 实际用这个: document.activeElement
  • var selection = documentOrShadowRootInstance.getSelection()
    • 实际用这个: selection = window.getSelection(); 得到selection, 这个是live的.
  • var caretPosition = document.caretPositionFromPoint(float x, float y);
  • var element = document.elementFromPoint(x, y);
  • var elements = document.elementsFromPoint(x, y);
  • var style = window.getComputedStyle(element [, pseudoElt]);
  • attribute = document.createAttribute(name)// = element.setAttribute(name, value);
  • let fragment = document.createDocumentFragment();
  • var element = document.createElement(tagName[, options]);
  • var event = document.createEvent(type); 请使用CustomEvent来替代.
  • var nodeIterator = document.createNodeIterator(root, whatToShow, filter);
  • var text = document.createTextNode(“string”);
  • document.createTreeWalker(root, whatToShow[, filter[, entityReferenceExpansion]]);
被废弃的方法