在生成RTL CSS文件中创建反应的应用程序内和它们之间的切换基于状态的改变

问题描述 投票:4回答:4

我使用的是创建反应的应用程序内的多语言项目。我想用一些库,如“cssJanus”或“rtlcss”的萨斯生成CSS文件到一个单独的文件,然后使用这个新生成的文件,当我切换到另一种语言转换。

这里是我的index.js看起来像...

import React from "react";
import ReactDOM from "react-dom";
import * as serviceWorker from "./serviceWorker";
import { BrowserRouter as Router } from "react-router-dom";
import { Provider } from "react-redux";
import App from "./App";
import { configureStore } from "./store/configureStore";

const store = configureStore();

ReactDOM.render(
    <Provider store={store}>
        <Router>
            <App />
        </Router>
    </Provider>,
    document.getElementById("root")
);

serviceWorker.unregister();

这是我的“App.js”的模样......

import React, { Component } from "react";
import "./App.scss";
import { Route, Switch } from "react-router-dom";
import SignIn from "./features/signin/SignIn";

class App extends Component {
    render() {
        return (
            <>
                <Switch>
                    <Route path="/" exact component={SignIn} />
                </Switch>
            </>
        );
    }
}

export default App;

正如你可以看到我使用“./App.scss”文件,该文件只需要另一个“.scss”文件一堆@import语句中的“./src/css/”目录...

/* autoprefixer grid: on */
@import "css/reset";
@import "css/variables";
@import "css/global";

我需要你对如何做到这一点的建议。如何从App.scss生成的CSS转换为RTL到自己的.css文件,并将它们和基于全局状态改变原来的生成CSS之间切换。

我搜索了很多这样的事情,但没有运气。

或者,如果你有更好的方法,我洗耳恭听。

css reactjs create-react-app right-to-left rtlcss
4个回答
4
投票

这是一个需要ejecting并添加一个轻量级的webpack-rtl-plugin一个简单的解决方案。

运行后

npx create-react-app react-rtl 
cd react-rtl
yarn eject
yarn add -D webpack-rtl-plugin @babel/plugin-transform-react-jsx-source

转到config/webpack.config.js做出一些调整:

// import the plugin
const WebpackRTLPlugin = require('webpack-rtl-plugin')

// ...

module: { ... }
plugins: [
   // ...,
   // use the plugin
   new WebpackRTLPlugin({ diffOnly: true })
].filter(Boolean),
// ...

在这个阶段,如果运行yarn build查查build/static/css文件夹,你应该希望看到包含您的RTL样式的其他.rtl.css文件。然后,我们需要告诉webpack使用MiniCssExtractPlugin.loader发展以及因此将成为通过link标签而不是内嵌样式风格:

// common function to get style loaders
const getStyleLoaders = (cssOptions, preProcessor) => {
  const loaders = [
    isEnvDevelopment && { loader: MiniCssExtractPlugin.loader }, // <-- use this
    // isEnvDevelopment && require.resolve('style-loader'), <-- instead of this 

不要忘了这个插件,笑:

module: { ... }
plugins: [
   // ...,

   // isEnvProduction &&      <-- comment this out
   new MiniCssExtractPlugin({
     // Options similar to the same options in webpackOptions.output
     // both options are optional
     filename: 'static/css/[name].[contenthash:8].css',
     chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
   }),

   // ...
].filter(Boolean),

从这里,你终于可以抓住你的默认样式href和使用插入RTL风格。这里是你如何可以实现它:

class RtlCssBundleService {
  constructor() {
    this.rtlApplied = false
    this.rtlStyles = [];
    this.ltrStyles = Array.from(
      document.querySelectorAll('link[rel="stylesheet"]')
    )
  }

  insert = () => {
    if (this.rtlApplied) { return }

    this.rtlApplied = true

    if (this.rtlStyles.length) {
      return this.rtlStyles.forEach(style => {
        document.body.appendChild(style)
      })
    }

    this.rtlStyles = this.ltrStyles.map(styleSheet => {
      const link = document.createElement("link")
      link.href = styleSheet.href.replace(/\.css$/, '.rtl.css')
      link.rel = "stylesheet"
      document.body.appendChild(link)
      return link
    })
  }

  detach = () => {
    this.rtlApplied = false
    this.rtlStyles.forEach(style => {
      document.body.removeChild(style)
    })
  }

  toggle = () => {
    return this.rtlApplied
      ? this.detach()
      : this.insert()
  }
}

const rtlStyles = new RtlCssBundleService()

export default rtlStyles

然后从你的任何部件的使用。所以无论如何,我敢肯定,我已经错过了一些东西,也许这是一个可怕的做法,但似乎工作,这里是demo


0
投票

放眼望去有一个叫做从制作的Airbnb提供一个DirectionProvider react-with-direction库 - 组件,你可以在基于语言包的组件。希望帮助。


0
投票

解决方法之一是将生成的CSS文件中的公共文件夹,然后参考他们在您的index.html像头:

<link rel="stylesheet" id="ltr_rtl_css" href="%PUBLIC_URL%/test_ltr.css" />

然后根据需要动态地切换href属性:

  const [rtl, setRtl] = useState(false);
  useEffect(
    () => {
      const dir = rtl ? "rtl" : "ltr";
      const cssElement = document.getElementById("ltr_rtl_css");
      if (cssElement) {
        const rootUrl = process.env.PUBLIC_URL ? process.env.PUBLIC_URL : "";
        const href = rootUrl + "/test_" + dir + ".css";
        cssElement.setAttribute("href", href);
      }
      document.dir = dir;
    },
    [rtl]
  );

这需要在构建过程中一个单独的步骤来从SCSS文件两个CSS文件,而不是直接在你的JavaScript导入SCSS文件,但不使用不同的方法为,我不能想象没有办法做到这一点使用进口在SCSS文件的内容。

这里有一个工作示例展示了这一点:

Edit ltr/rtl

这也包括使用html dir属性来控制通过入口即一个CSS文件样式的一个例子,但它听起来不像,将满足您的需求。

这里有一些资源上如何生成CSS文件的信息:

在上面的链接记录的“看”的方法可能需要生成LTR文件的照顾。我想,这大概是能够钉在cssJanus或rtlcss处理的“看”的方法来生成RTL CSS文件中的一个,但我目前还没有的最佳方式任何专业知识,做到这一点。这也可能是足以满足您的需求,只是让你的生产构建过程的RTL文件部分的生成。


0
投票

如果您使用Flexbox的和CSS网格他们有RTL支持内置的。然后使用CSS Logical Properties保证金,填充,边界等。如果这还不够,那么你可以使用[dir="rtl"] .your-class作为后备。

现在,你不必有两个单独的css文件维护。

这里是一个跨浏览器margin-right例子。

-webkit-margin-end: 25px;
margin-inline-end: 25px;
@supports (not (-webkit-margin-end: 0)) and (not (margin-inline-end: 0)) {
    margin-right: 25px;
}

你可以换行成一个mixin跨您的应用程序更容易使用。

© www.soinside.com 2019 - 2024. All rights reserved.