Produced by Fourier

JavaScriptで表の自動横スクロールを実装する

Takahashi Takahashi カレンダーアイコン 2024.08.16

はじめに

スマホで表を表示したときに、横スクロールがめんどくさいと感じたことはないでしょうか?

今回は、ボタンを押したときに所定位置まで自動で横スクロールする機能をJavaScriptで実装する方法をご紹介します。

実装

ここでは、横スクロール機能の実例としてシフト表を作成します。

表の仕様は以下です。

  • 1番左側の列に「氏名」の項目を用意
  • 1行目に曜日の項目を用意
  • 表の幅 > 画面幅 となったとき、表が横スクロールできるようになる
  • 「氏名」の列はスクロールされない(一番左の列で固定)
  • 表上部の曜日ボタンを押すと指定した曜日まで表が自動スクロールする

見た目の作成

まずはhtmlとCSSで表の見た目を整えます。

ul.scroll-toggle li が横スクロールを発火させるボタンになってます。

See the Pen spectrum-web-analyzer by FOURIER Inc. ( @fourier-inc )on CodePen .

thの各カラム左端の位置を取得

次に、 thead の中の th の左端の位置を取得します。これは各カラムへのスクロール位置を指定するためです。

/**
 * thの各カラム左端の位置を取得
 * @return offsetPositionLeft
 */
function getOffsetPositionLeft() {
    if (!doctorTable) return;
    const PositionLeft = [];
    let offsetPositionLeft;
    const thColumns = doctorTable.querySelectorAll('table > thead > tr > th:not(:first-child)');
    const value = doctorTable.querySelector('table > thead > tr > th:first-child');
    const offset = value ? value.getBoundingClientRect().right : undefined;
    const columnsArray = Array.from(thColumns);

    columnsArray.forEach(function (column) {
        const left = column.getBoundingClientRect().left;
        PositionLeft.push(left);
    });
    if (offset) {
        offsetPositionLeft = PositionLeft.map(function (x) {
            return x - offset;
        });
        return offsetPositionLeft;
    }
}

doctorTable && doctorTable.addEventListener('scroll', getOffsetPositionLeft);

ボタンをクリックしたときの挙動

次に、ボタンをクリックしたときに指定の位置にスクロールするように設定します。

/**
 * ボタンをクリックしたとき
 */
const scrollButtons = doctorTable ? doctorTable.querySelectorAll('ul.scroll-toggle li') : null;
if (scrollButtons) {
    const position = getOffsetPositionLeft();
    scrollButtons.forEach(function (button) {
        const buttonFirstChild = button.firstElementChild;
        if (buttonFirstChild) {
            buttonFirstChild.addEventListener('click', function () {
                const buttonArray = Array.from(scrollButtons);
                const scrollIndex = buttonArray.indexOf(button); // クリックしたbuttonは兄弟要素の中の何番目の要素かを取得
                if (position) {
                    const positionScroll = Math.ceil(position[scrollIndex]);
                    doctorTable && doctorTable.scrollTo({
                        left: positionScroll,
                        behavior: 'smooth'
                    });
                }
            });
        }
    });
}

表をスクロールしたときの挙動

最後に、表をスクロールしたとき、ボタンのハイライトが切り替わるように設定します。

/**
 * 表をスクロールしたとき
 */
function scrollTable() {
    if (!doctorTable) return;
    const position = getOffsetPositionLeft();
    const scrollButtons = doctorTable.querySelectorAll('ul.scroll-toggle li');
    const arrayScrollButton = Array.from(scrollButtons);
    let prevIndex = 0;
    const prevElement = doctorTable.querySelector('li[aria-current="true"]');
    if (prevElement && position) {
        prevIndex = arrayScrollButton.indexOf(prevElement);
        const currentIndex = position.reduce(function (maxIndex, value, index) {
            return value <= 0 ? index : maxIndex;
        }, -1);
        if (prevIndex === currentIndex) {
            return;
        } else {
            prevElement.setAttribute("aria-current", "false");
            scrollButtons[currentIndex].setAttribute("aria-current", "true");
        }
    }
}

doctorTable && doctorTable.addEventListener('scroll', scrollTable);

完成形

完成形は以下のCodePenで確認できます。

(画面幅を狭めることで動きを確認することができます。)

See the Pen spectrum-web-analyzer by FOURIER Inc. ( @fourier-inc )on CodePen .

まとめ

表の列が増えるとスマホサイズでの表示が見づらくなってしまいますが、この対処法を参考にしていただければと思います。

ぜひ試してみてください!

Takahashi

Takahashi slash forward icon Engineer

主にWordPressを担当しています。趣味はフットサル、サッカー観戦。

関連記事