【问题标题】:How to add RTL support for Material UI React如何为 Material UI React 添加 RTL 支持
【发布时间】:2019-10-13 09:41:49
【问题描述】:

我正在构建一个 LTR 应用程序,我想添加 RTL 支持。 该应用程序基于 Material UI React。 由于我使用的是 CSS Flex Box,因此我可以将应用程序旋转到 RTL,只需将 dir="rtl" 添加到正文中即可。我还在here 提到的主题中添加了direction="rtl"。

但并非一切都改变了。

让我们以此为例: 正如您在此处看到的,我在文本元素的左侧进行了填充。 在 RTL 版本中,由于一切都被颠倒了,所以向左填充在 UI 中没有任何影响,我的意思是它必须向右填充以显示两个元素之间的小空间:

似乎我做错了什么,因为在 Material UI 文档here 中,在添加此 sn-p 并将组件包裹在其周围后,此功能必须是开箱即用的。

这是我的父组件应用:

import React, { PureComponent } from "react";
import { theme } from "./styling/theme";
import Routes from "./Routes";
// Redux
import { Provider } from "react-redux";
import store from "./app/store";

import LoadingBar from "react-redux-loading-bar";
// CSS
import { MuiThemeProvider } from "@material-ui/core/styles";
// import { ThemeProvider } from "@material-ui/styles";
import { create } from "jss";
import rtl from "jss-rtl";
import JssProvider from "react-jss/lib/JssProvider";
// import { StylesProvider, jssPreset } from "@material-ui/styles";
import { createGenerateClassName, jssPreset } from "@material-ui/core/styles";
import { themeObject, colors } from "./styling/theme";
// Helpers
import get from "lodash/get";

// Configure JSS
const jss = create({ plugins: [...jssPreset().plugins, rtl()] });
const generateClassName = createGenerateClassName();

function RTL(props) {
  return (
    <JssProvider jss={jss} generateClassName={generateClassName}>
      {
        props.children
      }
    </JssProvider>
  );
}

class App extends PureComponent {
  render() {
    const isRtl = get(store, "classified.language.rtl", false);
    return (
      <Provider store={store}>
        <RTL>
          <MuiThemeProvider
            theme={
              isRtl
                ? { ...theme, direction: "rtl" }
                : { ...theme, direction: "ltr" }
            }
          >
            <LoadingBar
              style={{
                backgroundColor: colors.primary[500],
                height: themeObject.spacing.unit,
                zIndex: 9999
              }}
            />
            <Routes />
          </MuiThemeProvider>
        </RTL>
      </Provider>
    );
  }
}

export default App;

这是我的组件的一个示例(上图中的那个:CLList):

import React, { Component } from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
// Helpers
import isFunction from "lodash/isFunction";
import cloneDeep from "lodash/cloneDeep";

import styles from "./CLList.styles";

const defaultImg = "IMAGE_URL_HERE";
class CLList extends Component {
  static propTypes = {
    classes: PropTypes.object.isRequired,
    items: PropTypes.arrayOf(
      PropTypes.shape({
        img: PropTypes.string,
        name: PropTypes.string
      })
    ).isRequired,
    onClick: PropTypes.func
  };
  render() {
    const { classes, items, onClick } = this.props;
    return (
      <ul className={classes.list}>
        {items.map((item, key) => (
          <li
            className={classes.item}
            onClick={() => isFunction(onClick) && onClick(cloneDeep(item))}
            key={key}
          >
            <img
              className={classes.image}
              src={item.img || defaultImg}
              alt={item.name}
              title={item.name}
            />
            <span className={classes.label}>{item.name}</span>
          </li>
        ))}
      </ul>
    );
  }
}

export default withStyles(styles)(CLList);

最后一个文件是 CLList 的 CSS :

import { colors } from "../..";
const styles = theme => ({
  list: {
    display: "flex",
    flexDirection: "column",
    listStyle: "none",
    padding: 5,
    margin: 0,
    "& > li:not(:last-child)": {
      marginBottom: 10
    }
  },
  item: {
    flex: 1,
    display: "flex",
    cursor: "pointer",
    "&:hover": {
      backgroundColor: colors.primary[50]
    }
  },
  image: {
    flex: "0 0 15%",
    maxWidth: "40px",
    maxHeight: "40px"
  },
  label: {
    flex: "1",
    alignSelf: "center",
    paddingLeft: 20
  }
});

