Làm cách nào để áp dụng các kiểu được quản lý Vật liệu-UI cho các yếu tố không phản ứng, không phản ứng?


9

Tôi có một ứng dụng mà tôi đang sử dụng UI UI và nhà cung cấp chủ đề của nó (sử dụng JSS).

Bây giờ tôi đang kết hợp fullcalWiki-Reac , đây không thực sự là một thư viện React hoàn chỉnh - nó chỉ là một trình bao bọc thành phần React mỏng xung quanh mã fullcalWiki ban đầu.

Điều đó có nghĩa là, tôi không có quyền truy cập vào những thứ như đạo cụ kết xuất để kiểm soát cách nó tạo kiểu cho các thành phần của nó.

Tuy nhiên, nó cung cấp cho bạn quyền truy cập trực tiếp vào các phần tử DOM, thông qua một cuộc gọi lại được gọi khi nó kết xuất chúng (ví dụ: phương thức eventRender ).

Đây là một hộp cát demo cơ bản.

nhập mô tả hình ảnh ở đây

Bây giờ những gì tôi muốn làm là làm cho các thành phần Lịch đầy đủ (ví dụ: các nút) chia sẻ giao diện giống như phần còn lại của ứng dụng của tôi.

Một cách để làm điều này là tôi có thể ghi đè thủ công tất cả các kiểu bằng cách xem tên lớp mà nó sử dụng và triển khai kiểu cho phù hợp.

Hoặc - tôi có thể triển khai chủ đề Bootstrap - như được đề xuất trong tài liệu của họ.

Nhưng vấn đề với một trong những giải pháp này, đó là:

  1. Nó sẽ là rất nhiều công việc
  2. Tôi sẽ gặp vấn đề về đồng bộ hóa, nếu tôi thay đổi chủ đề MUI của mình và quên cập nhật chủ đề lịch thì chúng sẽ trông khác.

Những gì tôi muốn làm là:

  • Kỳ diệu chuyển đổi chủ đề MUI thành chủ đề Bootstrap.
  • Hoặc tạo ánh xạ giữa tên lớp MUI và tên lớp lịch, đại loại như:
.fc-button = .MuiButtonBase-root.MuiButton-root.MuiButton-contained
.fc-button-primary= .MuiButton-containedPrimary

Tôi không ngại phải xoa bóp các bộ chọn, v.v. để làm cho nó hoạt động (ví dụ: Ví dụ - Nút MUI có hai nhịp bên trong, trong khi Lịch đầy đủ chỉ có một). Chủ yếu là khi tôi thay đổi chủ đề - không muốn phải thay đổi chủ đề ở hai nơi.

Sử dụng một cái gì đó như Sass với @extendcú pháp của nó sẽ là những gì tôi có trong tâm trí. Tôi có thể tạo CSS toàn lịch với Sass đủ dễ dàng - nhưng Sass sẽ có quyền truy cập vào MuiTheme như thế nào?

Có lẽ tôi có thể có cách tiếp cận ngược lại - nói với MUI 'Này các tên lớp này ở đây nên được đặt kiểu giống như các lớp MUI này'.

Bất kỳ đề nghị cụ thể về cách tôi sẽ giải quyết điều này?

Câu trả lời:


4

Đây là gợi ý của tôi (rõ ràng, nó không đơn giản). Lấy các kiểu từ chủ đề MUI và tạo stylethẻ dựa trên nó bằng cách sử dụng react-helmet. Để thực hiện nó một cách độc đáo, tôi đã tạo ra một thành phần "trình bao bọc" làm bản đồ. Tôi chỉ thực hiện quy tắc chính nhưng nó có thể được mở rộng cho tất cả các quy tắc khác.

Bằng cách này, bất kỳ thay đổi nào bạn sẽ thực hiện trong chủ đề cũng sẽ ảnh hưởng đến các bộ chọn được ánh xạ.

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>
  );
}

Và việc sử dụng bộ chuyển đổi

<MuiAdapter theme={theme} />

Bản demo hoạt động: https://codesandbox.io/s/reverent-mccarthy-3o856

