2013-08-17 25 views
11

大きな配列があり、テーブルにレンダリングする必要があります。すべてのアイテムをレンダリングする代わりに、私はいくつかのアイテムを水平方向と垂直方向にレンダリングしています。次に、マウススクロールに基づくスクロールで、垂直/水平の更新テーブル値が発生したかどうかを確認します。しかし、私はこのスクロールで水平方向のデータ更新が機能しない

に2つの問題はここに私のコード

  1. 水平にデータが更新されない、スクロールに問題ある持っています。
  2. 水平方向にスクロールすると、画面もちらつきます。
  3. 水平要素が正しく配置されていません。ここで

ここhttp://jsbin.com/oSOsIQe/2/edit

jsbinリンクで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 
}); 

私にこれを手伝ってください。

+8

他の人もアイデアを得るためにコメントを投稿してください。そして、この質問を閉じるためにjavascriptと投票を知らない人のために、これはJSの質問です。 JQueryは言語だとは思わないでください.Javascriptは言語です。 – Exception

答えて

1

SOLUTION、同様の質問へのmy 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> 

あなたのコードをクリーンアップするだけでいくつかの点:

    0この日および年齢で

  • を(あなたは、資本とそれを起動しようとしている場合と)

  • あなたがOO方式でオブジェクトを使用していない

    は、新しいの必要は/コンストラクタとしての機能を使用しませんコンパイラは私たちのために多くのことを行うことができます。 'i'や 'j'のような名前を使用する理由はありません。 'index'ははるかに自明で、ifステートメントはand演算子を使用した!data && /*set data*/

  • は、彼らが必要としていない匿名の、呼び出しワンス機能を採用していない、彼らは親関数が

  • 0を実行するたびに再コンパイルする必要があります) if (!data) /*set data*/を使用
  • は、ループの外で変数を宣言

  • 使用しません(この場合)のコードが動作している場合を除き、それは難しいいただきまし

  • 個人の好み送信ヌルに行くを参照することができます)(ランダム未定義ではなく関数に代入し、行列がaptと同じ場合に関数$ matrixを指定しないでください コメントを使用してください!

  • 個人の好みあなたは何をやっている知っている限り、++ xはあなたが必要な正確に何であり、あなたが水平方向のスクロールを使用しているため、リソース

  • のマイナー無駄であるX ++、隠れ忘れますスクロールバー

  • 単純に始まり、高さを取得しようとしないでください。高さの検出のようなものは、作業用のソリューションのために予約されている細かいところです。ifステートメントを1行に書くことができても、常に適切な字下げを使用してください。

  • あなたは、コードを編集するときに

  • を助けるために他の人々を期待し、オンラインでのコードを投稿しているのでに関するあなた個人的な好みを重要ではありませんが、セマンティクスを更新してください。例えば。 'heightForcer'という要素がwidthを操作するようになりました。これを 'areaForcer'と呼びます。

+0

あなたの答えを聞いてうれしい! – Exception

+0

誰が複雑な問題を解決できますか?そのような高い賞金もあります! :P私の最後の答えに置いたコメントと頭のためにありがとう – Hashbrown

+0

私はちょっと疑問に思っています、私はあなたのコードで問題があったと私はちょうど論理的な不一致が起こったことを知りたい点を除いて、 。 – Exception

1

onmousewheelイベントを#fooに接続していますが、#fooはそれに含まれているデータと同じ大きさであることに気づいていません。あなたは、以下の変更を行う場合は

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

あなたは値が更新されますないことに気付くでしょう(すなわち#wrapperの代わり#fooを取ります)。

+0

あなたの提案やマウスハンドラーコードに基づいてコードを更新しました。まだ運がありません。 – Exception

+0

申し訳ありませんが、間違ったコードを共有しています。明らかに、コードを少しリファクタリングする必要があることを意味します。 –

+0

いつかフィドルを準備してください。 – Exception

2

jsbinの例が少し変更されており、wheelDelta属性が使用されています。これが、水平方向と垂直方向の更新を区別できない理由です。ユーザーが垂直または水平にスクロールしたかどうかによって、wheelDeltaXおよびwheelDeltaYを使用する必要があります。これは値またはゼロになります。

また、マウスホイールイベントを使用する際には注意してください。標準に準拠していないため、あなたに遭遇する可能性があります。 scroll()メソッドがどのようにこれらのハンドラを実装しているかを見るには、JQueryソースを調べる価値があります。私は、オブジェクトのスクロール時に合成イベントをトリガする、要素のスクロールオフセットを監視するタイマーがあると思います。しかし、それは完全な野生の推測です。私が言ったように、あなたはそれを見ている方が良いです。

+0

wheelDeltaXについて教えてくれてありがとう、私が 'var delta = Math.max(-1、Math.min(1、(e.wheelDelta || -e.detail)));'を使う前に、私は水平スクロールをターゲットにしているので、私は 'scrollTop'、' scrollLeft'メソッドに切り替えました。 – Exception