poziomy pasek przewijania na górze i na dole tabeli

159

Mam bardzo duży tablena mojej stronie. Postanowiłem więc umieścić poziomy pasek przewijania na dole tabeli. Ale chciałbym, aby ten pasek przewijania był również na górze stołu.

To, co mam w szablonie, to:

<div style="overflow:auto; width:100%; height:130%">
<table id="data" style="width:100%">...</table>
</div>

Czy można to zrobić tylko w HTML i CSS?

psoares
źródło
1
stackoverflow.com/questions/2274627/… Uważam, że to rozwiązanie jest przydatne.
VARSHA DAS

Odpowiedzi:

234

Aby zasymulować drugi poziomy pasek przewijania na górze elementu, umieść „atrapę” divnad elementem, który ma przewijanie w poziomie, wystarczająco wysoko, aby zmieścić pasek przewijania. Następnie dołącz moduły obsługi zdarzenia „scroll” dla elementu fikcyjnego i elementu rzeczywistego, aby zsynchronizować inny element po przesunięciu któregoś z suwaków. Fikcyjny element będzie wyglądał jak drugi poziomy pasek przewijania nad rzeczywistym elementem.

Aby zobaczyć przykład na żywo , zobacz to skrzypce

Oto kod :

HTML:

<div class="wrapper1">
  <div class="div1"></div>
</div>
<div class="wrapper2">
  <div class="div2">
    <!-- Content Here -->
  </div>
</div>

CSS:

.wrapper1, .wrapper2 {
  width: 300px;
  overflow-x: scroll;
  overflow-y:hidden;
}

.wrapper1 {height: 20px; }
.wrapper2 {height: 200px; }

.div1 {
  width:1000px;
  height: 20px;
}

.div2 {
  width:1000px;
  height: 200px;
  background-color: #88FF88;
  overflow: auto;
}

JS:

$(function(){
  $(".wrapper1").scroll(function(){
    $(".wrapper2").scrollLeft($(".wrapper1").scrollLeft());
  });
  $(".wrapper2").scroll(function(){
    $(".wrapper1").scrollLeft($(".wrapper2").scrollLeft());
  });
});
StanleyH
źródło
naprawdę świetna odpowiedź! wielkie dzięki! :) więc próbowałem użyć twojego przykładu, ale pasek na górze nie działa, a kiedy próbowałem zwiększyć szerokość, pasek przewijania znika. jakiś pomysł, dlaczego?
psoares
1
Czy sprawiłeś, że to zadziałało? Aby uzyskać więcej informacji na temat jQuery, zobacz api.jquery.com/scrollLeft (oczywiście możesz to zrobić bez jQuery, dołączając bezpośrednio procedury obsługi onscroll). Aby uzyskać wdzięczną degradację dla użytkowników bez JS, możesz dodać fikcyjny element div do DOM przez JS .
StanleyH
1
tak, mam to do pracy, dodałem tylko <script type = "text / javascript" src = "path"> </script> do <head>. Więc za każdym razem, gdy dodawałem jquery, musiałem dodać ten, który dodaje @fudgey? Przepraszam, javascript i jquery nadal są dla mnie trochę chińskie
psoares
4
@StanleyH: jak ustawić element div, aby automatycznie przyjmował szerokość znajdującej się w nim tabeli? Nie chcę ręcznie określać szerokości div2, ale chcę, aby automatycznie przyjmował szerokość tabeli, którą zawiera.
sqlchild
3
@CodyGuldner: jak ustawić element div, aby automatycznie przyjmował szerokość znajdującej się w nim tabeli? Nie chcę ręcznie określać szerokości div2, ale chcę, aby automatycznie przyjmował szerokość tabeli, którą zawiera.
sqlchild
38

Spróbuj użyć jquery.doubleScrollwtyczki :

jQuery:

$(document).ready(function(){
  $('#double-scroll').doubleScroll();
});

CSS:

#double-scroll{
  width: 400px;
}

HTML:

<div id="double-scroll">
  <table id="very-wide-element">
    <tbody>
      <tr>
        <td></td>
      </tr>
    </tbody>
  </table>
</div>
pawel.suwala
źródło
5
Odwiedź github.com/avianey/jqDoubleScroll, aby zobaczyć wersję niesamowitej wtyczki Pawła, która nie wymaga jQueryUI.
fatal_error
1
Link prowadzi do nieobsługiwanego GitHub z niedziałającymi linkami w read me. Nie próbowałem rzeczywistego js.
Paul Gorbas
19

