【问题标题】:less.css variables initialized from database从数据库初始化的less.css 变量
【发布时间】:2013-05-30 15:24:34
【问题描述】:

我正在将 dotnetless (http://www.dotlesscss.org/) 用于 asp.net 网络表单应用程序,并且效果很好。我喜欢对颜色、字体大小等使用变量。但据我所知,变量值是静态的。

有没有办法使用 dotnetless 根据用户 ID 从数据库中初始化这些变量值?

基本上我想把这个网络应用程序转换成一个基于主题的网站,所以每个用户都可以选择自己的颜色、字体、字体大小等。

任何方向都将不胜感激。

【问题讨论】:

    标签: c# css less


    【解决方案1】:

    肯定是可以的,可惜你不能从LESS本身查询你的数据库,所以你基本上需要为用户编写LESS文件,里面包含需要的变量值,然后加载。

    您可以在此处从另一个答案中找到示例:https://stackoverflow.com/a/11628325/2330244

    【讨论】:

    • 所以这意味着应该为我的变量文件实现这个 IFileReader。这个文件阅读器是否像处理程序一样,并且会无点等待我的进程。抱歉,我只是不明白它将如何适应服务器端的 dotnetless 进程。请你给我解释一下。此解决方案是否适用于每个用户。谢谢你给我这个方向。
    • 基本上每个用户都会有一个带有不同变量的自定义 .less 文件。该文件是在一个单独的进程中编写的,可能是在用户创建/编辑其主题时。有意义吗?
    • 所以这将是维护问题。我的想法更像是我们无法拦截 dotnetless 处理程序并为每个用户初始化变量,没有任何文件等。我真的很感谢你的帮助。非常感谢。
    • 是的,这是我能想到的唯一方法。如果您不想使用任何文件等,您始终可以在内联 CSS 中加载变量
    • @JesúsCarrera - 如果您愿意制作自定义功能/插件,您可以使用 .Less 做任何您想做的事情。我在我的回答中展示了如何做到这一点。
    【解决方案2】:

    我认为,如果这是您想要采用的路径,您应该创建一个 IHttpHandler 来替换无点的 LessCssHttpHandler。这个处理程序将执行与 LessCssHttpHandler 基本相同的操作,但会在编译成 css 之前将数据库变量插入到 less 中。

    您可以查看Bundle Transformer LESS 项目,该项目使用 dotless 进行的翻译较少。它还有一个 IHttpHandler ,您可以以此为基础。

    正如其他人所说,这可能不是最好的做法

    编辑: Handler的基本起点

    public class LessHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            var request = context.Request;
            var response = context.Response;
            var user = context.User;
    
            string assetUrl = request.Url.LocalPath;
            string assetPath = context.Server.MapPath(assetUrl);
    
            //load less file into the data.
            var data = "";
            using (var file = new StreamReader(assetPath))
            {
                data = file.ReadToEnd();
            }
    
            DotlessConfiguration lessEngineConfig = DotlessConfiguration.GetDefault();
            lessEngineConfig.MapPathsToWeb = false;
            lessEngineConfig.CacheEnabled = false;
            lessEngineConfig.DisableUrlRewriting = false;
            lessEngineConfig.Web = false;
            lessEngineConfig.MinifyOutput = true;
            lessEngineConfig.LessSource = typeof(VirtualFileReader);
            var lessEngineFactory = new EngineFactory(lessEngineConfig);
            ILessEngine lessEngine = lessEngineFactory.GetEngine();
    
            string vars = "";
            //TODO set default for vars
            if (user != null)
            {
                //TODO get vars for user
            }
    
            var content = lessEngine.TransformToCss(string.Format("{0}{1}", vars, data), null);
    
            // Output text content of asset
            response.ContentType = "text/css";
            response.Write(content);
            response.End();
        }
    
        public bool IsReusable
        {
            get { return true; }
        }
    }
    

    【讨论】:

    • 嗨,Shawn,感谢您的回复和捆绑转换器的链接。我认为这种方法是迄今为止最好的,但为什么你认为这不是最好的行动方案。谢谢。
    • @Shawn C. 为什么它不是最好的方法?
    • @Shawn C. 我在哪里注册 LessHandler,让它运行?
    【解决方案3】:

    为什么不创建一个具有执行所需查找功能的自定义 .LESS 插件?

    下面的代码经过测试,如图所示。我实际上并没有在数据库中查找数据,但所有必要的信息都应该可用。我验证了在网站上以 Windows 身份验证模式运行时,我能够通过HttpContext.Current.User.Identity.Name 检索当前用户。

    要使用下面的函数,你可以在你的 less 文件中输入如下内容:

    --lookup using custom function (hit db)
    @brand_color:getCustomColor(usersThemeAttribute);
    
    --then use the variable like normal
    color: @brand_color;
    

    代码

    [DisplayName("UserProfilePlugin")]
    public class UserProfilePlugin : IFunctionPlugin
    {
        public Dictionary<string, Type> GetFunctions()
        {
            return new Dictionary<string, Type> 
            {
                { "getCustomColor", typeof(GetCustomColorFunction) }
            };
        }
    }
    
    public class GetCustomColorFunction : Function
    {
        protected override Node Evaluate(Env env)
        {
            Guard.ExpectNumArguments(1, Arguments.Count(), this, Location);
            Guard.ExpectNode<Keyword>(Arguments[0], this, Arguments[0].Location);
            //the idea is that you would have many colors in a theme, this would be the name for a given color like 'bgColor', or 'foreColor'
            var colorAttrName = Arguments[0] as Keyword;
    
            //Lookup username
            // string username = HttpContext.Current.User.Identity.Name;
    
            //perform some kind of DB lookup using the username, get user theme info
            // UserProfile up = new UserProfile();
            // System.Drawing.Color c = up.GetColorByAttribute(colorAttrName.Value);
            //return the appropriate color using RGB/etc...
            // return new Color(c.R, c.G, c.B);
            return new Color(129, 129, 129);
        }
    }
    

    要注册插件,请将其添加到 web.config:

    <dotless cache="false" >
        <plugin name="UserProfilePlugin" assembly="Your.Assebly.Name" />
    </dotless>
    

    考虑为 dotless 禁用缓存,以便用户所做的更改立即生效。

    链接:https://github.com/dotless/dotless/wiki/FunctionPlugins

    【讨论】:

    • 嗨彼得,使用这种方法我可以一次初始化一个变量,但是有什么方法可以一次初始化所有变量。我确实尝试过类似 new TextNode("@lightBlue:197.460233326px;");并在较少的文件中使用如下 - myCustomColor;并按如下方式使用它-color:@lightBlue;,但它不起作用。如果它有效,它将给我带来两个优势,对于所有变量,我只需访问数据库一次,对于每个样式表,我将仅通过一个函数在顶部调用此方法,并且所有变量都将被初始化。谢谢
    • @daljit - 可能有办法做到这一点,但我不确定。但是,如果您主要关心的是多个数据库调用,那么一些简单的缓存应该可以解决问题。
    • 是的,但我也可以在每个样式表的顶部添加自定义函数,所有变量都将从那里初始化。
    • @daljit 为什么你没有将彼得的答案标记为答案?你最终得到什么解决方案?
    【解决方案4】:

    最简单的解决方案可能是在网页中内联 LESS 代码:(如 here 解释的那样)

    <html>
      <head>
        <style type="text/less">
          // DB and user-dependent code here
        </style>
      </head>
      ...
    </html>
    

    这样,您可以像自定义网页一样自定义 LESS 样式表。

    如果您想使用无点编译的 CSS,您可以将自定义样式表传递给无点解析器:

    Less.Parse(".foo { font-size: <user-dependent-value>;}")
    

    然后,您需要将编译后的 CSS 输出直接包含在您的网页中:

    <html>
      <head>
        <style type="text/css">
          // result of Less.Parse(...)
        </style>
      </head>
      ...
    </html>
    

    【讨论】:

    • 感谢瑞吉斯的回答。我会在这个周末尝试并告诉你。
    【解决方案5】:

    这取决于您将拥有多少个主题。如果您的数量有限,最好(从性能和复杂性方面)将用户映射到您预编译的 .less 主题之一。

    但是,如果您允许每个用户自定义主题以便有很多(或无限数量)主题,那么最好在主题为更改并保存结果。在每次页面加载时,您都会引用该主题文件,直到用户选择一个新主题。最好的情况是,它会在用户系统上缓存很长时间。

    除非是少量定制的 LESS/CSS,否则我会避免使用内联 CSS 路由。它将增加每个页面的文件大小/带宽,因此在移动设备上加载更慢。相反,我会使用最近的 ASP.NET Web.Optimization 包来帮助您在主题更改时构建、编译和优化 LESS -> CSS 并缓存结果。

    因此,在页面加载时,大多数页面会引用保存在数据库中的现有自定义页面主题。更改主题后,您将经历完整的 less -> css 过程。

    【讨论】:

    • 嗨,丹,感谢您的回复。我们有无限数量的用户和主题的范围,我们允许每个用户自定义主题。您的意思是将结果保存在实际文件中,或者它也可以与数据库一起使用。谢谢
    • 是的,我会缓存/保存已编译的样式表。为了快速启动和运行,您可以保存该任务直到需要它;现在使用动态样式处理。但最终,我会将缓存的样式表保存到 NoSQL 数据库或数据库中专门用于样式表的表中。 (这些将是最容易管理的),或者您可以保存到文件中。 (最容易服务,更难管理)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-10
    • 2014-04-21
    • 2021-07-08
    • 2013-06-08
    • 2011-07-09
    • 2016-05-28
    • 1970-01-01
    相关资源
    最近更新 更多