何时将listView的itemTemplate插入到DOM中?

4
我创建了一个自定义的itemTemplateFunction,如此处所述。但是我想访问在DOM渲染过程中定义的属性(如height或clientHeight)。这是为了允许子元素在布局中动态偏移。
目前我已经研究了两种方法:
  • renderComplete - returned as an element in the itemPromise then return object. The event fired as expected, however the attributes (such as height) did not have set values, so it looks as though the item is not in the DOM at this point.
  • setInterval - although this would work it's a bad solution as I am relying on a constant time offset, something which ideally I don't want to do.

    function itemTemplateFunction(itemPromise) {
    
       return itemPromise.then(function (item) {
           var div = document.createElement("div");
    
           var img = document.createElement("img");
           img.src = item.data.picture;
           img.alt = item.data.title;
           div.appendChild(img);
    
           var childDiv = document.createElement("div");
    
           var title = document.createElement("h4");
           title.className += "title";
           title.innerText = item.data.title;
           childDiv.appendChild(title);
    
           var desc = document.createElement("h6");
           desc.innerText = item.data.text;
           childDiv.appendChild(desc);
    
           div.appendChild(childDiv);
    
           return {
               element: div,
               renderComplete: itemPromise.then(function (item){
                   return item.ready;
               }).then(function (item){
                   var height_a = div.querySelector(".title").clientHeight;
                   var height_b = WinJS.Utilities.query(".title", div).clientHeight;
               })
           }
       });
    };
    

创建第一个项目时,尽管返回了承诺,但属性仍未最终确定。但是,如果我将item.ready的返回值包装在一个超时间隔为0的第二个承诺中,它会如预期返回。

       return {
           element: div,
           renderComplete: itemPromise.then(function (item){
               return WinJS.Promise.timeout(0).then(function () {
                   return item.ready;
               });
           }).then(function (item){
               var height_a = div.querySelector(".title").clientHeight;
               var height_b = WinJS.Utilities.query(".title", div).clientHeight;
           })
       }

免责声明:我不是winjs专家,但很熟悉javascript/jquery。你的then方法返回的div元素在DOM中并不存在,直到它被实际添加到文档中,例如document.appendChild(div),或者添加到文档的某个子元素中。此时它应该获得客户端属性。也许你可以钩住DOMNodeInserted事件? - skarist
1个回答

1
你需要寻找的是item.ready属性,它位于itemPromise.then()方法的完成处理程序中。
item.ready本身是一个promise,在项目呈现时被实现,此时所有与布局相关的属性应该已设置。
要使用它,请从itemPromise.then()方法的第一个完成处理程序返回item.ready,然后在链中添加另一个.then(function(item){})。在该完成处理程序内,您可以检查这些属性。
我在我的免费电子书《HTML,CSS和JavaScript编程Windows Store应用程序第2版》的第7章中进行了详细介绍,特别是在该章节末尾称为“模板函数(第2部分):优化的项目呈现”的部分以及多阶段呈现的讨论。相同的内容也 出现在旧的Windows 8开发者博客上,但请注意,博客上讨论的“回收站占位符”选项仅适用于WinJS 1.0。

谢谢你的回复,Kraig。你的书非常好,我之前就用它来实现多阶段渲染。你说得对,使用Promise和链式调用确实可以让我按预期获取clientHeight - 尽管第一项不行,当访问clientHeight时仍然返回零值。如果我在0间隔的时间内使用Promise超时来抵消item.ready的返回,我就可以访问第一项的值。虽然这感觉有点凌乱。 - user3821285
这很奇怪,WinJS团队可能会进一步调查。是否有可能制作一个小的重现项目,或者至少将核心HTML和JS代码复制到此处,以便可以放入空白模板项目中? - Kraig Brockschmidt - MSFT
我已经在一个空的Grid App项目中重新创建了这个问题,并用这些覆盖了默认的页面文件夹,这将重新创建这个问题。 - user3821285

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接