【问题标题】:Inject data into Sass variables in Ember application在 Ember 应用程序中将数据注入到 Sass 变量中
【发布时间】:2016-07-25 20:25:03
【问题描述】:

我正在开发一个将许多单独的“站点”呈现为子目录的应用程序 - 例如/client/1/client/2 等。对于每一个,可以在应用程序的管理部分指定两个颜色值。

我想知道是否有一种方法可以将最初由 Ember 发布到后端 API 并随后从后端 API 检索到的值注入到 SCSS 文件中进行预处理?

到目前为止,我还没有找到任何解决方案。

【问题讨论】:

  • 不,这是不可能的。当您的 ember 应用开始工作并可以操作用户数据时,sass 文件已经编译为 css。所以目前没有办法改变变量。
  • @typeoneerror 我看不出这与问题和我的评论有什么关系
  • @GennadyDogaev 它展示了如何使用 javascript 在浏览器中呈现 Sass,包括在运行时更改变量。

标签: ember.js sass ember-cli


【解决方案1】:

在我们的 Ember/Rails 应用程序中,我们根据数据库中的一些设置为每个客户端生成 CSS 文件。例如,我们的Tenant 模型有两个字段:

{
    primary_color: 'ff3300',
    secondary_color: '00ff00'
}

我们公开路线

scope '/stylesheets', format: 'css' do
  get 'tenant/:tenant_id', to: 'stylesheets#tenant_css'
end

我们的控制器看起来像这样:

class StylesheetsController < ApplicationController

  layout nil

  rescue_from 'ActiveRecord::RecordNotFound' do
    render nothing: true, status: 404
  end

  def tenant_css
    # fetch model
    tenant = Tenant.find(params[:tenant_id])

    # cache the css under a unique key for tenant
    cache_key = "tenant_css_#{tenant.id}"

    # fetch the cache
    css = Rails.cache.fetch(cache_key) do
      # pass sass "params"
      render_css_for 'tenant', {
        primary_color: tenant.primary_color,
        secondary_color: tenant.secondary_color
      }
    end

    render_as_css css
  end

  protected

  # our renderer, could also add a custom one, but simple enough here
  def render_as_css(css)
    render text: css, content_type: 'text/css'
  end

  # looks for a template in views/stylesheets/_#{template}.css.erb
  def render_css_for(template, params = {})
    # load the template, parse ERB w params
    scss = render_to_string partial: template, locals: { params: params }
    load_paths = [Rails.root.join('app/assets/stylesheets')]
    # parse the rendered template via Saas
    Sass::Engine.new(scss, syntax: :scss, load_paths: load_paths).render
  end

end

这样,您可以链接到/stylesheets/tenant/1.css,它将使用 Sass 引擎为租户呈现 CSS。

在这种情况下,在views/stylesheets/_tenant.css.erb 中,你会有这样的东西(它是一个ERB 文件,但你现在可以在其中使用Sass):

@import "bootstrap-buttons";

<% if params[:primary_color].present? %>
  $primary-color: <%= params[:primary_color] %>;
  h1, h2, h3, h4, h5, h6 {
    color: $primary-color;
  }
<% end %>

<% if params[:secondary_color].present? %>
  $secondary-color: <%= params[:secondary_color] %>;
  a {
    color: $secondary-color;
    &:hover {
      color: darken($secondary-color, 10%);
    }
  }
<% end %>

您会注意到,我现在可以使用 @import 为 Sass 引擎导入样式表路径中的任何内容(在这种情况下,我可以利用 Bootstrap Sass 库中的一些帮助程序)。

当支持 CSS 的模型更新时,您需要某种缓存清理器来擦除缓存:

class Tenant < ActiveRecord::Base
  after_update do
    Rails.cache.delete("tenant_css_#{id}")
  end
end

简而言之,这就是 Rails 方面。

在 Ember 中,我的猜测是您会希望根据 ID 加载样式表,这样样式表就不能被硬编码到“index.html”中。 Ember CSS Routes 插件可能会很好地为您服务,但我发现它只是将 &lt;link&gt; 附加到标题中,因此如果您需要随时交换 CSS 样式表,这将不起作用。我通过这样的路线解决了这个问题:

afterModel(model, transition) {
  // dynamically form the URL here
  const url = "/stylesheets/tenant/1";

  // build link object
  const $link = $('<link>', { rel: 'stylesheet', href: url, id: 'tenant-styles' });

  // resolve the promise once the stylesheet loads
  const promise = new RSVP.Promise((resolve, reject) => {
    $link.on('load', () => {
      $link.appendTo('head');
      resolve();
    }).on('error', () => {
      // resolve anyway, no stylesheet in this case
      resolve();
    });
  });

  return promise;
},

// remove the link when exiting
resetController(controller, isExiting, transition) {
  this._super(...arguments);
  if (isExiting) {
    $('#tenant-styles').remove();
  }
}

您也可以在&lt;head&gt; 中添加一个空白元素,然后使用Ember Wormhole 格式化&lt;link&gt; 标签并渲染到“虫洞”中。

编辑

您也可以查看rendering Sass directly in the client application。对于像两种颜色这样简单的东西,这不会对性能产生太大影响,尤其是如果您使用服务工作者或类似的东西来缓存结果。

【讨论】:

    猜你喜欢
    • 2018-05-03
    • 2017-03-31
    • 1970-01-01
    • 2014-11-10
    • 2018-03-14
    • 2018-01-24
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多