Przede wszystkim świetna odpowiedź, @StanleyH. Jeśli ktoś się zastanawia jak zrobić kontener typu double scroll z dynamiczną szerokością:

css

.wrapper1, .wrapper2 { width: 100%; overflow-x: scroll; overflow-y: hidden; }
.wrapper1 { height: 20px; }
.div1 { height: 20px; }
.div2 { overflow: none; }

js

$(function () {
    $('.wrapper1').on('scroll', function (e) {
        $('.wrapper2').scrollLeft($('.wrapper1').scrollLeft());
    }); 
    $('.wrapper2').on('scroll', function (e) {
        $('.wrapper1').scrollLeft($('.wrapper2').scrollLeft());
    });
});
$(window).on('load', function (e) {
    $('.div1').width($('table').width());
    $('.div2').width($('table').width());
});

html

<div class="wrapper1">
    <div class="div1"></div>
</div>
<div class="wrapper2">
    <div class="div2">
        <table>
            <tbody>
                <tr>
                    <td>table cell</td>
                    <td>table cell</td>
                    <!-- ... -->
                    <td>table cell</td>
                    <td>table cell</td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

próbny

http://jsfiddle.net/simo/67xSL/

simo
źródło
3
Użyj, $('.div1').width( $('.div1')[0].scrollWidth)aby uzyskać rzeczywistą szerokość przewijania treści, przydatne, gdy nie używasz specjalnie kontenera, takiego jak tabela. @simo Niesamowity wysiłek mate.
Clain Dsilva
Aby wyjaśnić, musiałem również zmienić kod na scrollWidth, aby mój własny kod działał tam, gdzie szerokość treści w div2 była zmienna ze względu na znajdującą się tam dynamiczną zawartość po stronie serwera.
AdamJones
15

Bez JQuery (2017)

Ponieważ możesz nie potrzebować JQuery, oto działająca wersja Vanilla JS oparta na odpowiedzi @StanleyH:

var wrapper1 = document.getElementById('wrapper1');
var wrapper2 = document.getElementById('wrapper2');
wrapper1.onscroll = function() {
  wrapper2.scrollLeft = wrapper1.scrollLeft;
};
wrapper2.onscroll = function() {
  wrapper1.scrollLeft = wrapper2.scrollLeft;
};
#wrapper1, #wrapper2{width: 300px; border: none 0px RED;
overflow-x: scroll; overflow-y:hidden;}
#wrapper1{height: 20px; }
#wrapper2{height: 100px; }
#div1 {width:1000px; height: 20px; }
#div2 {width:1000px; height: 100px; background-color: #88FF88;
overflow: auto;}
<div id="wrapper1">
    <div id="div1">
    </div>
</div>
<div id="wrapper2">
    <div id="div2">
    aaaa bbbb cccc dddd aaaa bbbb cccc 
    dddd aaaa bbbb cccc dddd aaaa bbbb 
    cccc dddd aaaa bbbb cccc dddd aaaa 
    bbbb cccc dddd aaaa bbbb cccc dddd
    </div>
</div>

rap-2-godz
źródło
to właściwie nie jest responsywne / dynamiczne w przypadku, gdy nie znasz swojej szerokości
elad silver
tak! ma te same zastrzeżenia, co oryginalna odpowiedź @StanleyH
rap-2-h
11

Możesz użyć wtyczki jQuery, która zrobi to za Ciebie:

Wtyczka zajmie się całą logiką za Ciebie.

avianey
źródło
2
Chociaż ta wtyczka robi to samo co wtyczka suwala / jquery.doubleScroll, ma więcej opcji, takich jak ponowne obliczanie szerokości w
oknie .resize
1
Nie zależy również od interfejsu użytkownika jquery.
plemię84
1
Poleciłbym tę wtyczkę, wygląda na ulepszoną wersję suwala / jquery.doubleScroll i działa dla mnie
Russell England
Najpierw dziękuję za świetną wtyczkę! Jednak mam problem z kierunkiem przewijania: rtl. Wygląda na to, że nie obsługuje go poprawnie. Jeśli któryś z was guru javascripts wie, jak to naprawić, oto skrzypce: jsfiddle.net/qsn7tupc/3 Zauważ, że działa w Chrome, ale w żadnej innej przeglądarce.
Vlado,
10

