覆盖通过 JavaScript 文件加载的 SCSS 文件变量的可行方法是啥?

Posted

技术标签:

【中文标题】覆盖通过 JavaScript 文件加载的 SCSS 文件变量的可行方法是啥?【英文标题】:What are feasible ways of overwriting variables of SCSS files which are loaded through JavaScript files?覆盖通过 JavaScript 文件加载的 SCSS 文件变量的可行方法是什么? 【发布时间】:2017-06-18 17:34:12 【问题描述】:

假设我有一个组件,其中包含一个用于行为的 javascript 文件、一个 html 模板文件和一个用于外观的 SCSS 文件。

我们使用 Webpack 在应用的主 JavaScript 中加载组件的 JavaScript(例如通过require('./path/to/the-component.js'))。我们使用组件的 JavaScript 来加载它的 SCSS 文件(通过require('./the-component.scss'))。

组件的 SCSS 文件包含一个具有默认值的变量(例如,最小高度:$min-height: 400px)。

如果我在组件的所有用法中都不喜欢 400px:如何覆盖这样的变量(例如在应用程序的 SCSS 文件中*)以将 $min-height 调整为 500px 当然,由于违反关注点分离原则并不是一个好主意,因此组件不应该对其周围目录的组织方式做出任何假设。

到目前为止,我还没有找到解决此问题的方法。但我敢肯定有人这样做。

*) 以及我应该如何(在哪里)加载这样的文件(通常,我通过 app.js 加载 app.scss)

【问题讨论】:

我很好奇你为什么对 scss 文件使用 require 而不是使用 compass 编译它们。 为了简单起见,我们在 Web 项目中总是使用sass-loader (+node-sass)。不需要指南针。 (+ 我们希望随时灵活地用 LESS 替换 SASS) 因为您在 RAM 中拥有 css/scss 文件的字符串,因为这就是 require 使用它的方式,您可以在其上使用字符串 replace() 并重新输入它。您将不得不挖掘以弄清楚如何访问所需的缓存,但它肯定是可行的。 疯狂的想法,我喜欢。但是,对于一个可以接受的答案,它有点太老套了,因为我实际上是在寻求一个“最佳实践”的解决方案,而不仅仅是一个肮脏的快速修复。 是的,我不认为有一个简单的内置方式,在看到其他想法之后,我认为它看起来不错/简单/可实现。 fwiw,我们已经为语言字符串做了类似的事情,发现没有更简单的方法可以集成到现有的交付系统中...... 【参考方案1】:

mixin 能帮到你吗? 比如说

@mixin set-min-height($min-height) 
  min-height: $min-height;

以及您想要在组件中设置高度或您刚刚调用的任何属性的任何位置

.app__view  @include set-min-height(400px); 

.component__view  @include set-min-height(500px); 

我相信这种方法比覆盖变量要好,因为无论如何你都要为你的组件特定规则设置一个属性。

【讨论】:

mixin 无法通过require/import 语句加载the-component.js。因此它在组件的 SCSS 文件中是未定义的。 + 组件不能依赖它的存在。 我建议在应用程序级别声明 mixin,以便应用程序的任何组件都可以继承它。但是为什么不希望组件依赖它的存在呢? 该组件是 100%(应用程序)独立的,因此它可以在任何地方使用。不需要mixin,它是可选的。因此组件不能依赖它。 :D 我认为这是一个非常有趣的观点。我低估了这个问题。【参考方案2】:

我认为仅仅因为组件的所有实例最终将具有相同的样式(除非您使用多个类,如Tyler Biscoe 建议),因此不可能通过 scss 实现您想要的。最后,您将拥有一个组件的静态 css 文件,并且所有实例都将共享它。

考虑重构您的 scss 以从 scss 中取出 $min-height,使其成为组件的参数并使用内联样式来应用它。对于 React,它看起来像这样:

import './MyComponent.scss';

class MyComponent extends Component 
  render() 
    return (
      const divStyle = 
        minHeight: this.props.minHeight
      
      <div style=divStyle></div>
    );
  

然后你可以添加任意宽度的组件:

class App extends Component 
  render() 
    return (
      <MyComponent minHeight="300px"/>
      <MyComponent minHeight="400px"/>
      <MyComponent minHeight="500px"/>
    );
  

这样你就可以从 MyComponent 中提升 min-height 参数并让更高的组件指定它。

更新:

