水平数据更新不适用于滚动

时间:2013-08-17 06:12:39

标签: javascript

我有一个大数组,我需要将它渲染到一个表中。而不是渲染所有项目,我只是水平和垂直渲染几个项目。然后在基于鼠标滚动的滚动上是否发生垂直/水平更新表值。但是我有两个问题

以下是我的代码问题

  1. 横向滚动数据时不会更新。
  2. 水平滚动也会使屏幕闪烁。
  3. 水平元素未正确对齐。
  4. 这是jsbin链接http://jsbin.com/oSOsIQe/2/edit

    这是JS代码,我知道代码不干净但我稍后会清理它。

    var $matrix = (function () {
    function $matrix(data, holder, hidescrollbar, config) {
        var header_h = config.header || "150px";
        var data_h = config.header || "90px";
        !data && (function () {
            // Fake Data, will be removed later
            data = new Array(50000);
            for (var i = 0, l = data.length; i < l; i++) {
                var dummy = Math.random().toString(36).substring(5);
                var dum = [];
                for (var j = 0; j < 26; j++) {
                    dum.push(dummy + i);
                }
                data[i] = dum;
            }
        }());
        hidescrollbar = hidescrollbar || false;
        var heightForcer = holder.appendChild(document.createElement('div'));
        heightForcer.id = "heightForcer";
        var view = null;
        //get the height of a single item
        var dimensions = (function () {
            //generate a fake item and calculate dimensions of our targets
            var div = document.createElement('div');
            div.style.height = "auto";
            div.innerHTML = "<div class='rowHeader'>fake</div><div class='rowData'>fake</div>";
            holder.appendChild(div);
            var output = {
                row: div.firstChild.offsetHeight,
                header: div.firstChild.offsetWidth,
                data: div.lastChild.offsetWidth
            }
            holder.removeChild(div);
            return output;
        })();
    
        function refreshWindow() {
            //remove old view
            if (view != null) {
                view.innerHTML = "";
            } else {
                //create new view
                view = holder.appendChild(document.createElement('div'));
            }
            var firstItem = Math.floor(holder.scrollTop / dimensions.row);
            var lastItem = firstItem + Math.ceil(holder.offsetHeight / dimensions.row) + 1;
            if (lastItem + 1 >= data.length) lastItem = data.length - 1;
    
            var hfirstItem = Math.floor(holder.scrollLeft / dimensions.data);
            var hlastItem = hfirstItem + Math.ceil(holder.offsetWidth / dimensions.data) + 1;
            if (hlastItem + 1 >= data[firstItem].length) hlastItem = data[firstItem].length - 1;
    
            //position view in users face
            view.id = 'view';
            view.style.top = (firstItem * dimensions.row) + 'px';
            view.style.left = (hfirstItem * dimensions.data) + 'px';
            var div;
            //add the items
            for (var index = firstItem; index <= lastItem; ++index) {
                div = document.createElement('div');
                var curData = data[index].slice(hfirstItem, hlastItem);
                div.innerHTML = '<div class="rowHeader">' + 
                  curData.join('</div><div class="rowData">') +
                "</div>";
                div.className = "listItem";
                div.style.height = dimensions.row + "px";
                view.appendChild(div);
            }
            console.log('viewing items ' + firstItem + ' to ' + lastItem);
        }
        heightForcer.style.height = (data.length * dimensions.row) + 'px';
        heightForcer.style.width = (data[0].length * dimensions.data) + 'px';
        if (hidescrollbar) {
            //work around for non-chrome browsers, hides the scrollbar
            holder.style.width = (holder.offsetWidth * 2 - view.offsetWidth) + 'px';
        }
        refreshWindow();
    
        function delayingHandler() {
            //wait for the scroll to finish
            //setTimeout(refreshWindow, 10);
            refreshWindow();
        }
        if (holder.addEventListener) holder.addEventListener("scroll", delayingHandler, false);
        else holder.attachEvent("onscroll", delayingHandler);
    }
    return $matrix;
     }());
    
    new $matrix(undefined, document.getElementById('listHolder'), false, {
      header: "150px",
      data: "90px",
      headerColumns: 2
    });
    

    请帮我解决这个问题。

3 个答案:

答案 0 :(得分:2)

我注意到你的jsbin示例已被略微修改并使用了wheelDelta属性。这就是您无法区分水平和垂直更新的原因。您需要使用wheelDeltaXwheelDeltaY,它们将是一个值或零,具体取决于用户是垂直滚动还是水平滚动。

另外,小心使用鼠标滚轮事件,它不符合标准,所以可能会回来困扰你。可能值得看一下JQuery源代码,看看scroll()方法如何实现这些处理程序。我想象有一个计时器监视元素的滚动偏移,当对象滚动时触发合成事件。但这是一个完全疯狂的猜测。就像我说的那样,你最好还是看看它。

答案 1 :(得分:1)

问题是您在onmousewheel上挂钩#foo事件,但没有意识到#foo只与其中包含的数据一样大。如果您进行了以下更改(即采用#wrapper而不是#foo

var listHold = document.getElementById('wrapper');

