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.