chụp màn hình


Tôi thích suy nghĩ này. Vấn đề với giải pháp này là về cơ bản bạn vẫn sẽ tự mình thực hiện tất cả các kiểu (ví dụ: màu di chuột, phần đệm, bán kính đường viền, v.v.). Nếu ví dụ, bạn quyết định văn bản nút nên được gạch chân, bạn sẽ cần phải nhớ thêm text-decorationtài sản vào mũ bảo hiểm.
dwjohnston

Tôi hiểu những gì bạn yêu cầu. Tôi đã thử thực hiện một cách tiếp cận khác và thao tác các stylethẻ MUI và thêm các công .fc-cụ chọn chúng theo bản đồ nhưng chúng có xung đột ở các cấp cơ sở (chẳng hạn như display, paddingv.v.) vì vậy tôi không thấy nó sẽ hoạt động như thế nào ngay cả khi bạn có tùy chọn để di chuyển nó trong scss. Ví dụ: Codeandbox.io/s/charming-sound-3xmj9
Mosh Feu

Haha - bây giờ điều này tôi thích. Tôi sẽ cho nó một cái nhìn tốt hơn sau này.
dwjohnston

3

Bạn có thể tạo ánh xạ giữa tên lớp MUI và tên lớp lịch bằng cách đi qua ref. Có thể đây không phải là điều mà một số người gọi là "thực hành tốt nhất" ... nhưng đó là một giải pháp :). Lưu ý rằng tôi đã cập nhật thành phần của bạn từ thành phần chức năng thành thành phần lớp, nhưng bạn có thể thực hiện việc này bằng các móc trong thành phần chức năng.

Thêm ref

Thêm một refyếu tố MUI mà bạn muốn đặt làm tham chiếu, trong trường hợp của bạn là Button.

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

Và một refgói divquanh thành phần bạn muốn ánh xạ tới. Bạn không thể thêm nó trực tiếp vào thành phần vì điều đó sẽ không cho phép chúng tôi truy cập children.

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

Các lớp bản đồ

Từ việc componentDidMount()thêm bất kỳ logic nào bạn cần để nhắm mục tiêu nút DOM chính xác (đối với trường hợp của bạn, tôi đã thêm logic cho typematchingClass). Sau đó chạy logic đó trên tất cả các nút FullCalWiki DOM và thay thế classListbất kỳ nút nào phù hợp.

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);
    }
  });
};

Điều này có thể hơi nặng tay, nhưng nó đáp ứng yêu cầu bằng chứng trong tương lai của bạn khi bạn cập nhật UI UI cập nhật. Nó cũng sẽ cho phép bạn thay đổi classListkhi bạn chuyển nó sang một phần tử, có lợi ích rõ ràng.

Hãy cẩn thận

Nếu các thành phần 'được ánh xạ tới' ( FullCalendarcác lớp được cập nhật trên các thành phần bạn nhắm mục tiêu (như nếu nó được thêm vào.is-selected nút hiện tại) hoặc thêm các nút mới sau khi gắn thì bạn phải tìm ra cách theo dõi các thay đổi có liên quan và chạy lại Hợp lý.

Tôi cũng nên đề cập rằng (rõ ràng) việc thay đổi các lớp có thể gây ra hậu quả ngoài ý muốn như phá vỡ giao diện người dùng và bạn sẽ phải tìm ra cách khắc phục chúng.

Đây là hộp cát hoạt động: https://codesandbox.io/s/determined-frog-3loyf


1
Những công việc này. Lưu ý rằng bạn không phải chuyển đổi thành một thành phần lớp - bạn có thể sử dụng các hook để làm điều này.
dwjohnston

Bạn đã đúng, điều này có thể được thực hiện với các móc trong một thành phần chức năng. Tôi đã cập nhật câu trả lời để phản ánh điều đó.
sallf

Đẹp, khá là cách tiếp cận thực dụng. Nhưng không thực sự khả thi vì bạn sẽ luôn cần một ref.
Aniket Chowdhury
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.