4

我有如下文本 DIV。我只针对非 IE 和 webkit 浏览器。

一 :

<div id="target1"> Some<sup>en</sup> <i><b>text</b></i> </div>

上面的行看起来像: Some en text with style

第二 :

<div id="target2"> Some<sup>en</sup> <span class='boldIt'>text</span></div>
.boldIt{
   font-weight : bold;
   font-style : italic;
}

它看起来和上面一样。根据观点两者是相同的。但是下面和上面不一样

<div id="target3"> Someen text</div>

我的要求是比较三个目标元素。

我尝试过的: 我尝试遍历 DIV 的每个子节点并使用getComputedStyle(). 但是我可以看到页面上发生了很大的性能问题。因为涉及的案例太多了。

有一个想法,但无奈,Here is an IDEA 在画布上绘制两个元素并比较两个画布就像比较两个图像一样。这真的可能吗?如果可能,当我将一个内联元素与块级元素进行比较时,它会改变比较的行为吗?

请就此向我提出建议。如果没有想法,我会坚持使用我之前提到的 HTML 方式。

我已经使用画布尝试过这个,我的目标只是 Chrome。安东尼的回答完全符合我的要求。但在下面的情况下,我找不到办法做到这一点

for(var i = 0; i < arr.length; i++){
  var htStr = arr[i].one, htStr2 = arr[i].two;
  // How can I match these two now...
} 
4

2 回答 2

3

您使用 a 的想法<canvas>是可能的。

请参阅演示(在 Chrome、Safari 和 Opera 上测试)。

您可以使用html2canvas将以下内容转换为 3 个不同的画布,并比较它们的 base64 字符串以确定它们在视觉上是否相同。您应该将它们包装在单独的容器中,以便所有文本都呈现在画布中。

<div id="target1-container">
    <div id="target1"> Some<sup>en</sup> <i><b>text</b></i> </div>
</div>
<div id="target2-container">
    <div id="target2"> Some<sup>en</sup> <span class='boldIt'>text</span></div>
</div>
<div id="target3-container">
    <div id="target3"> Someen text</div>
</div>

转换为canvas和base64字符串,使用async.js处理多个异步调用:

async.parallel({
    target1: function (callback) {
        html2canvas(document.getElementById("target1-container"), {
            onrendered: function (canvas) {
                callback(null, canvas.toDataURL());
            }
        });
    },
    target2: function (callback) {
        html2canvas(document.getElementById("target2-container"), {
            onrendered: function (canvas) {
                callback(null, canvas.toDataURL());
            }
        });
    },
    target3: function (callback) {
        html2canvas(document.getElementById("target3-container"), {
            onrendered: function (canvas) {
                callback(null, canvas.toDataURL());
            }
        });
    }
},
function (err, results) {
    console.log(results);
});

关于您更新的问题,这是一个比较由字符串定义的元素的视觉外观的函数:

function compare(arr, fn) {
    // create test div
    var testdiv = document.createElement("div");
    testdiv.style.marginTop = '1000px';
    document.body.appendChild(testdiv);
    async.map(
        arr,
        function (data, callback) {
            var htStr = data.one,
                htStr2 = data.two;
            // create elements from strings
            var el = document.createElement("div"),
                el2 = document.createElement("div");
            el.innerHTML = htStr;
            testdiv.appendChild(el);
            el2.innerHTML = htStr2;
            testdiv.appendChild(el2);
            // convert to canvas and base64 strings
            async.parallel([
                function (callback) {
                    html2canvas(el, {
                        onrendered: function (canvas) {
                            callback(null, canvas.toDataURL());
                        }
                    });
                },
                function (callback) {
                    html2canvas(el2, {
                        onrendered: function (canvas) {
                            callback(null, canvas.toDataURL());
                        }
                    });
                }
            ],
            // start comparison
            function (err, results) {
                if (results[0] === results[1]) {
                    callback(null, true);
                } else {
                    callback(null, false);
                }
            });
        },
        // callback function
        function (err, results) {
            document.body.removeChild(testdiv);
            if (typeof fn === 'function') {
                fn(results);
            }
        }
    );
}
// elements to be tested
var arr = [];
arr.push({
    one: '<div id="target1"> Some<sup>en</sup> <i><b>text</b></i> </div>',
    two: '<div id="target2"> Some<sup>en</sup> <span class="boldIt">text</span></div>'
});
arr.push({
    one: '<div id="target1"> Some<sup>en</sup> <i><b>text</b></i> </div>',
    two: '<div id="target3"> Someen text</div>'
});
// let the test begin
compare(arr, function (result) {
    console.log(result);
});

它在回调函数中返回一个数组,其中

  • true意味着元素在视觉上是相同的,并且
  • false意味着他们是不同的。

请参阅此 DEMO中的控制台。

于 2013-05-05T14:27:07.407 回答
1

我假设“比较”是指检测元素是否在像素级别以相同的方式呈现。请注意,在词汇基础上完全不相等的元素可以满足此条件;相反,两个元素可能在词汇上相同,但由于许多因素而呈现不同,特别是从父母那里继承的属性。您还需要考虑这样一个事实,即元素的像素表示在构成其包含矩形的像素的意义上可能被页面上其他地方的某些东西污染了;最明显的例子是具有固定位置的元素。

综上所述,既然我们将等价定义为像素级等价,那么答案确实是对要比较的元素进行“快照”并进行比较。最简单的方法是使用无头 Web 浏览器,例如 PhantomJS。我不会提供完整的程序,但这里是基础知识:

  1. 在您的page.evaluate函数中,使用 获取相关元素的尺寸getBoundingClientRect

  2. 然后使用window.callPhantom. 这将调用使用定义的函数page.onCallBack

  3. 在回调中,设置page.clipRect为要捕获的项目的尺寸。然后使用类似的东西page.renderBase64来捕获图像,并将结果存储为文件。

  4. 对要比较的其他元素重复此操作。

  5. 比较存储的 base64 图像的字节级等效性。

于 2013-05-05T14:09:35.253 回答