export default styles;

我希望标签的 paddingLeft 为 => paddingRight。这可能吗 ?它是开箱即用的功能吗?或者我应该只使用RTL-CSS-JS 并在正文包含 dir="RTL" 时包装我的所有样式对象以自动更改样式?

我对这两个库也很困惑:

  • @material-ui/core/styles
  • @material-ui/styles

我应该使用第一个还是第二个?有什么区别?

感谢您的宝贵时间。

编辑 1:

我在我的 CSS 对象上使用了 rtlCSSJS,得到了预期的结果。但我不确定这是否是最好的方法。 CLList 的 CSS 现在看起来像这样:

import rtlCSSJS from "rtl-css-js";
import { colors } from "../..";
const defaultDir = document.body.getAttribute("dir");
const styles = theme =>
  defaultDir === 'rtl' ? rtlCSSJS({...CSS_HERE....}) : {...CSS_HERE....};
export default styles;

【问题讨论】:

    标签: javascript css reactjs material-ui react-material


    【解决方案1】:

    我想我找到了自己问题的解决方案,但请随意添加任何增强功能或更好的解决方案。

    Material UI 默认使用 jss-rtl,最后一个是 rtl-css-js 的包装器。所以不需要直接使用 rtl-css-js,因为 Material UI 会完成这项工作。

    我将父应用组件更改为:

    import React, { PureComponent } from "react";
    import Routes from "./Routes";
    import RTL from "./RTL";
    // Redux
    import { Provider } from "react-redux";
    import store from "./app/store";
    
    import LoadingBar from "react-redux-loading-bar";
    
    import { themeObject, colors } from "./styling/theme";
    
    class App extends PureComponent {
      render() {
        return (
          <Provider store={store}>
            <RTL>
              <>
                <LoadingBar
                  // className="loading"
                  style={{
                    backgroundColor: colors.primary[500],
                    height: themeObject.spacing.unit,
                    zIndex: 9999
                  }}
                />
                <Routes />
              </>
            </RTL>
          </Provider>
        );
      }
    }
    
    export default App;
    

    我添加了 RTL 组件,它将连接到 Redux 以定义正确的主题和正确的方向。我将语言数据保存在 Redux 中,并根据这些数据定义为我的应用程序提供的主题。

    这是 RTL 组件:

    import React, { PureComponent } from "react";
    import PropTypes from "prop-types";
    // Redux
    import { connect } from "react-redux";
    // CSS
    import { MuiThemeProvider, createMuiTheme } from "@material-ui/core/styles";
    import { create } from "jss";
    import rtl from "jss-rtl";
    import JssProvider from "react-jss/lib/JssProvider";
    import { createGenerateClassName, jssPreset } from "@material-ui/core/styles";
    
    // Theme
    import { themeObject } from "./styling/theme";
    
    // Helpers
    import get from "lodash/get";
    // Configure JSS
    const jss = create({ plugins: [...jssPreset().plugins, rtl()] });
    const generateClassName = createGenerateClassName();
    
    const G_isRtl = document.body.getAttribute("dir") === "rtl";
    
    class RTL extends PureComponent {
      static propTypes = {
        children: PropTypes.oneOfType([
          PropTypes.array,
          PropTypes.object,
          PropTypes.node
        ]),
        language: PropTypes.object
      };
    
      render() {
        const { children, language } = this.props;
        const isRtl = get(language, "rtl", G_isRtl);
    
        const theme = createMuiTheme({
          ...themeObject,
          direction: isRtl ? "rtl" : "ltr"
        });
    
        return (
          <JssProvider jss={jss} generateClassName={generateClassName}>
            <MuiThemeProvider theme={theme}>{children}</MuiThemeProvider>
          </JssProvider>
        );
      }
    }
    
    const mapStateToProps = ({ classified }) => ({
      language: classified.language
    });
    export default connect(mapStateToProps)(RTL);
    

    现在所有子组件都将根据语言在 RTL 和 LTR 之间切换,我们可以只专注于一个布局,所有的逆向工作都通过这个插件完成。

    我还想说,按照官方documentation 中的说明对我不起作用!我发现的大部分解决方案都是基于答案here

    【讨论】:

      猜你喜欢
      • 2020-05-02
      • 1970-01-01
      • 1970-01-01
      • 2021-04-10
      • 1970-01-01
      • 2018-07-23
      • 2018-11-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多