2015-10-07 87 views
0

是否有任何其他方法可以在不使用scrollHeight的情况下获取某个HTML元素的内部高度?scrollHeight的替代DOM属性

事情是我有一个有100个记录的表格,在每个记录中,我使用height = 0然后height = scrollHeight在列中调整某个textarea的大小。

问题是IE执行scrollHeight至少20〜50ms取决于大小和我有大约100条记录。这意味着,仅仅为了IE来渲染所有的记录,只需要加载100条记录需要6秒以上,如果我需要加载100条记录呢?那会毁了我的网站。

所以我问是否有任何替代scrollHeight或者你可以提供任何替代代码,调整textarea。

谢谢你是进步,

UPDATE

这是我从IE浏览器用户界面的响应得到 enter image description here

更新2

二图片:正如你所看到的下面的图片,为什么IE在获取某个元素的scrollHeight方面很慢ENT(文本区域),是因为它计算整个布局(HTML正文),而不是只让特定元素的scrollHeight属性(textarea元素)

enter image description here

回答

4

这听起来像你再逐行,阅读scrollHeight然后设置height。这是非常昂贵的,因为在写入之后每次读取都会触发重排,以便给出准确答案(因为写入可能会改变页面上会影响正在读取的值的内容)。这不是height=scrollHeight需要时间;这是为了做到这一点所必需的回流。

layout (write height of all: 0) 

reflow 
read scrollHeight 
write height 

reflow (!) 
read scrollHeight 
write height 

reflow (!) 
read scrollHeight 
write height 
... 

reflow (!) 
paint 

(或者你设置height为0在每次迭代中,它并不重要,因为连续写入无法触发回流。)

相反,尝试做一个批次。将所有的scrollHeight值读入一个数组;那么,当你拥有他们全部时,把他们全部设置好。这样,你将只会得到两次重排:一次当你开始阅读时,一次当你完成你的代码并且浏览器需要显示页面时,因为只要你只是阅读或者只是写作,没有回流是只有当你从写作到阅读价值时才需要。

layout (write height of all: 0) 

reflow 
read scrollHeight 
read scrollHeight 
... 
write height 
write height 

reflow 
paint 

编辑:这是一个黑客;我还没有那么好的Knockout。但作为一个可能的最小例子,如果你不能以任何其他方式做,它可能会这样做。你可能会想运行它,并延伸到“整页”,否则您将无法看到任何东西:)

var vm = { 
 
    list: ko.observableArray(["foo", "bar\nbaz", "1\n2\n3\n4"]) 
 
}; 
 

 
var updatedHeights; 
 

 
ko.bindingHandlers.autoresizeStart = { 
 
    update: function(elem, valueAccessor) { 
 
    var data = ko.utils.unwrapObservable(valueAccessor()); 
 
    console.log("start update; setting updateHeights to []"); 
 
    updatedHeights = []; 
 
    } 
 
}; 
 
ko.bindingHandlers.autoresize = { 
 
    update: function(elem, valueAccessor) { 
 
    console.log("mid update;", elem, "is updated, so let's remember its scrollHeight"); 
 
    updatedHeights.push([elem, elem.scrollHeight]); 
 
    } 
 
}; 
 
ko.bindingHandlers.autoresizeEnd = { 
 
    update: function(elem, valueAccessor) { 
 
    var data = ko.utils.unwrapObservable(valueAccessor()); 
 
    console.log("end update; lets set heights for all updated elements:"); 
 
    updatedHeights.forEach(function(elemWithHeight) { 
 
     console.log(" ", elemWithHeight[1], elemWithHeight[0]); 
 
     elemWithHeight[0].style.height = elemWithHeight[1] + "px"; 
 
    }); 
 
    console.log("all done :)"); 
 
    } 
 
}; 
 

 
ko.virtualElements.allowedBindings.autoresizeStart = true; 
 
ko.virtualElements.allowedBindings.autoresizeEnd = true; 
 

 

 
ko.applyBindings(vm); 
 

 
setTimeout(function() { 
 
    vm.list.push("a\nb\nc\nd\ne\nf\ng"); 
 
}, 1000);
<!-- results pane console output; see http://meta.stackexchange.com/a/242491 --> 
 
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script> 
 

 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script> 
 

 
<!-- ko autoresizeStart: list --><!-- /ko --> 
 
<ul data-bind="foreach: list"> 
 
    <li > 
 
    <textarea data-bind="text: $data, autoresize: $data"></textarea> 
 
    </li> 
 
</ul> 
 
<!-- ko autoresizeEnd: list --><!-- /ko -->

+0

它也许可能,但事情是,我使用淘汰赛JS。然后我创建了一个autoResizeHeight自定义绑定。我的记录在一个Items()observableArray属性中。所以它会实际循环每个项目。 – VJPPaz

+0

检查我的更新,基于截图。我有2个单独的电话为scrollHeight,但第二个电话毫秒离我的第一个电话执行时间不是很远 – VJPPaz

+0

因此,模式是我预测 - 你有'style.height = 0'(写),然后是'scrollHeight' (一读)。这触发回流。我不知道如何用你的自定义绑定解决这个问题,但基本上你会想要两次遍历:一个是将所有元素的高度渲染为零,然后当它们全部渲染时,将它们全部设置为scrollHeight。 – Amadan