2017-03-07 71 views
3

我想创建一个荧光笔工具,它的工作原理是这样的:更换HTML,然后添加一个文件片段回HTML

  • 用户首先选择的文本范围。
  • 他们然后单击颜色按钮之一,所选文本的背景突出
  • 然后,他们选择文本的另一个范围...
  • 现在,当他们按一下按钮所有的HTML被替换为缓存版本的HTML(没有亮点)
  • 然后,新突出显示的新选定文本会被附加到新鲜的html中。

这样一次只能突出显示一个文本范围。

问题:

我有一个很难理解的RangeSelectionNode API的

目前,我不能添加突出显示的文本回新鲜的HTML ...我我只是将它附加到document.body。

我到目前为止有:

https://jsfiddle.net/4mb39jd6/

(function(){ 

    var highlighter = { 

    /** 
    * 
    */ 
    init: function(){ 
     this.cacheDOM(); 
     this.bindEvents(); 
    }, 

    /** 
    * 
    */ 
    cacheDOM: function(){ 
     this.$html   = $('.content').html(); 
     this.$content  = $('.content'); 
     this.$highlighter = $('.highlighter'); 
    }, 

    /** 
    * 
    */ 
    bindEvents: function(){ 
     this.$highlighter.on('mousedown', this.highlightSelection.bind(this)); 
    }, 

    /** 
    * 
    */ 
    highlightSelection: function(e){ 

     var selection = window.getSelection();   // get selection 
     var text  = selection.toString();   // get selected text 
     var newNode = document.createElement('span'); // create node 

     newNode.style.backgroundColor = $(e.target).css('backgroundColor'); // set node properties 
     newNode.appendChild(document.createTextNode(text));     // append selection text to node 

     var range = selection.getRangeAt(0);  // 2 - get the selected range 
     range.deleteContents();     // delete the contents 
     range.insertNode(newNode);    // insert the new node with the replacement text 
     documentFragment = range.cloneContents(); // clone the node 

     this.$content.html(this.$html);    // refresh the content 
     document.body.appendChild(documentFragment); // add the new highlighted text 
    }, 
    }; 
    highlighter.init(); 

})(); 

问:

如何添加我的强调点......它看起来像这样<span style="background-color: rgb(255, 255, 131);">some random text</span>回成新的html文档,以便它处于相同的位置。

+0

任何具体的原因,你要克隆的全部内容? 'highlightSection'中最后三行的注释似乎产生了所需的行为... https://jsfiddle.net/wxrxf6r1/ – user3297291

+0

是的,原因是我只想在任何一个给定时刻选择一段文本。 ..因为它是我可以突出各地...我只想要能够一次选择一个范围。 –

+1

你有没有看过[mark.js](https://markjs.io/)? – dude

回答

1

如果目标是在一次只有一个亮点,我会去一个不太复杂的方法是:

  • 当增加一个亮点,
  • 检查HTML前一个亮点,发现

时要做到这一点,你的标记彰显<span> s的属性或类(或更好,但存储参考)

  • 删除它:

    newNode.classList.add("js-highlight"); 
    

    添加一个方法来删除这样的元素:

    clearHighlight: function() { 
        var selection = document.querySelector(".js-highlight"); 
    
        if (selection) { 
        selection.parentElement.replaceChild(
         document.createTextNode(selection.innerText), 
         selection 
        ); 
        } 
    } 
    

    然后,更换前你range与突出显示元素,称之为clearHighlight

    例子:https://jsfiddle.net/2tqdLfb1/

    一种替代方案:

    我也尝试另一种方法是尊重你的 “缓存HTML” 的逻辑,却发现它被过于复杂。该方法的基础:

    • 检查选择
    • 商店开始索引和选择
    • 的结束索引的parentElement查询路径通过缓存HTML字符串替换HTML
    • 通过存储的查询路径查找新选中的选定父元素
    • 根据选择开始和结束索引将其分成1,2或3个textNodes
    • 替换你的亮点表示选择textNode <span>

    ,告诉您如何可以存储你的范围祖先查询路径的一个例子:

    function getPathUpToSelector(selector, element, path) { 
        var parent = element.parentElement; 
    
        if (parent && !element.matches(selector)) { 
        var index = Array.from(parent.children).indexOf(element) + 1; 
        path.push("*:nth-child(" + index + ")"); 
    
        return getPathUpToSelector(selector, parent, path); 
        } 
    
        return [selector].concat(path).join(" > "); 
    } 
    
  • +0

    谢谢!这是太棒了。我过于复杂的事情,这很好。现在唯一的问题是,如果我在两个节点上选择文本,那么HTML标记将被销毁......我在这里开始了一个新问题:http://stackoverflow.com/questions/42656501/serializing-html-placing-span-elements -around选择的文本,同时保留个 –