2012-05-07 3 views
1

Je travaille sur une application avec un besoin ferme de l'entreprise pour afficher une table html avec jusqu'à 60 lignes et jusqu'à 50 colonnes.Cellules sélectionnables de haute performance dans une grande table - IE6

Idéalement, les utilisateurs pourraient sélectionner des cellules de tableau individuelles ou cliquer et faire glisser pour sélectionner plusieurs cellules. Mon problème est que je suis limité à utiliser IE6 pour le moment, et j'ai eu de la difficulté à trouver (ou à coder) un moyen de permettre ce type de sélection sur autant de cellules sans dégradation sévère des performances.

Ma méthode actuelle ressemble fondamentalement ceci:

$(document).ready(function() { 
    var selecting = false; 
    var colStart, rowStart; 

    var tableContainer = $("#tableContainer") 

    tableContainer.delegate("td", "mousedown", function() { 
     //Clear Selection 
     tableContainer.find("td.selected").removeClass("selected"); 

     $(this).addClass("selected"); 
     colStart = $(this).index(); 
     rowStart = $(this).parents("tr").index(); 
     selecting = true; 
    }).delegate("td", "mouseover", function() { 
     if (selecting) { 
      //Clear Selection 
      tableContainer.find("td.selected").removeClass("selected"); 

      var theCell = $(this); 

      // Get the row and column numbers of the current cell 
      var colEnd = theCell.index(); 
      var rowEnd = theCell.parents("tr").index(); 

      // Account for rowEnd being smaller than rowStart 
      var rowSliceStart = Math.min(rowStart, rowEnd); 
      var rowSliceEnd = Math.max(rowStart, rowEnd); 

      tableContainer.find("tr").slice(rowSliceStart, rowSliceEnd + 1).each(function() { 
       var colSliceStart = Math.min(colStart, colEnd); 
       var colSliceEnd = Math.max(colStart, colEnd); 

       // Add the required class to the children 
       $(this).children().slice(colSliceStart, colSliceEnd + 1).addClass("selected"); 
      }); 
     } 
    }).delegate("td", "mouseup", function() { 
     selecting = false; 
    }); 
});​ 

Est-ce que quelqu'un a des suggestions pour une méthode pour améliorer la performance de cette fonction? Je crois que l'ajout/la suppression de cours absorbe la plus grande partie des coûts indirects, alors j'espère surtout trouver des gains d'efficacité.

Répondre

2
  1. Les tables sont les frais généraux eux-mêmes, surtout quand ils contiennent beaucoup de choses. Les tableaux ne rendent également que lorsqu'ils sont complets. Envisager des paginations si possible.

  2. Les manipulations DOM constantes, les repeints (modification de l'apparence) et les rediffusions (modification des dimensions) constituent également un surdébit.

  3. IE6 lui-même n'a pas été conçu pour effectuer de lourdes opérations JS. IE6 est quoi? 10 ans? Qu'est-ce qui était JS il y a 10 ans? validations et pop-ups, n'est-ce pas?

  4. Appels de fonction répétés. Dans jQuery, il est préférable de mettre en cache la valeur des appels de fonction comme le $(this) au lieu de l'appeler à plusieurs reprises. En tant que ce que je comprends dans votre code, vous exécutez $.each(), tranche et quelques maths aléatoires au cours du passage de la souris. C'est lourd.

  5. envisager d'utiliser un plus récent jQuery

Aussi, j'ai nettoyé un peu de votre code:

$(function() { 
    var selecting = false, 
     tableContainer = $("#tableContainer"), 
     colStart, rowStart; 

    tableContainer.on("mousedown", 'td', function() { 
     var $this = $(this); //reference this 
     colStart = $this.index(); 
     rowStart = $this.closest("tr").index(); //use closest instead of parents to avoid going up to root 
     $(".selected", tableContainer).removeClass("selected"); //context instead of find 
     $this.addClass("selected"); 

     selecting = true; 
    }).on("mouseover", 'td', function() { 
     if (selecting) { 

      var theCell = $(this), 
       colEnd = theCell.index(), 
       rowEnd = theCell.closest("tr").index(), //use closest 
       rowSliceStart = Math.min(rowStart, rowEnd), 
       rowSliceEnd = Math.max(rowStart, rowEnd); 

      $(".selected", tableContainer).removeClass("selected"); 

      $("tr", tableContainer).slice(rowSliceStart, rowSliceEnd + 1).each(function() { 
       var colSliceStart = Math.min(colStart, colEnd), 
        colSliceEnd = Math.max(colStart, colEnd); 
       $('> *', this).slice(colSliceStart, colSliceEnd + 1).addClass("selected"); //using selector to get children instead of $(this).children() 
      }); 
     } 
    }).on("mouseup", 'td', function() { 
     selecting = false; 
    }); 
});​ 
+0

Nice. Pourrait également peut-être mettre en cache la liste des cellules sélectionnées pour éviter d'avoir à les retrouver entre chaque appel de gestionnaire de souris. – Ben

+0

Pourrait également garder un cache de '$ (" tr ", tableContainer)' – Ben

+0

@Ben Oui, vous pouvez mettre en cache (c'est difficile cependant), mais c'est à l'OP pour en construire un. Mais il y a un problème de ramassage des ordures. Si les éléments sont supprimés dans le DOM, l'entrée de cache correspondant à cet élément doit également être annulée manuellement. Ou alors, des fuites de mémoire se produisent. – Joseph

1

Cela ne semble pas vraiment mauvais. La seule chose que je pourrais penser au-dessus de ma tête serait de calculer seulement les deltas sur mouseover. En d'autres termes, stockez les colonnes/lignes de début et de fin précédentes et, lors du prochain événement mouseover, mettez à jour les classes des éléments qui ont été modifiés.

Autres choses mineures:

  • cache $(this) dans le gestionnaire mousedown
  • Je ne suis pas sûr à 100% celui-ci pour IE6, mais vous pouvez essayer de changer le sélecteur de .find('td.selected') juste .find('.selected'). Le premier a deux conditions à vérifier, contre un seul. Dans les navigateurs modernes, la seconde serait définitivement être plus rapide, puisque jQuery peut tirer parti de getElementsByClassName, mais cela n'existe pas dans IE6, alors qui sait?
    • Vous pouvez également expérimenter avec un sélecteur plus ciblé, en particulier si le contenu des cellules contient d'autres éléments DOM. .find('> tr > .selected')
  • réglez le gestionnaire de survol de la souris.
+0

Merci beaucoup. Je vais réfléchir à la façon d'aborder les deltas, car la méthode addClass() a certainement le plus d'impact sur les performances, donc si je peux réduire le nombre d'éléments sur lesquels je travaille, cela devrait aider. Puis-je vous demander ce que vous voulez dire en limitant le gestionnaire de survol de la souris? Quelque chose comme définir un délai d'attente afin qu'il ressemble plus à un vol stationnaire? Si oui, avez-vous des exemples de comment cela pourrait fonctionner? – Alex

+0

@Alex Voici un plugin jQ pour les fonctions de throttling: http://benalman.com/projects/jquery-throttle-debounce-plugin/ Cela signifie simplement que la fonction ne sera pas exécutée à chaque fois qu'il y a un survol de la souris, mais au plus, une fois par X millisecondes. – nickf

+0

Un grand merci! Je vais jeter un coup d'oeil quand je serai de retour au travail – Alex

Questions connexes