Javascript 获取CSS3列中的可见文本
尝试创建一个可以读取元素内部当前可见文本的方法。你在下面看到的方法是我在过去几天里得到的 除了使用插入符号/范围之外,还有什么更可靠的方法来获取元素中的可见文本吗?因为我遇到的问题是,我有很多溢出的文本,这些文本也会被选中,因为插入符号不会捕获textNode,而是父容器 我的页面外观示例&为什么我对当前方法有问题:Javascript 获取CSS3列中的可见文本,javascript,css,Javascript,Css,尝试创建一个可以读取元素内部当前可见文本的方法。你在下面看到的方法是我在过去几天里得到的 除了使用插入符号/范围之外,还有什么更可靠的方法来获取元素中的可见文本吗?因为我遇到的问题是,我有很多溢出的文本,这些文本也会被选中,因为插入符号不会捕获textNode,而是父容器 我的页面外观示例&为什么我对当前方法有问题: 到目前为止,Gael拥有最易于实现的性能友好型解决方案 不确定我在这里是否有意义,否则请让我知道:) function getTextInColumn (rect) {
- 到目前为止,Gael拥有最易于实现的性能友好型解决方案李>
function getTextInColumn (rect) {
var startX = rect.left;
var startY = rect.top;
var endX = rect.left + rect.width - 2;
var endY = rect.top + rect.height - 2;
var start, end, range = null;
var i = 0;
var rangeText = '';
while ((rangeText === '' && i < 100 && endY > 5)) {
range = null;
if (typeof document.caretPositionFromPoint != 'undefined') {
start = document.caretPositionFromPoint(startX, startY);
end = document.caretPositionFromPoint(endX, endY);
if (start !== null && end !== null) {
range = document.createRange();
range.setStart(start.offsetNode, start.offset);
range.setEnd(end.offsetNode, end.offset);
}
}
else if (typeof document.caretRangeFromPoint != 'undefined') {
start = document.caretRangeFromPoint(startX, startY);
end = document.caretRangeFromPoint(endX, endY);
if (start !== null && end !== null) {
range = document.createRange();
range.setStart(start.startContainer, start.startOffset);
range.setEnd(end.startContainer, end.startOffset);
}
}
if (range !== null) {
rangeText = range.toString();
}
endY -= 52;
i++;
}
return rangeText;
}
函数列(rect){
var startX=矩形左;
var startY=rect.top;
var endX=rect.left+rect.width-2;
var endY=rect.top+rect.height-2;
变量开始、结束、范围=空;
var i=0;
var rangeText='';
而((rangeText==''&&i<100&&endY>5)){
范围=空;
if(typeof document.caretPositionFromPoint!=“未定义”){
开始=document.caretPositionFromPoint(startX,startY);
结束=document.caretPositionFromPoint(endX,endY);
如果(开始!==null和结束!==null){
range=document.createRange();
range.setStart(start.offsetNode,start.offset);
range.setEnd(end.offsetNode,end.offset);
}
}
else if(typeof document.caretRangeFromPoint!=“未定义”){
开始=document.caretRangeFromPoint(startX,startY);
end=document.caretRangeFromPoint(endX,endY);
如果(开始!==null和结束!==null){
range=document.createRange();
range.setStart(start.startContainer,start.startOffset);
range.setEnd(end.startContainer,end.startOffset);
}
}
如果(范围!==null){
rangeText=range.toString();
}
endY-=52;
i++;
}
返回文本;
}
正如我猜的,您正在尝试解析DOM并获取所有文本元素
如果您查看以下内容:
然后看看DOM元素属性
查看示例以检索文本值
如果你发布你的html代码,你会得到更好的帮助
希望这对全球有所帮助,你必须测试每个字母是否可见。 由于块容器可以部分可见,并且知道其内容的哪些部分是可见的,这意味着要对它们进行单独测试,直到达到字母粒度。
然而,不必测试每个字母,而是可以测试一组字母是否可见,并使用a减少它们,就像知道是否所有包含的字母都可见一样 第一种方法 textNode的位置、维度(例如边界矩形)不在其属性中 因此,我最初尝试在块元素中插入textNodes,但这会导致性能问题,因为修改DOM意味着回流 此外,我们不仅要确定文本节点是否可见,还要确定其所有字母是否可见。所以我把每个字母放在一个块元素中:
var text= textNode.nodeValue;
var markedText= text.replace(/(.)/g,"<span class='marker'>$1</span>");
var markedContainer= document.createElement("div");
markedContainer.innerHTML= markedText;
textContainer.replaceChild(markedContainer,textNode);
然后,由于range
具有与块容器相同的方法,我们可以测试是否与窗口边界相交:
function intersectionArea(a, b) {
//credits to http://math.stackexchange.com/a/99576
var x_overlap = Math.max(0, Math.min(a.right, b.right)
- Math.max(a.left, b.left))
var y_overlap = Math.max(0, Math.min(a.bottom, b.bottom)
- Math.max(a.top, b.top));
return x_overlap * y_overlap;
}
这给出了范围的可见方式:完全可见、部分可见、无可见:
var intersection = intersectionArea(a, b);
if (intersection == 0)
state= "NULL";
else {
//that means that a is completly in b
if (intersection == intersectionArea(a, a))
state= "COMPLETE";
else
state= "PARTIAL";
}
如果某个范围部分可见,则将其分成两个子集,然后对其进行测试,以获得可见或不可见但不部分的子集
/*
ranges are indexed in an object by their startOffset property
*/
var ranges = { 0 : range };
/*
rangesIdx contains all the ranges which have to be tested
*/
var rangesIdx = [0];
while ( rangesIdx.length > 0 ) {
var range = ranges[ rangesIdx.shift() ];
switch (overlapsVisibleContent(range)){
case "PARTIAL":
// if a range is partially visible, it is splitted on its middle
// the two resulting ranges will then be tested
if (range.endOffset - range.startOffset > 1){
//even if one letter is not completly visible, it is considered to be completly.
var rangeLastPart= splitRange(range);
ranges[ rangeLastPart.startOffset ] = rangeLastPart;
rangesIdx.push( rangeLastPart.startOffset );
rangesIdx.push( range.startOffset );
}else
if( paintingMode )
paint( range.getBoundingClientRect(), "COMPLETE" )
break;
case "COMPLETE":
// if a range is completly visible, it stays on the ranges object
break;
case "NULL":
// if a range is completly unvisible, it is deleted from the ranges object.
delete ranges[ range.startOffset ];
}
}
对于相同的文本,处理持续时间为数十毫秒。
而且复杂性并不随文本长度的增加而增加
完整的代码是
一些注意事项
它只获取一个textNode的可见文本,但同样的二进制搜索逻辑也可以应用于DOM树
所有可见范围在过程结束时合并;这可能是一个问题,因为相邻行不能连接 我不太清楚:你想抓取页面可见部分中的所有文本吗?@Gael-我不想抓取DOM元素中的所有可见文本,DOM元素显示在我附加到帖子的图像中。这里需要注意的是,所有的文本都在同一个元素中。你能给我们相关的html吗?你能检查一下这是否是你想要实现的:@Gael-这正是我想要的。这种方法唯一关心的是性能。当我使用这个解决方案索引200多页时。我将对实现进行一次尝试,并将结果反馈给您:)非常感谢您给出如此详细的示例/方法。但正如示例所示。。对我来说,这是一个有趣的话题;)对其进行了调整,使其能够与HTML内容一起工作&这样开发人员就可以将测试矩形发送给该方法。-这至少是我最后使用的:)您的解决方案比我以前的解决方案好得多。这要快得多我喜欢树行者:)
/*
ranges are indexed in an object by their startOffset property
*/
var ranges = { 0 : range };
/*
rangesIdx contains all the ranges which have to be tested
*/
var rangesIdx = [0];
while ( rangesIdx.length > 0 ) {
var range = ranges[ rangesIdx.shift() ];
switch (overlapsVisibleContent(range)){
case "PARTIAL":
// if a range is partially visible, it is splitted on its middle
// the two resulting ranges will then be tested
if (range.endOffset - range.startOffset > 1){
//even if one letter is not completly visible, it is considered to be completly.
var rangeLastPart= splitRange(range);
ranges[ rangeLastPart.startOffset ] = rangeLastPart;
rangesIdx.push( rangeLastPart.startOffset );
rangesIdx.push( range.startOffset );
}else
if( paintingMode )
paint( range.getBoundingClientRect(), "COMPLETE" )
break;
case "COMPLETE":
// if a range is completly visible, it stays on the ranges object
break;
case "NULL":
// if a range is completly unvisible, it is deleted from the ranges object.
delete ranges[ range.startOffset ];
}
}