您会注意到值已更新。

答案 2 :(得分:1)

SOLUTIONmy answer对类似问题的概念扩展

<强> CODE

function matrix(data, holder, config) {
    'use strict';

    //copy the config, substituting defaults
    config = {
        cellWidth : (config && config.cellWidth) || 150,
        rowHeight : (config && config.rowHeight) || 22,
    };

    if (!data) {
        //create 50000x26 array for data
        data = (function (length, depth) {
            var output = new Array(length);
            var startAt;

            for (var index = 0; index < length; ++index) {
                //var startAt = Math.random().toString(36).substring(5);
                var startAt = index + ':';
                output[index] = new Array(depth);

                for (var index2 = 0; index2 < depth; ++index2)
                    output[index][index2] = startAt + index2;
            }

            return output;
        })(50000, 26);
    }

    //guard against 0 length arrays
    if (data.length < 1 || data[0].length < 1)
        return;

    var areaForcer = holder.appendChild(holder.ownerDocument.createElement('div'));

    var view = null;
    function refreshWindow() {
        //remove old view
        if (view != null)
            view.innerHTML = "";
        //create new view
        else
            view = holder.appendChild(holder.ownerDocument.createElement('div'));

        var firstRow = Math.floor(holder.scrollTop / config.rowHeight);
        var lastRow = firstRow + Math.ceil(holder.offsetHeight / config.rowHeight) + 1;
        if (lastRow + 2 > data.length)
            lastRow = data.length - 1;

        var firstColumn = Math.floor(holder.scrollLeft / config.cellWidth);
        var lastColumn = firstColumn + Math.ceil(holder.offsetWidth / config.cellWidth) + 1;
        if (lastColumn + 2 > data[0].length)
            lastColumn = data[0].length - 1;

        //position view in users face
        view.id = 'view';
        view.style.top = (firstRow * config.rowHeight) + 'px';
        view.style.left = (firstColumn * config.cellWidth) + 'px';

        var row;
        var cell;
        //add the rows
        for (var index = firstRow; index <= lastRow; ++index) {
            row = view.ownerDocument.createElement('div');
            row.style.height = config.rowHeight - 2 + 'px';
            view.appendChild(row);

            //add the cells
            for (var index2 = firstColumn; index2 <= lastColumn; ++index2) {
                cell = row.ownerDocument.createElement('div');
                cell.className = 'listItem';
                cell.innerHTML = data[index][index2];
                cell.style.width = config.cellWidth - 2 + 'px';
                row.appendChild(cell);
            }
        }

        console.log('viewing items [' + firstRow + ':' + lastRow + '][' + firstColumn + ':' + lastColumn + ']');
    }

    areaForcer.style.height = (data.length * config.rowHeight) + 'px';
    areaForcer.style.width = (data[0].length * config.cellWidth) + 'px';

    refreshWindow();

    function delayingHandler() {
        //wait for the scroll to finish
        setTimeout(refreshWindow, 10);
    }

    if (holder.addEventListener)
        holder.addEventListener('scroll', delayingHandler, false);
    else
        holder.attachEvent('onscroll', delayingHandler);
}

matrix(null, document.getElementById('listHolder'), false);
html, body {
    width:100%;
    height:100%;
    padding:0;
    margin:0
}

body{
    overflow:hidden; 
}

.listItem {
    border : 1px solid gray;
    margin : 1px 0px;
    display : inline-block;
}

#listHolder {
    position:relative;
    height:100%;
    width:100%;
    background-color:#CCC;
    box-sizing:border-box;
    overflow:auto;
}

#view {
    position:absolute;
}

#view, #view * {
    overflow : hidden;
    white-space : nowrap;
}

#view > div {
    width : 100%;
}
<div id="listHolder"></div>

清理代码只是一些事情:

  • 你没有以OO的方式使用该对象,不需要新的/使用该函数作为构造函数(如果你打算,以一个大写的方式启动它)

  • 在这个时代,编译器可以为我们做很多事情,没有理由使用像'i'或'j'这样的名字,其中'index'更加自我解释,而if语句是为了你使用的运算符(!data && /*set data*/,使用if (!data) /*set data*/

  • 不要在不需要的情况下使用匿名的一次调用函数,每次父函数运行时都需要重新编译它们

  • 在循环之外声明变量

  • 不要使用random()(在这种情况下),除非代码有效,否则很难看到最新情况

  • 个人偏好向函数发送null而不是undefined,并且当矩阵与apt一样时,不要将函数命名为$ matrix 使用评论!

  • 个人偏好除非你知道自己在做什么,否则++ x正是你所需要的,x ++是对资源的轻微浪费

  • 因为你正在使用水平滚动,忘记隐藏滚动条

  • 从简单开始,不要试图获得高度,只需强制一个。检测高度等问题是为工作解决方案保留的细节

  • 总是使用正确的缩进,即使if语句可以写在一行上。关于您的个人偏好并不重要,因为您在线发布代码希望其他人帮助您

  • 编辑代码时请确保更新语义。例如。名为'heightForcer'的元素现在也操纵宽度,通过调用'areaForcer'来消除它