Magic Responsive Tables, 자극 및 IntersectionObserver
                                            
                                                
                                                
                                                
                                                
                                                
                                                 32113 단어  railswebdevjavascript
                    
열을 추가할 때 문제가 발생했습니다.작은 화면을 어떻게 처리할 겁니까?
모든 열을 볼 수 있도록 테이블을 수평으로 스크롤해야 합니다.책상은 예민해져야 한다.
본고에서 우리는 Shopify’s Polaris UI toolkit에서 사용한 측면 스크롤 소부품(현재 React에 내장되어 있음)을 소개할 것이다. 우리는 Stimulus을 사용하여 이 기능을 다시 만들 것이다. React에서 데이터 테이블을 다시 쓸 필요가 없다.
우리는 IntersectionObserver API 을 사용할 것이다. 이것은 React 구성 요소가 최초로 사용한 것처럼 크기 조정 관찰 프로그램과 스크롤 관찰 프로그램을 추가하는 것이 아니라, 광범위하게 사용되는 새로운 브라우저 기능이다.
자극 빠른 시작
Stimulus 기존 HTML에 점진적인 상호 작용을 추가할 수 있는 애플릿 라이브러리
CSS가 요소가 문서 객체 모델(DOM)에 나타날 때 요소에 스타일을 추가하는 것처럼 Stimulus도 요소가 DOM에 나타날 때 요소에 상호작용(이벤트 프로세서, 동작 등)을 추가하고 요소가 DOM에서 제거될 때 제거합니다.Rails와 서버에서 보여 주는 HTML과 매우 일치하기 때문에 이 곳에서 사용할 것입니다.
HTML에 CSS 클래스를 추가해서 스타일을 연결할 수 있는 것처럼, 요소에 특수한 자극
data- 속성을 추가해서 상호작용을 연결할 수도 있습니다.자극은 이런 것들을 감시하고 일치할 때 상호작용을 불러일으킨다. (((table-scroll 라는 자극 컨트롤러)<div data-controller="table-scroll">
  <button
    class="button button-scroll-right"
    data-table-scroll-target="scrollRightButton"
    data-action="table-scroll#scrollRight"
  >
    ...
  </button>
</div>
Shopify Polaris 데이터 테이블에서 스크롤 탐색 다시 만들기
Shopify의 UI 라이브러리는 상하문이 수용할 수 있는 열을 초과할 때만 표시할 수 있는 똑똑한 사이드 스크롤 내비게이션 위젯을 도입했다.좌우로 스크롤하는 단추와 보기에 몇 열의 작은 점이 있는지 표시합니다.
원작이 React에 있을 때, 우리는 자극을 사용하여 재창조 기능을 사용할 것이다.이 HTML은 Shopify의 구현에서 나온 것입니다. 모든 Polaris 종류를 제거하면 응용 프로그램 스타일에 맞는 구조를 가지게 됩니다.
따라서 응용 프로그램에서 인코딩될 전체적인 태그 구조를 만들고
table-scroll 자극 컨트롤러를 추가합니다.(간결하게 보기 위해 일부 CSS 스타일이 생략되었으므로 가능한 경우 키 클래스를 호출하려고 합니다.)
<div data-controller="table-scroll">
  <div data-table-scroll-target="navBar">
    <!-- Navigation widget -->
  </div>
  <div class="flex flex-col mx-auto">
    <div class="overflow-x-auto" data-table-scroll-target="scrollArea">
      <table class="min-w-full">
        <!-- Table contents -->
      </table>
    </div>
  </div>
</div>
<th> 표시에 속성을 추가해서 각 열의 목표를 설정합니다.우리는 모든 열을 column의 목표값으로 설정하여 자극적인 다목적 귀속을 이용할 수 있다. 이것은 자극 컨트롤러에서 자동으로 columnTargets수 그룹을 귀속시킬 수 있다.<!-- Table contents -->
<table class="min-w-full">
  <thead>
    <tr>
      <th data-table-scroll-target="column">Product</th>
      <th data-table-scroll-target="column">Price</th>
      <th data-table-scroll-target="column">SKU</th>
      <th data-table-scroll-target="column">Sold</th>
      <th data-table-scroll-target="column">Net Sales</th>
    </tr>
  </thead>
  <tbody>
    <!-- Table body -->
  </tbody>
</table>
<!-- Navigation widget -->
<div data-table-scroll-target="navBar">
  <!-- Left button -->
  <button data-table-scroll-target="leftButton" data-action="table-scroll#scrollLeft">
    <svg></svg>
  </button>
  <!-- Column visibility dots -->
  <% 5.times do %>
    <span class="text-gray-200" data-table-scroll-target="columnVisibilityIndicator">
      <svg></svg>
    </span>
  <% end %>
  <!-- Scroll Right button -->
  <button data-table-scroll-target="rightButton" data-action="table-scroll#scrollRight">
    <svg></svg>
  </button>
</div>
<div
  data-controller="table-scroll"
  data-table-scroll-nav-shown-class="flex"
  data-table-scroll-nav-hidden-class="hidden"
  data-table-scroll-button-disabled-class="text-gray-200"
  data-table-scroll-indicator-visible-class="text-blue-600"
>
  <!-- The rest of the markup -->
</div>
IntersectionObserver를 사용하여 활성화
현재 우리는 이미 표시를 주석했으니, 우리는 자극 컨트롤러를 추가할 수 있다.
우리는
scrollArea의 위치를 관찰하고 보이는 것을 검출하는 방법이 필요하다.Polaris 구현과 달리 APIIntersectionObserver를 사용합니다.window.resize 또는 window.scroll가 필요하지 않으며, 이는 새 네이티브 브라우저 API보다 성능이 더 비쌉니다.IntersectionObserver API는 요소의 가시성을 모니터링하고 가시성 변경 시 콜백을 트리거합니다.우리의 예에서, 우리는 열 제목의 가시성에 주목할 것이다.// controllers/table_scroll_controller.js
import { Controller } from "stimulus";
export default class extends Controller {
  static targets = [
    "navBar",
    "scrollArea",
    "column",
    "leftButton",
    "rightButton",
    "columnVisibilityIndicator",
  ];
  static classes = [
    "navShown",
    "navHidden",
    "buttonDisabled",
    "indicatorVisible",
  ];
  connect() {
    // start watching the scrollAreaTarget via IntersectionObserver
  }
  disconnect() {
    // stop watching the scrollAreaTarget, teardown event handlers
  }
}
IntersectionObserver 확인해야 하며, 지원하지 않으면 우아하게 등급을 내려야 한다.컨트롤러가 연결될 때, 우리는
IntersectionObserver를 만들고, 리셋을 제공한 다음, 우리가 관찰하고자 하는 모든 것을 등록합니다 IntersectionObserver.시작할 때마다
columnTargets 리셋을 시작할 때 (intersection Observer가 초기화될 때 기본적으로 시작합니다.) 모든 열 제목의 updateScrollNavigation 속성을 업데이트해서 다른 리셋을 나중에 검사할 수 있도록 합니다.import { Controller } from "stimulus";
function supportsIntersectionObserver() {
  return (
    "IntersectionObserver" in window ||
    "IntersectionObserverEntry" in window ||
    "intersectionRatio" in window.IntersectionObserverEntry.prototype
  );
}
export default class extends Controller {
  static targets = [...];
  static classes = [...];
  connect() {
    this.startObservingColumnVisibility();
  }
  startObservingColumnVisibility() {
    if (!supportsIntersectionObserver()) {
      console.warn(`This browser doesn't support IntersectionObserver`);
      return;
    }
    this.intersectionObserver = new IntersectionObserver(
      this.updateScrollNavigation.bind(this),
      {
        root: this.scrollAreaTarget,
        threshold: 0.99, // otherwise, the right-most column sometimes won't be considered visible in some browsers, rounding errors, etc.
      }
    );
    this.columnTargets.forEach((headingEl) => {
      this.intersectionObserver.observe(headingEl);
    });
  }
  updateScrollNavigation(observerRecords) {
    observerRecords.forEach((record) => {
      record.target.dataset.isVisible = record.isIntersecting;
    });
    this.toggleScrollNavigationVisibility();
    this.updateColumnVisibilityIndicators();
    this.updateLeftRightButtonAffordance();
  }
  disconnect() {
    this.stopObservingColumnVisibility();
  }
  stopObservingColumnVisibility() {
    if (this.intersectionObserver) {
      this.intersectionObserver.disconnect();
    }
  }
화면에서 CSS 클래스를 열고 닫으려면 Stimulus의 대상 바인딩을 사용합니다.CSS 클래스를 구성할 수 있으므로 JavaScript 패키지를 재구성하는 대신 HTML을 편집하여 UI를 조정할 수 있습니다.
toggleScrollNavigationVisibility() {
  const allColumnsVisible =
    this.columnTargets.length > 0 &&
    this.columnTargets[0].dataset.isVisible === "true" &&
    this.columnTargets[this.columnTargets.length - 1].dataset.isVisible ===
      "true";
  if (allColumnsVisible) {
    this.navBarTarget.classList.remove(this.navShownClass);
    this.navBarTarget.classList.add(this.navHiddenClass);
  } else {
    this.navBarTarget.classList.add(this.navShownClass);
    this.navBarTarget.classList.remove(this.navHiddenClass);
  }
}
updateColumnVisibilityIndicators() {
  this.columnTargets.forEach((headingEl, index) => {
    const indicator = this.columnVisibilityIndicatorTargets[index];
    if (indicator) {
      indicator.classList.toggle(
        this.indicatorVisibleClass,
        headingEl.dataset.isVisible === "true"
      );
    }
  });
}
updateLeftRightButtonAffordance() {
  const firstColumnHeading = this.columnTargets[0];
  const lastColumnHeading = this.columnTargets[this.columnTargets.length - 1];
  this.updateButtonAffordance(
    this.leftButtonTarget,
    firstColumnHeading.dataset.isVisible === "true"
  );
  this.updateButtonAffordance(
    this.rightButtonTarget,
    lastColumnHeading.dataset.isVisible === "true"
  );
}
updateButtonAffordance(button, isDisabled) {
  if (isDisabled) {
    button.setAttribute("disabled", "");
    button.classList.add(this.buttonDisabledClass);
  } else {
    button.removeAttribute("disabled");
    button.classList.remove(this.buttonDisabledClass);
  }
}
scrollLeft() {
  // scroll to make visible the first non-fully-visible column to the left of the scroll area
  let columnToScrollTo = null;
  for (let i = 0; i < this.columnTargets.length; i++) {
    const column = this.columnTargets[i];
    if (columnToScrollTo !== null && column.dataset.isVisible === "true") {
      break;
    }
    if (column.dataset.isVisible === "false") {
      columnToScrollTo = column;
    }
  }
  this.scrollAreaTarget.scroll(columnToScrollTo.offsetLeft, 0);
}
scrollRight() {
  // scroll to make visible the first non-fully-visible column to the right of the scroll area
  let columnToScrollTo = null;
  for (let i = this.columnTargets.length - 1; i >= 0; i--) {
    // right to left
    const column = this.columnTargets[i];
    if (columnToScrollTo !== null && column.dataset.isVisible === "true") {
      break;
    }
    if (column.dataset.isVisible === "false") {
      columnToScrollTo = column;
    }
  }
  this.scrollAreaTarget.scroll(columnToScrollTo.offsetLeft, 0);
}
그것을 싸라
봐라!우리는 매우 아름다운 응답 스크롤 테이블을 가지고 있다.큰 화면에서, 그것은 일반적인 HTML 표처럼 보인다.그러나 뷰 포트를 축소하면 내비게이션 위젯이 나타나고 테이블의 어떤 부분이 보이는지 볼 수 있습니다.
전반적으로 말하자면, 이 컨트롤러의 코드는 200줄도 안 되므로, 전체 응용 프로그램에서 각종 크기의 표를 처리할 수 있어야 한다.
Hotwire의 발표에 따라 비수욕 응용 프로그램의'마지막 마일'상호작용에 있어 자극은 중요한 구성 부분이다.Stimum 은 대개 JavaScript 를 적게 실행하는 데 사용되지만, 미러링 기능이 완비된 UI 라이브러리를 위한 보다 견고한 컨트롤러를 구축할 수 있습니다.
특이한 클라이언트 프레임워크를 사용하기 위해 응용 프로그램 체계 구조를 완전히 바꾸기 전에 기존의 HTML 태그와 자극을 사용할 수 있는지 확인하십시오.
Reference
이 문제에 관하여(Magic Responsive Tables, 자극 및 IntersectionObserver), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/swanson/magic-responsive-tables-with-stimulus-and-intersectionobserver-21kk텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)