我想你可以从 mycomponent.scss 中取出 $min-height 并将其设置在父级中。假设您必须为 .my-component css 类设置 $min-height,在父级的 scss 文件中您可以执行以下操作:

.large-component > .my-component 
  min-height: $large-min-height;


.small-component > .my-component 
  min-height: $small-min-height;

但同样,这不允许您将参数传递给组件,只能根据组件的父容器设置样式。

【讨论】:

感谢您的意见。我认为它是权宜之计,因为它似乎破坏了结构 (HTML)、行为 (JavaScript) 和外观 (CSS) 的清晰分离,我可以通过为这些问题编写三个不同的文件来实现,每个文件 100% 都准确地解决了一个问题的顾虑。 "我认为通过scss不可能实现你想要的,因为组件的所有实例最终都会有相同的样式"结构中的上下文(包装DOM元素的CSS类= 包装组件实例的 DOM 元素)可以决定要覆盖哪些组件实例的样式以及保留哪些组件实例的样式。 我同意这违反了关注点分离。这可能不是一件坏事。如果你的组件足够纤细,那么将所有组件的样式、结构和逻辑放在同一个地方,对于可测试性、可读性和易于理解你的应用程序来说是一个巨大的好处。这也使您的组件更具可重用性。简而言之,我真的鼓励您考虑使用许多孤立的组件来构建您的应用程序。 React 是这种方法的一个很好的例子。 只要您拥有有限且预定义数量的组件实例,就是这样。当您挑选出一个组件实例时,显式 ID 和 .parent &gt; .wrapper &gt; .component 之类的内容本质上是相同的。 顺便说一句,这是关于将参数传递给 webpack 要求的讨论:github.com/jtangelder/sass-loader/issues/49【参考方案3】:

我的想法是添加第二个最小高度变量。例如$min-height-2,并为其分配不同的值。然后将其应用于不同的类名,您可以选择性地将其分配给您希望具有不同最小高度的元素。

$min-height: 400px;
$min-height-2: 500px;

.some-element 
  min-height: $min-height;

  &.larger-element 
    min-height: $min-height-2;
  


HTML:

<div class="some-element"> This element has min-height 400px</div>
<div class="some-element larger-element">This element has min-height 500px</div>

【讨论】:

很有趣的方法,但是它违反了关注点分离的原则,因为它做了太多的假设。考虑我们需要在三个完全不同的项目中使用该组件,该组件出现 30 次,$min-height 有 10 个不同的值。这意味着我需要 9 个额外的 CSS 类。可维护性的噩梦。组件应该完全独立于它的用途,并且默认高度应该可以忽略不计(在大多数情况下会被覆盖)。 有人可能会说您已经通过使用 javascript 编辑样式违反了关注点分离。你最好的选择是做我上面概述的事情。这只是一种“它是如何完成的”。话虽如此,您也可以直接使用 javascript 编辑 css: someElement.style.minHeight = '500px !important';但是我不推荐这种方法。 样式不是使用 JavaScript 编辑的。它只是通过组件的主文件的加载过程,它(当然)是一个 JavaScript 文件。样式由 SCSS 文件编辑,该文件位于使用该组件的某个应用程序中的某个位置。关注点分离(重要的“关注点分离”)是组件代码(JS、HTML、CSS)的要求。因为组件的代码不应受到其用法更改的影响。 明白了。在我看来,解决方案可能是为组件设置一组基本样式,这些样式全部存储在您布置的结构中,然后可能允许项目包含他们自己的 scss 文件,如果需要,该文件将进一步修改组件所以。那有意义吗?这与人们如何对 bootstrap 或 google 的 material-lite 框架等框架进行小幅修改的概念类似。 这是我的计划。但是如果我在项目自己的 SCSS 文件中定义变量,我怎样才能让它们覆盖我组件的变量?如果我决定修改 Bootstrap,我可以使用 @import 语句(据我所知)使我能够更改其他文件中的变量。但是使用 Webpack,@import 语句被替换为 require 语句,这似乎是变量的障碍。

以上是关于覆盖通过 JavaScript 文件加载的 SCSS 文件变量的可行方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何覆盖Prototype.js类中声明的javascript函数

javascript和jquery覆盖

JavaScript 加载时JQueryMobile覆盖

注入的 Javascript 不会覆盖 UiWebView 中的 URL

javascript [loading overlay jquery]显示加载覆盖/封面#jquery

网站未完成加载时loading覆盖全网页的实现