Odpowiedź StanleyH była doskonała, ale miała jeden niefortunny błąd: kliknięcie zacienionego obszaru paska przewijania nie powoduje już przejścia do zaznaczenia, które kliknąłeś. Zamiast tego otrzymujesz bardzo mały i nieco irytujący przyrost pozycji paska przewijania.

Przetestowano: 4 wersje przeglądarki Firefox (w 100%), 4 wersje przeglądarki Chrome (w 50%).

Oto mój jsfiddle . Możesz obejść ten problem, mając zmienną on / off (prawda / fałsz), która pozwala na wyzwolenie tylko jednego zdarzenia onScroll () w danym momencie:

var scrolling = false;
$(".wrapper1").scroll(function(){
    if(scrolling) {
      scrolling = false;
      return true;
    }
    scrolling = true;
    $(".wrapper2")
        .scrollLeft($(".wrapper1").scrollLeft());
});
$(".wrapper2").scroll(function(){
    if(scrolling) {
      scrolling = false;
      return true;
    }
      scrolling = true;
    $(".wrapper1")
        .scrollLeft($(".wrapper2").scrollLeft());
});

Zachowanie problemowe z zaakceptowaną odpowiedzią:

Właściwie pożądane zachowanie:

Więc dlaczego tak się dzieje? Jeśli przejdziesz przez kod, zobaczysz, że wrapper1 wywołuje scrollLeft wrapper2, a wrapper2 wywołuje scrollLeft wrapper1 i powtarzamy to w nieskończoność, więc mamy problem z nieskończoną pętlą. Albo raczej: ciągłe przewijanie użytkownika powoduje konflikt z wywołaniem przewijania przez wrapperx, pojawia się konflikt zdarzeń i wynikiem końcowym nie jest przeskakiwanie pasków przewijania.

Mam nadzieję, że to pomoże komuś innemu!

HoldOffHunger
źródło
świetne wyjaśnienie! rzeczywiście robił nieskończoną pętlę
Ahmed Aboud
Tak. Dziękuję Ci bardzo za Twoje wsparcie! To jest dla mnie pomocne.
Giang D.MAI
3

Łączenie przewijaków zadziałało, ale w sposób, w jaki jest napisane, tworzy pętlę, która spowalnia przewijanie w większości przeglądarek, jeśli klikniesz na część jaśniejszego paska przewijania i przytrzymasz go (nie podczas przeciągania rolki).

Naprawiłem to flagą:

$(function() {
    x = 1;
    $(".wrapper1").scroll(function() {
        if (x == 1) {
            x = 0;
            $(".wrapper2")
                .scrollLeft($(".wrapper1").scrollLeft());
        } else {
            x = 1;
        }
    });


    $(".wrapper2").scroll(function() {
        if (x == 1) {
            x = 0;
            $(".wrapper1")
                .scrollLeft($(".wrapper2").scrollLeft());
        } else {
            x = 1;
        }
    });
});
Yossi Vainshtein
źródło
To rozwiązuje również problem, który miałem z sugerowanymi odpowiedziami. Jednak to tylko nieznacznie łagodzi problem, może nadal występować stopniowe / wolne przewijanie, jeśli odległość, którą chcesz przewinąć, jest wystarczająco duża.
Świątynia Dan
Z flagą warunkową / to rozwiązanie działa dobrze, a testy są zgodne z oczekiwanym zachowaniem bez stosowania JavaScript w przeglądarce.
userabuser
3

rozwiązanie tylko javascript oparte na odpowiedziach @HoldOffHunger i @bobince

<div id="doublescroll">

.

function DoubleScroll(element) {
            var scrollbar= document.createElement('div');
            scrollbar.appendChild(document.createElement('div'));
            scrollbar.style.overflow= 'auto';
            scrollbar.style.overflowY= 'hidden';
            scrollbar.firstChild.style.width= element.scrollWidth+'px';
            scrollbar.firstChild.style.paddingTop= '1px';
            scrollbar.firstChild.appendChild(document.createTextNode('\xA0'));
            var running = false;
            scrollbar.onscroll= function() {
                if(running) {
                    running = false;
                    return;
                }
                running = true;
                element.scrollLeft= scrollbar.scrollLeft;
            };
            element.onscroll= function() {
                if(running) {
                    running = false;
                    return;
                }
                running = true;
                scrollbar.scrollLeft= element.scrollLeft;
            };
            element.parentNode.insertBefore(scrollbar, element);
        }

    DoubleScroll(document.getElementById('doublescroll'));
