使用uiwebview中的javascript将样式应用于文本范围
我在iPhone上的UIWebView中以html的形式显示一些简单样式的文本。它基本上是一系列段落,偶尔带有强烈或强调的短语。在运行时,我需要将样式应用于文本范围 有几个类似的场景,其中之一就是突出显示搜索结果。如果用户搜索了“某物”,我想更改单词出现后的背景颜色,然后稍后恢复原始背景 是否可以使用javascript将样式应用于文本范围?其中一个关键部分是能够取消设置样式 似乎有两条可能的道路要走。一种是在Objective-C中修改一些html,并将其作为某个容器的新innerHTML通过javascript传递。另一种方法是使用javascript直接操作DOM节点 我可以操纵html,但在Objective-C中这听起来很乏味,所以如果这是一种合理的方法,我宁愿操纵DOM。我对javascript和DOM不太熟悉,所以我不知道这是否是一种合理的方法 我编写了一些例程来在文本范围和带有偏移量的节点范围之间进行转换。因此,如果我从文本范围100-200开始,从一个段落开始,到第三个段落结束,我可以得到文本节点和代表给定文本范围的节点内的偏移量。我只需要一种方法来分割文本中偏移量处的文本节点。目前,我只是将样式应用于包含文本范围的段落 请注意:使用uiwebview中的javascript将样式应用于文本范围,javascript,iphone,html,css,uiwebview,Javascript,Iphone,Html,Css,Uiwebview,我在iPhone上的UIWebView中以html的形式显示一些简单样式的文本。它基本上是一系列段落,偶尔带有强烈或强调的短语。在运行时,我需要将样式应用于文本范围 有几个类似的场景,其中之一就是突出显示搜索结果。如果用户搜索了“某物”,我想更改单词出现后的背景颜色,然后稍后恢复原始背景 是否可以使用javascript将样式应用于文本范围?其中一个关键部分是能够取消设置样式 似乎有两条可能的道路要走。一种是在Objective-C中修改一些html,并将其作为某个容器的新innerHTML通过
- 请使用纯javascript,没有像jquery这样的外部框架
- 这些更改永远不需要写入磁盘
- 更改应该是可撤消的,或者至少是可删除的
- 要应用的样式已存在于css文件中
- 它需要在iPhone3.0及更高版本中工作
- 应用程序附带所有源文件
- 请说得详细些
谢谢你的建议。我想你需要很多来获得一个完整的解决方案,但它看起来很有趣,所以我已经实现了。以下内容适用于最新的WebKit浏览器,包括运行OS 3.0的iPhone上的Safari。它使用了非标准但方便的
intersectsNode
方法Range
,该方法存在于WebKit中,但在3.0中从Firefox中删除,因此它在Firefox的最新版本中不起作用,但可以简单地实现
下面将用一个
元素围绕每个选定的文本节点,该元素包含一个“someclass”类以及一个允许轻松撤消的唯一类applyClassToSelection
返回此唯一类;将该类传递到removeSpansWithClass
以删除跨距
更新:修复了选择完全包含在单个文本节点中的问题
更新2:现已在运行OS 3.0的iPhone上测试并运行
更新3:添加了rangeIntersectsNode
功能以增加对Firefox 3.0及更高版本的支持。这段代码现在应该可以在Firefox 1.0+、Safari 3.1+、Google Chrome、Opera 9.6+以及其他可能的版本中使用(目前尚未测试)它在Internet Explorer中根本不起作用,并且会在浏览器中出现错误。我计划很快开发IE版本
<script type="text/javascript">
var nextId = 0;
var rangeIntersectsNode = (typeof window.Range != "undefined"
&& Range.prototype.intersectsNode) ?
function(range, node) {
return range.intersectsNode(node);
} :
function(range, node) {
var nodeRange = node.ownerDocument.createRange();
try {
nodeRange.selectNode(node);
} catch (e) {
nodeRange.selectNodeContents(node);
}
return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
};
function applyClassToSelection(cssClass) {
var uniqueCssClass = "selection_" + (++nextId);
var sel = window.getSelection();
if (sel.rangeCount < 1) {
return;
}
var range = sel.getRangeAt(0);
var startNode = range.startContainer, endNode = range.endContainer;
// Split the start and end container text nodes, if necessary
if (endNode.nodeType == 3) {
endNode.splitText(range.endOffset);
range.setEnd(endNode, endNode.length);
}
if (startNode.nodeType == 3) {
startNode = startNode.splitText(range.startOffset);
range.setStart(startNode, 0);
}
// Create an array of all the text nodes in the selection
// using a TreeWalker
var containerElement = range.commonAncestorContainer;
if (containerElement.nodeType != 1) {
containerElement = containerElement.parentNode;
}
var treeWalker = document.createTreeWalker(
containerElement,
NodeFilter.SHOW_TEXT,
// Note that Range.intersectsNode is non-standard but
// implemented in WebKit
function(node) {
return rangeIntersectsNode(range, node) ?
NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
},
false
);
var selectedTextNodes = [];
while (treeWalker.nextNode()) {
selectedTextNodes.push(treeWalker.currentNode);
}
var textNode, span;
// Place each text node within range inside a <span>
// element with the desired class
for (var i = 0, len = selectedTextNodes.length; i < len; ++i) {
textNode = selectedTextNodes[i];
span = document.createElement("span");
span.className = cssClass + " " + uniqueCssClass;
textNode.parentNode.insertBefore(span, textNode);
span.appendChild(textNode);
}
return uniqueCssClass;
}
function removeSpansWithClass(cssClass) {
var spans = document.body.getElementsByClassName(cssClass),
span, parentNode;
// Convert spans to an array to prevent live updating of
// the list as we remove the spans
spans = Array.prototype.slice.call(spans, 0);
for (var i = 0, len = spans.length; i < len; ++i) {
span = spans[i];
parentNode = span.parentNode;
parentNode.insertBefore(span.firstChild, span);
parentNode.removeChild(span);
// Glue any adjacent text nodes back together
parentNode.normalize();
}
}
var c;
</script>
<input type="button" onclick="c = applyClassToSelection('someclass')"
value="Add class">
<input type="button" onclick="removeSpansWithClass(c)"
value="Remove class">
var-nextId=0;
变量rangeIntersectsNode=(typeof window.Range!=“未定义”
&&范围。原型。交叉点(SNODE)?
功能(范围、节点){
返回范围.intersectsNode(节点);
} :
功能(范围、节点){
var nodeRange=node.ownerDocument.createRange();
试一试{
nodeRange.选择node(节点);
}捕获(e){
nodeRange。选择NodeContents(节点);
}
返回范围。比较基本点(range.END\u到\u START,nodeRange)=-1&&
range.compareBoundaryPoints(range.START\u至\u END,节点范围)==1;
};
函数applyClassToSelection(cssClass){
var uniquecsclass=“selection”+(++nextId);
var sel=window.getSelection();
如果(选择范围计数<1){
返回;
}
var范围=选择范围(0);
var startNode=range.startContainer,endNode=range.endContainer;
//如有必要,拆分开始和结束容器文本节点
if(endNode.nodeType==3){
endNode.splitText(range.endOffset);
range.setEnd(endNode,endNode.length);
}
if(startNode.nodeType==3){
startNode=startNode.splitText(range.startOffset);
range.setStart(startNode,0);
}
//创建所选内容中所有文本节点的数组
//使用树行者
var containerElement=range.commonAncestorContainer;
if(containerElement.nodeType!=1){
containerElement=containerElement.parentNode;
}
var treeWalker=document.createTreeWalker(
集装箱运输,
NodeFilter.SHOW_TEXT,
//注意Range.intersectsNode是非标准的,但是
//在WebKit中实现
功能(节点){
返回范围相交节点(范围、节点)?
NodeFilter.FILTER\u接受:NodeFilter.FILTER\u拒绝;
},
假的
);
var selectedTextNodes=[];
while(treeWalker.nextNode()){
选择TextNodes.push(treeWalker.currentNode);
}
var-textNode,span;
//将每个文本节点放置在
//具有所需类的元素
for(变量i=0,len=selectedTextNodes.length;i