<div class="utility-09 p-2" id="js-utility-09">
    <div class="table-container">
        <table class="table is-striped">
            <thead id="js-utility-09-head"></thead>
            <tbody id="js-utility-09-body"></tbody>
        </table>
    </div>
</div>
#js-utility-09.utility-09.p-2
  .table-container
    table.table.is-striped
      thead#js-utility-09-head
      tbody#js-utility-09-body
/* No context defined. */
  • Content:
    $BLOCK_NAME: '.utility-09';
    
    // 変数
    $width_min: 240px;
    $width_max: 360px;
    $c_icon: #000;
    
    #{ $BLOCK_NAME } {
      & table {
        table-layout: fixed;
        min-width: 100%;
      }
    
      & tr {
        word-wrap: break-word;
        word-break: keep-all;
      }
    
      &__head-th {
        position: relative;
      }
    
      &__head-th[data-key='remarks'] {
        min-width: $width_min;
        max-width: $width_max;
      }
    
      &__head-icon {
        position: absolute;
        display: none;
        top: 0;
        bottom: 0;
        right: 4px;
        width: 8px;
        height: 8px;
        margin: auto;
        transition: opacity 0.5s;
        cursor: pointer;
        &:hover {
          opacity: 0.5;
        }
        &::before {
          position: absolute;
          left: 0;
          right: 0;
          display: block;
          width: 0;
          height: 0;
          margin: auto;
          content: '';
          border: solid transparent;
          border-width: 6px 4px;
        }
        &.--asc {
          transform: translateY(-6px);
          &::before {
            bottom: 0;
            border-bottom-color: $c_icon;
          }
        }
        &.--desc {
          transform: translateY(6px);
          &::before {
            top: 0;
            border-top-color: $c_icon;
          }
        }
        @at-root #{ $BLOCK_NAME }__head-th[data-sortable='true'] & {
          display: block;
        }
      }
    
      & tbody td[data-key='remarks'] {
        min-width: $width_min;
        max-width: $width_max;
        word-wrap: normal;
        word-break: break-all;
      }
    }
    
  • URL: /components/raw/utility09/utility09.scss
  • Filesystem Path: src/components/utilities/utility09/utility09.scss
  • Size: 1.5 KB
  • Content:
    'use strict';
    
    export const utility09 = () => {
      const utility = new Utility09();
      utility.init();
    }
    
    type dataKeys = 'name' | 'type' | 'price' | 'number' | 'remarks'
    
    type orderType = 'asc' | 'desc'
    
    type headData = {
      key: dataKeys,
      label: string,
      sortable: boolean,
    }
    
    type bodyData = {
      name: string,
      type: string,
      price: number,
      number: number,
      remarks: string,
    }
    
    type tableData = {
      head: headData[],
      body: bodyData[],
    }
    
    class Utility09 {
      el: HTMLElement;
      headEl: HTMLElement;
      bodyEl: HTMLElement;
      dataUrl: string;
      data: tableData;
      dataCurrent: tableData;
      constructor() {
        this.el = document.getElementById('js-utility-09');
        this.headEl = document.getElementById('js-utility-09-head');
        this.bodyEl = document.getElementById('js-utility-09-body');
        if (location.origin === 'https://zakzakst.github.io') {
          // GitHubの場合
          this.dataUrl = '/parts/data/utility09.json';
        } else {
          // ローカル環境の場合
          this.dataUrl = '/data/utility09.json';
        }
        this.data = null;
        this.dataCurrent = null;
      }
    
      /**
       * 初期化
       */
      async init(): Promise<void> {
        if (!this.el) return;
        // データを取得して初期表示
        const data = await this.loadData();
        this.data = data;
        this.dataCurrent = JSON.parse(JSON.stringify(this.data));
        this.headSet();
        this.dataCurrentUpdate('name', 'asc');
        // 各種イベント設定
        this.onClickHead();
      }
    
      /**
       * データを読み込み
       */
      loadData(): Promise<any> {
        return new Promise(resolve => {
          fetch(this.dataUrl)
            .then((res) => {
              return res.json();
            })
            .then((data) => {
              resolve(data);
            })
            .catch(error => {
              console.log(error);
              resolve({});
            });
        });
      }
    
      /**
       * 見出しの設定
       */
      headSet(): void {
        this.headEl.innerHTML = '';
        const trEl = document.createElement('tr');
        this.dataCurrent.head.forEach(item => {
          const markup = `
            <th class="utility-09__head-th" data-key="${item.key}" data-sortable="${item.sortable}">
              ${item.label}
              <span class="utility-09__head-icon --asc"></span>
              <span class="utility-09__head-icon --desc"></span>
            </th>
          `;
          trEl.insertAdjacentHTML('beforeend', markup);
        });
        this.headEl.appendChild(trEl);
      }
    
      /**
       * 内容の設定
       */
      bodySet(): void {
        this.bodyEl.innerHTML = '';
        this.dataCurrent.body.forEach(item => {
          const markup = `
            <tr>
              <th data-key="name">${item.name}</th>
              <td data-key="type">${item.type}</td>
              <td data-key="price">${item.price}</td>
              <td data-key="number">${item.number}</td>
              <td data-key="remarks">${item.remarks}</td>
            </tr>
          `;
          this.bodyEl.insertAdjacentHTML('beforeend', markup);
        });
      }
    
      /**
       * 表示データの更新
       * @param key 並べ替え対象のデータ
       * @param order 並べ替え方法
       */
      dataCurrentUpdate(key: dataKeys, order: orderType): void {
        const orderVal = order === 'asc' ? 1 : -1;
        const newData: tableData = JSON.parse(JSON.stringify(this.data));
        newData.body.sort((a, b) => {
          let result = 0;
          if (a[key] < b[key]) {
            result = -1 * orderVal;
          } else if (a[key] > b[key]) {
            result = 1 * orderVal;
          }
          return result;
        });
        this.dataCurrent = newData;
        this.bodySet();
      }
    
      /**
       * 見出しクリック時のイベント設定
       */
      onClickHead(): void {
        this.headEl.addEventListener('click', e => {
          const target = <HTMLElement>e.target;
          // 並び替えアイコン以外がクリックされた場合、処理を終了
          if (!target.classList.contains('utility-09__head-icon')) return;
          // 並び替えの種類を取得
          let orderType: orderType = null;
          if (target.classList.contains('--asc')) {
            orderType = 'asc';
          }
          if (target.classList.contains('--desc')) {
            orderType = 'desc';
          }
          // 対象データのキー名を取得
          const targetHeadEl = <HTMLElement>target.closest('.utility-09__head-th');
          const targetKey = <dataKeys>targetHeadEl.dataset.key;
          // 並び替えを実行
          this.dataCurrentUpdate(targetKey, orderType);
        });
      }
    }
    
  • URL: /components/raw/utility09/utility09.ts
  • Filesystem Path: src/components/utilities/utility09/utility09.ts
  • Size: 4.5 KB

JSON データ( https://zakzakst.github.io/parts/data/utility09.json )を取得して
表組を表示・データ並び替えするスクリプト。