Ahmed Aboud
źródło
3

W oparciu o rozwiązanie @StanleyH stworzyłem dyrektywę AngularJS , demo na jsFiddle .

Łatwy w użyciu:

<div data-double-scroll-bar-horizontal> {{content}} or static content </div>

Dla programistów AngularJS

przno
źródło
31
„Nie jest wymagane jQuery”. Tak, tylko całe ramy. Nic takiego.
PitaJ
2

O ile wiem, nie jest to możliwe w przypadku HTML i CSS.

punkrockbuddyholly
źródło
cóż, tak właśnie myślałem ... Ale chciałbym wiedzieć, czy ktoś to zrobił i jak najlepiej to zrobić ..
psoares
W przypadku HTML i CSS nie ma najlepszego sposobu. To po prostu niemożliwe. Aby uzyskać tego rodzaju funkcjonalność, musisz użyć innych technik, takich jak javascript.
Justus Romijn
1
czy możesz podać kilka wskazówek, od których możesz zacząć szukać?
psoares
2
To nie daje odpowiedzi na pytanie. Aby skrytykować lub poprosić autora o wyjaśnienie, zostaw komentarz pod jego postem.
SSA
2
@SSA to odpowiedź na pytanie. Pytanie brzmiało: „Czy można to zrobić tylko w HTML i CSS?” a odpowiedź brzmi „nie”.
punkrockbuddyholly
2

W waniliowym Javascript / Angular możesz to zrobić w ten sposób:

scroll() {
    let scroller = document.querySelector('.above-scroller');
    let table = document.querySelector('.table');
    table.scrollTo(scroller.scrollLeft,0);
  }

HTML:

<div class="above-scroller" (scroll)="scroll()">
  <div class="scroller"></div>
</div>
<div class="table" >
  <table></table>
</div>

CSS:

.above-scroller  {
   overflow-x: scroll;
   overflow-y:hidden;
   height: 20px;
   width: 1200px
 }

.scroller {
  width:4500px;
  height: 20px;
}

.table {
  width:100%;
  height: 100%;
  overflow: auto;
}
Jakub Bares
źródło
1

Rozszerzając odpowiedź StanleyH i próbując znaleźć wymagane minimum, zaimplementowałem:

JavaScript (wywołany raz z jakiegoś miejsca $(document).ready()):

function doubleScroll(){
        $(".topScrollVisible").scroll(function(){
            $(".tableWrapper")
                .scrollLeft($(".topScrollVisible").scrollLeft());
        });
        $(".tableWrapper").scroll(function(){
            $(".topScrollVisible")
                .scrollLeft($(".tableWrapper").scrollLeft());
        });
}

HTML (pamiętaj, że szerokości zmienią długość paska przewijania):

<div class="topScrollVisible" style="overflow-x:scroll">
    <div class="topScrollTableLength" style="width:1520px; height:20px">
    </div>
</div>
<div class="tableWrapper" style="overflow:auto; height:100%;">
    <table id="myTable" style="width:1470px" class="myTableClass">
...
    </table>

Otóż ​​to.

MattC
źródło
1

dla wszystkich fanów angular / nativeJs, wdrażając odpowiedź @ simo

HTML (bez zmian)

<div class="top-scroll-wrapper">
    <div class="top-scroll"></div>
</div>

CSS (bez zmian, szerokość: 90% to mój projekt)

.top-scroll-wrapper { width: 90%;height: 20px;margin: auto;padding: 0 16px;overflow-x: auto;overflow-y: hidden;}
.top-scroll { height: 20px; }

JS (jak onload) lub ngAfterViewChecked(wszystkie assą dla TypeScript)

let $topscroll = document.querySelector(".top-scroll") as HTMLElement
let $topscrollWrapper = document.querySelector(".top-scroll-wrapper") as HTMLElement
let $table = document.querySelectorAll('mat-card')[3] as HTMLElement

