在iOS电子书阅读器中使用execCommand突出显示HTML的任何替代方法

时间:2011-12-08 10:12:20

标签: javascript ios uiwebview highlighting

我正在使用UIWebView为iOS开发图书阅读器。目前我正在处理一些基本的HTML文件,但最终将与ePubs一起使用。我正在寻找一种合适的文本范围样式。我的范围有点特殊,因为它们通常包含三个范围 - 一个键范围和一个范围,紧接在之前和范围之后。键范围可以跨越多个节点,并且可以例如在粗体文本等的选择内开始或结束。不应将样式写入文件。

目前我的工作解决方案如下:

document.designMode = "on";

// Color the first section
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range1);

if (!selection.isCollapsed){ 
document.execCommand("foreColor", false, color1);    
}

// Color the middle section
selection.removeAllRanges();
selection.addRange(range2);

if (!selection.isCollapsed){   
document.execCommand("backColor", false, color2);
document.execCommand("foreColor", false, color3);
}

// Color the last section
selection.removeAllRanges();
selection.addRange(range3);

if (!selection.isCollapsed){ 
document.execCommand("foreColor", false, color1);
}

document.designMode = "off";
selection.removeAllRanges();

这种方法很好但速度明显很慢(在iPad2上),即使我修改它以突出显示短HTML文档中的单个范围。在文本风格化之前总是有非常明显的延迟。看看iPad上的电子书阅读器,如kindle或iBooks,没有明显的延迟。他们如何实现突出显示功能?他们可能正在阅读所选文本的地理位置并应用某种叠加效果吗?

我已经找到了比我已经使用过的更好的解决方案,但没有运气,所以如果有人有想法我会非常感激。

谢谢!

2 个答案:

答案 0 :(得分:8)

我已经为上面做了一个替代方法,看起来要快得多。它主要基于mikeB在这个问题中给出的优秀代码。

How to get nodes lying inside a range with javascript?

  1. 我首先拆分创建新文本节点的开始和结束节点 只有符合给定范围的文本。我调整了范围 对于新节点。

  2. 我在上面的链接中使用稍微修改过的代码版本 返回范围内包含的text nodes数组。

  3. 我循环遍历数组并在每个文本周围添加样式 节点

  4. 据我测试,代码效果很好。当同时将样式应用于多个范围时,仍然会有延迟,但它比以前好多了。我有兴趣知道是否有人有任何改进。

    我的代码:

    function styleRange(range, style) // the style is a string of css styles. eg."background-color:darkblue; color:blue;"
    {    
        // Get the start and end nodes and split them to give new start and end nodes with only text that falls inside the range.
        var startNode = range.startContainer.splitText(range.startOffset);
        var endNode = range.endContainer.splitText(range.endOffset).previousSibling;
    
        // Adjust the range to contain the new start and end nodes
        // The offsets are not really important anymore but might as well set them correctly
        range.setStart(startNode,0);
        range.setEnd(endNode,endNode.length);
    
        // Get an array of all text nodes within the range
        var nodes = getNodesInRange(range);
    
        // Place span tags with style around each textnode
        for (i = 0; i < nodes.length; i++)
        {
            var span = document.createElement('span');
            span.setAttribute("style", style);
            span.appendChild( document.createTextNode(nodes[i].nodeValue));
            nodes[i].parentNode.replaceChild( span, nodes[i] );
        }
    }
    

    来自mikeB代码的修改代码:

    function getNodesInRange(range)
    {
        var start = range.startContainer;
        var end = range.endContainer;
        var commonAncestor = range.commonAncestorContainer;
        var nodes = [];
        var node;
    
        // walk parent nodes from start to common ancestor
        for (node = start.parentNode; node; node = node.parentNode)
        {
            if (node.nodeType == 3) //modified to only add text nodes to the array
                nodes.push(node);
            if (node == commonAncestor)
                break;
        }
        nodes.reverse();
    
        // walk children and siblings from start until end is found
        for (node = start; node; node = getNextNode(node))
        {
            if (node.nodeType == 3) //modified to only add text nodes to the array
                nodes.push(node);
            if (node == end)
                break;
        }
    
        return nodes;
    }
    
    
    function getNextNode(node, end)
    {
        if (node.firstChild)
            return node.firstChild;
        while (node)
        {
            if (node.nextSibling)
                return node.nextSibling;
            node = node.parentNode;
        }
    }
    

答案 1 :(得分:0)

Apollo为了成功,你必须在创建跨度时设置一个onclick监听器,方法是传递一个像

这样的回调函数
span.addEventListener("click",callbackwhenclickeventtrigger,false);
function callbackwhenclickeventtrigger(e){//pass as param the event target, inside this function create the un-bold function
}