web-dev-qa-db-fra.com

Comment diviser la fenêtre du navigateur en deux volets horizontaux

Jusqu'en HTML 4, il était possible de créer des mises en page avec des cadres chargeant différents fichiers HTML dans différents volets.

Ce que je veux faire, c'est obtenir un résultat similaire, mais charger et afficher à l'écran deux parties différentes du même document .

Mon paradigme idéal est MS Word, qui permet de scinder la fenêtre en deux parties horizontales pour afficher dans chacune d’elles différentes sections du même document (extrêmement utile lorsque vous comparez différentes parties du document ou lorsque vous déplacez des parties d’un côté à l’autre de façon prolongée). documents) ou MS Excel (même LibreOffice ou OpenOffice Calc ont une fonctionnalité similaire) qui permet de diviser le volet de la feuille en 2 (ou même en 4) sections pour la même raison ou de garder visibles certaines lignes en haut ou certaines colonnes en le droit (en-tête de ligne ou de colonne par exemple).

L'image suivante le montre:  Split same window document example.png

La flèche rouge indique la gouttière qui divise le document window en deux permettant de faire défiler chaque partie séparément, comme vous pouvez le voir en regardant le numéro de la ligne qui est dans le volet supérieur est 3 et 21 dans le volet inférieur. De plus, la gouttière est redimensionnable.

