【问题标题】:Alternative DOM property for scrollHeightscrollHeight 的替代 DOM 属性
【发布时间】:2016-01-04 06:29:54
【问题描述】:

有没有其他方法可以在不使用 scrollHeight 的情况下获取某个 HTML 元素的内部高度?

问题是我有一个包含 100 条记录的表,并且在每条记录中,我使用 height=0 然后使用 height=scrollHeight 调整列中某个文本区域的大小。

问题是 IE 执行 scrollHeight 至少 20 ~ 50ms 取决于大小,我有大约 100 条记录。这意味着,仅仅为了让 IE 渲染所有记录,加载 100 条记录需要超过 6 秒,如果我需要加载 100 条记录怎么办?那会毁了我的网站。

所以我想问是否有任何替代 scrollHeight 或者您是否可以提供任何替代代码来调整 textarea 的大小。

先谢谢了,

更新

这就是我从 IE UI 响应性中得到的

更新 2

第二张图:如下图所示,IE 获取某个元素(textarea)的 scrollHeight 速度很慢的问题是因为它计算了整个 Layout(html 正文)而不是仅仅获取 scrollHeight那个特定元素(textarea 元素)

【问题讨论】:

    标签: javascript html knockout.js autoresize


    【解决方案1】:

    听起来您正在逐行读取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
    

    编辑:这是一个hack;我在淘汰赛中还没有那么好。但作为可能的最小示例,如果您不能以任何其他方式做到这一点,它可能会做到。您可能想要运行它并拉伸到“整页”,否则您将看不到任何东西:)

    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 -->

    【讨论】:

    • 也许有可能,但问题是我使用的是淘汰赛 js。然后我创建了一个 autoResizeHeight 自定义绑定。我的记录在 Items() observableArray 属性中。所以它实际上会循环每个项目。
    • 检查我的更新,基于截图。我有 2 个单独的 scrollHeight 调用,但第二个调用 ms 离我的第一次调用执行时间不是很远
    • 所以模式和我预测的一样——你有style.height = 0(写入),然后是scrollHeight(读取)。这会触发回流。我不确定如何使用您的自定义绑定来解决它,但基本上您需要两次传递:一次将所有元素的高度渲染为零,然后当它们全部渲染时,将它们全部设置为 scrollHeight。
    • 我删除了 height=0 但 height=scrollHeight 仍然很慢。
    • 您需要删除读/写/读/写模式。之前你有“写高度”、“读滚动高度”、“写高度”、“写高度”、“读滚动高度”、“写高度”;摆脱 one “写入高度”不会削减它,您仍然有条纹读写。
    猜你喜欢
    • 1970-01-01
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-15
    相关资源
    最近更新 更多