$topscroll.style.width = totalWidth + 'px'
$topscrollWrapper.onscroll = e => $table.scroll((e.target as HTMLElement).scrollLeft, 0)
$table.onscroll = e => $topscrollWrapper.scroll((e.target as HTMLElement).scrollLeft, 0)
bresleveloper
źródło
0

Jeśli używasz iscroll.js w przeglądarce webkit lub przeglądarce mobilnej, możesz spróbować:

$('#pageWrapper>div:last-child').css('top', "0px");
Diyizm
źródło
0

Dyrektywa AngularJs, aby to osiągnąć: Aby z niej skorzystać, dodaj podwójny hscroll klasy css do swojego elementu. Będziesz potrzebował do tego jQuery i AngularJs.

import angular from 'angular';

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, $compile) {
  $scope.name = 'Dual wielded horizontal scroller';
});

app.directive('doubleHscroll', function($compile) {
  return {
restrict: 'C',
link: function(scope, elem, attr){

  var elemWidth = parseInt(elem[0].clientWidth);

  elem.wrap(`<div id='wrapscroll' style='width:${elemWidth}px;overflow:scroll'></div>`); 
  //note the top scroll contains an empty space as a 'trick' 
  $('#wrapscroll').before(`<div id='topscroll' style='height:20px; overflow:scroll;width:${elemWidth}px'><div style='min-width:${elemWidth}px'> </div></div>`);

  $(function(){
    $('#topscroll').scroll(function(){
      $("#wrapscroll").scrollLeft($("#topscroll").scrollLeft());
    });
    $('#wrapscroll').scroll(function() {
      $("#topscroll").scrollLeft($("#wrapscroll").scrollLeft());
    });

  });  

}

  };


});
Tore Aurstad
źródło
0

Oto przykład dla VueJS

index.page

<template>
  <div>
    <div ref="topScroll" class="top-scroll" @scroll.passive="handleScroll">
      <div
        :style="{
          width: `${contentWidth}px`,
          height: '12px'
        }"
      />
    </div>
    <div ref="content" class="content" @scroll.passive="handleScroll">
      <div
        :style="{
          width: `${contentWidth}px`
        }"
      >
        Lorem ipsum dolor sit amet, ipsum dictum vulputate molestie id magna,
        nunc laoreet maecenas, molestie ipsum donec lectus ut et sit, aut ut ut
        viverra vivamus mollis in, integer diam purus penatibus. Augue consequat
        quis phasellus non, congue tristique ac arcu cras ligula congue, elit
        hendrerit lectus faucibus arcu ligula a, id hendrerit dolor nec nec
        placerat. Vel ornare tincidunt tincidunt, erat amet mollis quisque, odio
        cursus gravida libero aliquam duis, dolor sed nulla dignissim praesent
        erat, voluptatem pede aliquam. Ut et tellus mi fermentum varius, feugiat
        nullam nunc ultrices, ullamcorper pede, nunc vestibulum, scelerisque
        nunc lectus integer. Nec id scelerisque vestibulum, elit sit, cursus
        neque varius. Fusce in, nunc donec, volutpat mauris wisi sem, non
        sapien. Pellentesque nisl, lectus eros hendrerit dui. In metus aptent
        consectetuer, sociosqu massa mus fermentum mauris dis, donec erat nunc
        orci.
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      contentWidth: 1000
    }
  },
  methods: {
    handleScroll(event) {
      if (event.target._prevClass === 'content') {
        this.$refs.topScroll.scrollLeft = this.$refs.content.scrollLeft
      } else {
        this.$refs.content.scrollLeft = this.$refs.topScroll.scrollLeft
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.top-scroll,
.content {
  overflow: auto;
  max-width: 100%;
}
.top-scroll {
  margin-top: 50px;
}
</style>

ZWRÓĆ UWAGĘ na height: 12px... Zrobiłem to 12px, więc zostanie zauważone również na użytkownikach komputerów Mac. Ale w przypadku okien 0,1px wystarczy

Dziekan Christian Armada
źródło
-1

Występuje problem z kierunkiem przewijania: rtl. Wygląda na to, że wtyczka nie obsługuje go poprawnie. Oto skrzypce: skrzypce

Zwróć uwagę, że działa poprawnie w Chrome, ale we wszystkich innych popularnych przeglądarkach górny kierunek paska przewijania pozostaje w lewo.

Vlado
źródło