Est-il possible de faire cela avec Vanilla JS avec HTML & CSS (pas de jQuery ou autre framework s'il vous plaît)?

Contraintes:

  1. Le document doit être identique pour les 2 volets (haut et bas) (l'ancien jeu de cadres doit charger deux documents différents ou le même document deux fois: je l'utilise déjà, mais je souhaite une approche plus propre, si possible!)
  2. Le séparateur (gouttière?) Doit être redimensionnable
  3. Les deux parties différentes du document sont parfaitement synchronisées, en ce sens que si je modifie quelque chose (avec la propriété contenteditable) dans le volet supérieur (ou inférieur), le volet inférieur (ou supérieur) affiche instantanément l'édition qui vient d'être effectuée, comme le fait MS Word ou Excel ... donc, si je supprime quelque chose dans une cellule du tableau du volet inférieur, même le contenu supérieur est ajusté en conséquence (même la taille de la colonne), comme cela se produit avec MS Word, Excel, Calc, etc.
  4. La vue partagée sera activée et désactivée en cliquant sur un bouton spécifique
  5. Je me fiche des vieux navigateurs, juste du script ECMA 2015 ou des plus récents
  6. Le fichier HTML contient de nombreux écouteurs d'événement attachés avec la méthode addEventListener() à différents éléments HTML tels que des boutons, des zones de texte, des cases à cocher, des sélections, etc. Cela signifie que la solution répondue doit pouvoir les conserver intacts et fonctionner dans les deux volets .

Où vais-je l'utiliser?

J'ai un tas de tables dans un fichier HTML local (aucun serveur Web impliqué) qui charge les données à partir d'un fichier csv ou du stockage de session du navigateur, et j'ai souvent besoin de comparer des données de différents points ou de conserver l'en-tête au-dessus pendant que en faisant défiler le reste d'un tableau spécifique ou en insérant de nouvelles données ou en mettant à jour d'anciennes données dans l'un d'eux pour voir en permanence dans quelle cellule du tableau je suis en train d'insérer ou de mettre à jour des données.

Situation:

Pour le moment, j'utilise le code suivant:

function splitView()
{
    var tgtSrc = location.href;
    var frameset =  '<frameset rows="*,*">' +
                        '<frame name="' + upFrame + '" src="' + tgtSrc + '">' +
                        '<frame name="' + dwFrame + '" src="' + tgtSrc + '">' +
                    '</frameset>';
    document.write(frameset);   
}

La fonction ci-dessus divise horizontalement le volet actuel de la fenêtre en deux cadres appelés upFrame et dwFrame (deux variables). Après fractionnement, une gouttière redimensionnable est placée entre les deux cadres.

De plus, l'algorithme permet de synchroniser les deux instances des données du document: cela fonctionne en enregistrant à chaque édition de données dans une image les données dans le stockage de session de cette image et en rechargeant les mêmes données dans l'autre image.

Cela fonctionne un peu, mais les cadres ne sont pas la solution, j'aimerais supprimer le besoin de charger le document deux fois et de synchroniser chaque instance avec tous les inconvénients relatifs. Donc, malheureusement, ce n'est pas la réponse ultime que je recherche car elle présente certains inconvénients:

  1. Les balises frame et frameset ne sont pas prises en charge dans les fichiers modernes compatibles HTML5, même si elles sont toujours prises en charge par les navigateurs.
  2. Le fichier doit être chargé deux fois (une fois par image), ce qui signifie un manque notable de performances et une synchronisation difficile en temps réel des modifications d’une image à l’autre (éventuellement, une synchronisation bidirectionnelle est nécessaire pour les éditer. du document). Malheureusement, même le processus de synchronisation nécessaire implique de perdre des performances qui verrouillent l'interface utilisateur pendant un instant chaque boucle de synchronisation.
  3. Le processus de synchronisation n’est pas en temps réel, il a un certain retard (quelques secondes): si je le raccourcis, j’ai un grand manque de performances, ce qui inclut le gel du navigateur.

Je suis donc ouvert à de meilleures réponses avec des solutions plus propres et plus efficaces. (J'ai même proposé aux développeurs Chrome d'implémenter une fonction dans le navigateur, car je pense vraiment que c'est une fonctionnalité indispensable, en particulier si l'on considère les systèmes de gestion de données en ligne en expansion.

Ce que je cherche:

L'utilisation du code ci-dessus que j'utilise déjà n'est pas obligatoire du tout: les réponses peuvent également proposer une approche complètement différente.

Donc, la solution ultime que je recherche est quelque chose de similaire à la fonction de fractionnement utilisée par Google Spreadsheet (s’ils le peuvent, j’espère que nous pourrons aussi), voici une image avec l’exemple 

 enter image description here

Regardez bien: il y a la gouttière qu'il est possible de déplacer horizontalement (il y a aussi une gouttière verticale, mais je me fiche de la division verticale, juste horizontale) et lorsque le tableur défile vers le bas, les lignes disparaissent dessous: dans fait la première rangée au-dessus de la gouttière est le n. 1 la première rangée dans la gouttière est n. 45.

Notez également la petite flèche blanche à double tête indiquée par la grosse flèche rouge à l'extrême gauche de la photo.

J'ai essayé d'étudier l'approche de la feuille de calcul Google pour procéder à une ingénierie inverse et extraire les caractéristiques essentielles et adapter la même "philosophie" à mon application locale, mais je ne suis pas assez bon pour comprendre ce qu'elles ont fait: mon suspect Est-ce que quand "une rangée de table frappe la gouttière" se cache juste derrière elle, mais je ne suis pas sûr.

IMHO c'est une fonctionnalité que chaque navigateur (même ceux des périphériques portables) doit avoir implémenté de manière native et sans utiliser l'ancienne technologie des cadres qui ne sont plus supportés en HTML 5. Malheureusement, cette possibilité divise le même document pour afficher et éditer différentes parties (comme un très long tableau par exemple) en gardant chaque volet mis à jour réciproquement, n'est pas (encore) une fonctionnalité de navigateur, donc entre-temps ... il est nécessaire de contourner le problème.

Remarquer:

La propriété CSS

position: sticky;

serait également utilisable pour résoudre une partie du problème (garder la tête bloquée lors de l'édition ou de l'insertion de données dans le tbody), mais malheureusement, cela ne semble pas fonctionner comme prévu sur les éléments de la tête, du moins sur certains navigateurs. En outre, cela ne résout qu’une partie du problème: en fait, s’il est nécessaire de comparer des données provenant de différentes parties d’un même tableau ou de tableaux différents dans le même document, cette solution n’est pas du tout satisfaisante. Donc, il faut autre chose.

18
willy wonka

Par curiosité, s'il s'agit de fichiers locaux sur votre ordinateur, pourquoi essayez-vous d'éditer les données de table à partir de fichiers CSV dans un navigateur au lieu d'utiliser simplement les capacités natives d'un programme comme Excel que vous avez mentionné ci-dessus? Ou si vous voulez le faire dans le navigateur, les feuilles de Google permettent-elles l’écran divisé? Je ne comprends tout simplement pas pourquoi ne pas utiliser un programme dédié et optimisé pour ce type de travail.

si vous souhaitez continuer à utiliser des cadres, vous devriez pouvoir ré-charger le fichier dans un cadre et simplement copier le innerHTML d'un cadre à un autre, comme ce qui suit. Si vous utilisez un stockage de session, il devrait (?) Être plus rapide pour enregistrer les modifications apportées à ce fichier et au fichier csv, mais être chargé à partir du stockage de session au lieu du fichier.

window.frames[upFrame].document.body.innerHTML = window.frames[dwFrame].document.body.innerHTML;

Au lieu d'utiliser des cadres, vous pouvez utiliser des DIV comme conteneurs, chargez-les dans le stockage local comme vous le suggérez et remplissez les deux DIV à partir de là. les sauvegardes iraient à la fois au fichier csv et au stockage local comme la solution de cadres. Javascript permet de suivre le début du défilement afin qu’une fois rechargées à partir de la mémoire de stockage locale, vous puissiez "extraire" les deux sections sur les lignes qu’elles occupaient.

Une solution plus rapide pourrait toutefois consister à conserver les données csv en mémoire (tableau) et à les enregistrer sur le fichier csv, mais la mise à jour à partir de la mémoire serait beaucoup plus rapide qu'un fichier en théorie, à droite :)

3
Viking NM

je pense que vous pouvez y arriver avec des divs.

commencez par créer deux divs pour contenir les vues supérieure et inférieure.

puis clone ensuite le contenu principal à chaque div.

en ajustant les dimensions et la position de chaque div, vous pouvez obtenir la vue d’une div divisée en deux parties

vous pouvez également créer un script de taille réelle pour gérer la hauteur de chaque vue.

pour des actions en cascade sur plusieurs vues. vous pouvez utiliser des événements dans la vue supérieure pour effectuer les modifications dans la vue inférieure et dans la vue inférieure pour les modifier dans la vue supérieure.

enfin désolé pour la mauvaise explication.

j'ai fait jsfiddle pour expliquer l'approche

[1]: https://jsfiddle.net/EmadElpurgy/r9w93zo7/sample code

2
Emad Elpurgy

Il y a probablement de meilleures solutions que le hack que j'ai imaginé, mais essayons.

Si vous voulez prendre la page entière et la diviser, vous pouvez utiliser votre solution de jeu de cadres, mais au lieu de faire charger la ressource par le navigateur deux fois, vous pouvez simplement copier son code HTML et l'écrire dans les cadres:

<html>
  <head>
    <style type="text/css">
        body { color: red; } /* Only used to test if CSS is copied as well
    </style>
  </head>
  <body>
      Hello world!
  </body>

  <script type="text/javascript">
    function inFrame () {
      try {
    return window.self !== window.top;
      } catch (e) {
        return true;
      }
    }


    function buildFrames() {
      const documentHTML = document.documentElement.innerHTML;

      const frameset = document.createElement('frameset');
      frameset.rows = '*,*';

      const frame1 = document.createElement('frame');
      const frame2 = document.createElement('frame');

      document.documentElement.innerHTML = '<html><body></body></html>';

      frameset.appendChild(frame1);
      frameset.appendChild(frame2);

      document.body.appendChild(frameset);

      frame1.src = 'data:text/html;charset=utf-8,' + encodeURI(documentHTML);
      frame2.src = 'data:text/html;charset=utf-8,' + encodeURI(documentHTML);
    }

    if (!inFrame()) {
        buildFrames();
    }
  </script>
</html>

Vous devez cependant faire attention au code javascript exécuté dans vos pages. Comme vous pouvez le constater, je devais également vérifier si la page ne se trouvait pas déjà dans un cadre, sinon le groupe continuerait à ajouter des ensembles de cadres au document (ou du moins jusqu'à ce que le navigateur l'en empêche).

2
samu

Je ne vais que partiellement répondre à votre question, car je n'ai pas de solution complète.

Les balises frame et frameset ne sont pas prises en charge dans les fichiers modernes compatibles HTML5, même si elles sont toujours prises en charge par les navigateurs.

Frame est obsolète en faveur de iframe . Cela devrait se comporter à peu près de la même manière.

Pour garantir la synchronisation entre les deux volets avec les contraintes que vous avez définies, vous allez devoir écrire un JS personnalisé, surtout que vous êtes opposé à framework/package.

0
Samir