【问题标题】:Next.js - Cant apply dynamic class names when using CSS ModulesNext.js - 使用 CSS 模块时无法应用动态类名
【发布时间】:2021-07-29 02:30:26
【问题描述】:

希望这里有人能帮我解决这个问题。

我正在尝试通过 NextJs 建立一个网站。我的一个页面有一些段落和按钮,它们的样式根据状态和事件而不同。在使用纯 React 以及在 NextJs 中使用全局样式表时,我可以让样式按预期工作;但是当我使用 CSS 模块时,我无法让它按预期运行。

(注意:我也可以通过使用简单的三元来让它工作 <h1 className={submitted ? styles.showresult : styles.hideresult}>Correct? {correct}</h1>; 但我还有一些其他场景需要依赖多个 if 并创建多个类,每个类都有自己的样式,所以我无法将简单的三元作为最终解决方案。

例如这是文件 pagex.js

import React from 'react';
import ReactDOM from 'react-dom';

const Pagex = () => {

const [submitted, setSubmitted] = React.useState(false); // whether the submit button was pressed

function calculateScore() {
  let correct = 0
  let incorrect = 0
    //......some scoring logic.....    
  setSubmitted(true)
  }

  // function to create a display class based on whether the submit button has been pressed
 function displayResult(){
   if (submitted === true) {
      return "showtheresult"
    } else {
         return "hidetheresult"
    }
  }

return (
  <section className="results">
      <h1 className={displayResult()}>Correct? {correct}</h1>
      <h1 className={displayResult()}>Incorrect? {incorrect}</h1>
  <button className={displayResult()} onClick={handleMovClick}>An instruction</button>
    </section>
    </div>
  );
};
export default Pagex;

globals.css 文件包含

h1.hidetheresult, h3.hidetheresult {
  visibility: hidden;
}

h1.showtheresult, h3.showtheresult {
  visibility: visible;
}

button.hidetheresult {
    border-color: pink;
  }

button.showtheresult {
    border-color: aqua;
  }

使用 CSS 模块时的变化

  1. 在正确的文件夹中添加一个名称正确的 CSS 文件 (../styles/Pagex.module.css) 包含相同的样式 以上
  2. pagex.js 中的额外导入 import styles from '../styles/Pagex.module.css'
  3. 在函数中更改引用 在 pagex.js 中
    function displayResult(){
       if (submitted === true) {
          return {styles.showtheresult}
        } else {
             return {styles.hidetheresult}
        }
      }

当我这样做时,'.'在{styles.showtheresult}{styles.hidetheresult} 中,vscode 将其突出显示为错误,并带有以下详细信息:',' 预期。 ts(1005)。 在运行开发服务器的情况下保存 js 会在尝试编译后显示类似的消息:语法错误:意外的令牌,预期的“,”,并且浏览器显示相同的消息以及 “无法编译"

还尝试通过从 displayResult() 函数中删除花括号来传递 styles.showtheresult / styles.hidetheresult。编译但在编译的网页上没有任何反应,即按下按钮时类没有更新,因此无法应用样式。

还尝试在 return 语句中传递为 ${styles.showresult} 和 ${styles.hideresult}(带 `)。这也可以编译,但页面本身给了我一个 "Unhandled Runtime Error ReferenceError: styles is not defined" 消息,我无法加载页面。

如果有人可以帮助纠正我在函数本身或代码其他地方的语法,我们将不胜感激。

【问题讨论】:

  • 您可以使用 classnames 模块,该模块是为有条件地添加多个类名的确切用例而编写的
  • 嗨@PsyGik 感谢您的反馈和指导。我一定会看一下该模块,但您能否帮助纠正我在示例中的语法以使其在不需要依赖类名模块的情况下工作?或者您是否表明这是一个限制而不是语法错误,并且解决它的方法是包含 classnames 模块?

标签: javascript css reactjs next.js css-modules


【解决方案1】:

因为你问得很好;)(开个玩笑)

所以 Next.js 是一个自以为是的框架,它使用 CSS 模块来强制组件范围样式。

基本上,您使用 name.module.css 文件名定义样式表并在其中添加常规 CSS。

.hidetheresult {
    visibility: hidden;
}

.showtheresult{
    visibility: visible;
}
  
.btn-hidetheresult {
    border-color: pink;
}

.btn-showtheresult {
    border-color: aqua;
}

现在要使用它,像任何 JS 模块一样导入它,

import styles from './styles.module.css'
console.log(styles);
// styles => {
//  hidetheresult: 'contact_hidetheresult__3LvIF',
//  showtheresult: 'contact_showtheresult__N5XLE',
//  'btn-hidetheresult': 'contact_btn-hidetheresult__3CQHv',
//  'btn-showtheresult': 'contact_btn-showtheresult__1rM1E'
//  }

如您所见,样式已转换为对象,现在您可以使用它们了 喜欢styles.hidetheresultstyles['btn-hidetheresult']

请注意样式表中缺少元素选择器。那是因为 CSS 模块重写了类名,但它们不涉及标签名。在 Next.js 中 默认行为。即它不允许元素标签选择器。

带有*.module.(css | scss | sass) 的文件扩展名是css 模块,它们只能使用类名或ID 来定位元素,而不能使用标签名。虽然这在 create-react-app 等其他框架中是可能的,但在 next-js 中是不可能的。

但您可以在 next.config.js 文件中覆盖它。 (超出此答案的范围)

有一个article 解释了如何覆盖它。 - 免责声明:我是作者


现在来到您的用例,您可以像这样进行条件样式:(假设样式与答案中给出的示例一致)

import React from "react";
import styles from "./styles.module.css";

const PageX = () => {
  const [submitted, setSubmitted] = React.useState(false);

  const getStyle = () => {
    if (submitted) return styles.showtheresult;
    else return styles.hidetheresult;
  };

  const getButtonStyle = () => {
    if (submitted) return styles["btn-showtheresult"];
    else return styles["btn-hidetheresult"];
  };

  return (
    <div>
      <section className="results">
        <h1 className={getStyle()}>Correct?</h1>
        <h1 className={getStyle()}>Incorrect?</h1>
        <button className={getButtonStyle()} onClick={handleMovClick}>
          An instruction
        </button>
      </section>
    </div>
  );
};

随着您添加更多条件,这些方法确实会变得更加复杂。这是classnames 模块派上用场。

import styles from "./styles.module.css";
import clsx from "classnames";

const PageX = () => {
  const [submitted, setSubmitted] = React.useState(false);

  const headerStyle = clsx({
    [styles.showtheresult]: submitted,
    [styles.hidetheresult]: !submitted,
  });
  const btnStyle = clsx({
    [styles["btn-showtheresult"]]: submitted,
    [styles["btn-hidetheresult"]]: !submitted,
  });
  return (
    <div>
      <section className="results">
        <h1 className={headerStyle}>Correct?</h1>
        <h1 className={headerStyle}>Incorrect?</h1>
        <button className={btnStyle} onClick={handleMovClick}>
          An instruction
        </button>
      </section>
    </div>
  );
};

这里有一个 CodeSandbox 供您使用:

【讨论】:

  • 非常感谢!我能够通过“return styles.showtheresult;”获得示例工作但无法获得“返回样式[“btn-showtheresult”];”版本工作。我确信这与我如何实现您的反馈有关,所以我很高兴接受您的解决方案,因为它解决了我的问题(同时我继续摆弄它并阅读了类名模块)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-07-27
  • 2019-03-27
  • 2021-09-10
  • 2021-11-25
  • 2019-12-01
  • 2022-01-05
  • 1970-01-01
相关资源
最近更新 更多