Material-UI가 아닌 비 반응 요소에 Material-UI 관리 스타일을 어떻게 적용합니까?


9

Material UI와 테마 제공자 (JSS 사용)를 사용하는 응용 프로그램이 있습니다.

이제 fullcalendar-react를 통합하고 있습니다. 실제로는 완전한 React 라이브러리가 아니며 원래 fullcalendar 코드 주위의 얇은 React 구성 요소 래퍼입니다.

즉, 렌더링 소품과 같은 요소에 액세스하여 요소의 스타일을 지정하는 방법을 제어 할 수는 없습니다.

그러나 렌더링 할 때 호출되는 콜백 (예 : eventRender 메소드 )을 통해 DOM 요소에 직접 액세스 할 수 있습니다 .

기본 데모 샌드 박스가 있습니다.

여기에 이미지 설명을 입력하십시오

이제 내가 원하는 것은 전체 캘린더 구성 요소 (예 : 버튼)를 나머지 응용 프로그램과 동일한 모양과 느낌으로 공유하는 것입니다.

이를 수행하는 한 가지 방법은 사용하는 클래스 이름을보고 스타일을 적절히 구현하여 모든 스타일을 수동으로 재정의 할 수 있다는 것입니다.

또는- 설명서에서 제안한 것처럼 Bootstrap 테마를 구현할 수 있습니다.

그러나 이러한 솔루션 중 하나의 문제점은 다음과 같습니다.

  1. 많은 일이 될 것입니다
  2. MUI 테마를 변경하고 캘린더 테마를 업데이트하지 않은 경우 동기화 모양이 다르게 보일 수 있습니다.

내가하고 싶은 것은 다음 중 하나입니다.

  • MUI 테마를 Bootstrap 테마로 마술처럼 변환하십시오.
  • 또는 MUI 클래스 이름과 달력 클래스 이름 사이에 다음과 같은 매핑을 만듭니다.
.fc-button = .MuiButtonBase-root.MuiButton-root.MuiButton-contained
.fc-button-primary= .MuiButton-containedPrimary

선택기 등을 마사지하여 작동시킬 필요는 없습니다 (예 : MUI 버튼에는 두 개의 내부 범위가 있지만 전체 달력에는 하나만 있음). 주로 테마를 변경할 때입니다. 두 곳에서 테마를 변경하고 싶지는 않습니다.

@extend구문에 Sass와 같은 것을 사용하는 것이 내가 염두에 둔 것입니다. Sass를 사용하여 전체 캘린더 CSS를 쉽게 만들 수는 있지만 Sass는 어떻게 MuiTheme에 액세스 할 수 있습니까?

아마도 나는 반대의 접근법을 취할 수 있습니다-MUI에게 '이 클래스 이름은 이러한 MUI 클래스와 같은 스타일이어야합니다.'

이 문제를 해결하는 방법에 대한 구체적인 제안이 있습니까?

답변:


4

여기 내 제안이 있습니다 (분명히 간단하지는 않습니다). MUI 테마에서 스타일을 가져 style와서를 사용하여이를 기반으로 태그를 생성 하십시오 react-helmet. 이벤트를 훌륭하게 수행하기 위해 맵을 수행하는 "래퍼"구성 요소를 만들었습니다. 기본 규칙 만 구현했지만 다른 모든 규칙으로 확장 할 수 있습니다.

이런 식으로 테마에서 변경하면 매핑 된 선택자에도 영향을줍니다.

import React from "react";
import { Helmet } from "react-helmet";

export function MuiAdapter({ theme }) {
  if (!theme.palette) {
    return <></>;
  }
  return (
    <Helmet>
      <style type="text/css">{`
          .fc-button-primary {
            background: ${theme.palette.primary.main}
          }
          /* more styles go here */
      `}</style>
    </Helmet>
  );
}

그리고 어댑터의 사용

<MuiAdapter theme={theme} />

실무 데모 : https://codesandbox.io/s/reverent-mccarthy-3o856

스크린 샷


나는이 생각을 좋아한다. 이 솔루션의 문제점은 여전히 ​​기본적으로 모든 스타일 (예 : 호버 색상, 패딩, 테두리 반경 등)을 직접 구현한다는 것입니다. 예를 들어, 단추 텍스트에 밑줄을 표시하기로 결정한 text-decoration경우 헬멧에 속성을 추가해야합니다 .
— dwjohnston

나는 당신이 요구하는 것을 이해합니다. 나는 다른 접근 방식을 취하고 MUI의 조작을 시도 style태그를하고 추가 .fc-지도에 따라 선택기 있지만 기본 수준의 충돌 (예 :이 display, padding난 당신이있을 것입니다 경우에도 작동 표시되지 않습니다, 그래서 등) scss에서 마이그레이션하는 옵션입니다. 예를 들면 다음과 같습니다. codesandbox.io/s/charming-sound-3xmj9
— Mosh Feu

하하-이제 좋아합니다. 나중에 더 잘 볼게요.
— dwjohnston

3

를 통해 MUI 클래스 이름과 달력 클래스 이름 사이의 매핑을 만들 수 있습니다 ref. 이것이 "모범 사례"라고 부르는 것이 아닐 수도 있지만 해결책은 :)입니다. 구성 요소를 기능 구성 요소에서 클래스 구성 요소로 업데이트했지만 기능 구성 요소의 후크로이를 수행 할 수 있습니다.

심판 추가

ref참조로 설정하려는 MUI 요소에 a 를 추가 하십시오 Button.

<Button
  color="primary"
  variant="contained"
  ref={x => {
    this.primaryBtn = x;
  }}
>

그리고 ref랩핑에 div당신은 매핑 할 구성 요소 주위. 에 액세스 할 수 없으므로 구성 요소에 직접 추가 할 수 없습니다 children.

<div
  ref={x => {
    this.fullCal = x;
  }}
>
  <FullCalendar
    ...
  />
</div>

지도 수업

에서 componentDidMount() 올바른 DOM 노드를 대상으로해야 할 어떤 논리 추가 (귀하의 경우에, 나는에 대한 논리를 추가 type하고 matchingClass). 그런 다음 모든 FullCalendar DOM 노드에서 해당 논리를 실행 classList하고 일치 하는 노드를 교체하십시오 .

componentDidMount() {
  this.updatePrimaryBtns();
}

updatePrimaryBtns = () => {
  const children = Array.from(this.fullCal.children);
  // Options
  const type = "BUTTON";
  const matchingClass = "fc-button-primary";

  this.mapClassToElem(children, type, matchingClass);
};

mapClassToElem = (arr, type, matchingClass) => {
  arr.forEach(elem => {
    const { tagName, classList } = elem;
    // Check for match
    if (tagName === type && Array.from(classList).includes(matchingClass)) {
      elem.classList = this.primaryBtn.classList.value;
    }

    // Run on any children
    const next = elem.children;
    if (next.length > 0) {
      this.mapClassToElem(Array.from(next), type, matchingClass);
    }
  });
};

이 방법은 다소 부담이 될 수 있지만 업데이트 재질 UI를 업데이트 할 때 향후 증명 요구 사항을 충족합니다. 또한 classList요소에 전달할 때를 변경하면 명백한 이점이 있습니다.

경고

'매핑 대상'구성 요소 ( FullCalendar)가 현재 요소에 추가 된 것처럼 대상 요소의 클래스를 업데이트 .is-selected하거나 마운트 후 새 단추를 추가하는 경우 관련 변경 사항을 추적하고 다시 실행할 수있는 방법을 찾아야합니다. 논리.

또한 클래스를 변경하면 UI가 깨지는 것과 같이 의도하지 않은 결과가 발생할 수 있으며이를 수정하는 방법을 알아야합니다.

작동중인 샌드 박스는 다음과 같습니다. https://codesandbox.io/s/determined-frog-3loyf


1
작동합니다. 클래스 컴포넌트로 변환 할 필요는 없습니다. 후크를 사용하여이를 수행 할 수 있습니다.
— dwjohnston

예, 맞습니다. 기능적 구성 요소의 후크로 수행 할 수 있습니다. 이를 반영하여 답변을 업데이트했습니다.
— sallf

훌륭하고 실용적인 접근 방식. 그러나 항상 심판이 필요할 것이므로 실제로 실현 가능하지는 않습니다.
— Aniket Chowdhury '12
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.