我们知道,简单的class名称容易造成css命名重复,比如你定义一个class:
<style>
.main { float: left; }
</style>
如果别人刚好也定义了一个className:.main,你的float:left就会影响到它。
所以Vue中发明了css_scoped,其原理就是在class名称后加上一个data属性选择器:
<style scoped>
.main { float: left; }
</style>
//转义后变成
<style>
.main[data-v-49729759] { float: left }
</style>
css_scoped是Vue的专用方案,如果你使用React等其它UI框架,那么你可以使用更通用的css_module,其原理是为样式名加hash字符串后缀,从而保证class名全局唯一:
<style module>
.main { float: left; }
</style>
//转义后变成
<style>
.main_3FI3s6uz { float: left; }
</style>
相比于css_scoped,css_module方案更通用,不改变其本身的权重,而且渲染性能要比前者好很多,所以更推荐大家使用css_module。
然而不管是css_scoped还是css_module,都绕不开2大缺点:
css_scoped可以使用穿透,但这样容易引发别的问题。我们来回忆一下,在css_scoped和css_module出现之前,人们是如何避免css命名冲突的?
对,就是人为的定义一些css命名空间。
那个时候,对每个Component组件都会在其根节点上定义一个不重复的ID或者class作为其命名空间,然后其内部的其它class都会以此命名空间作为前置限定,比如:
<div class="table-list">
<div class="hd"></div>
<div class="bd"></div>
<div class="ft"></div>
</div>
<style>
.table-list {
> .hd {
color: red
}
> .bd {
color: blue
}
}
</style>
这样一来,只要保证根节点的class不重复,其子节点的class就不会重复。
而对于一些全局样式,人们习惯加上一个g-作为命名空间,比如:
<style>
.g-hd {
color: red
}
</style>
这种依靠人为约定的css命名空间,虽然比较原始,但有其优点:
模块-组件名称的命名约定,基本上很容易保证其不重复。如果我们把css_module和css_命名空间结合起来,组件的命名空间由css_module自动生成,那岂不是一种更优雅的解决css冲突的方案么?
css_module中有2个特别的作用域限定符:
:global {
.test1 { color: blue; }
.test2 { color: red; }
}
//编译后
.test1 { color: blue; }
.test2 { color: red; }
:local {
.test1 { color: blue; }
.test2 { color: red; }
}
//编译后
.test1_3zyde4l1y { color: blue; }
.test2_2DHwuiHWM { color: red; }
如果我们使用css_namespace + css_module:
<div :class="styles.root">
<div class="hd"></div>
<div class="bd"></div>
<div class="ft"></div>
</div>
<style module>
:global {
:local(.root) {
> .hd {
color: red;
.title {
font-size: 18px;
}
}
> .bd { color: blue; }
}
}
</style>
//css编译后
<style>
.root_3zyde4l1y > .hd{ color: red; }
.root_3zyde4l1y > .hd .title{ font-size: 18px; }
.root_3zyde4l1y > .bd{ color: blue; }
</style>
这样的意思是:
css_module自动生成不重复的class名称,其余内部元素保持原始命名,不做任何转换。(当然某些情况下,也可以使用多个转换)> .hd这样就只会影响子级的.hd。<style>
.root_3zyde4l1y > .hd{ color: red; }
.root_3zyde4l1y > .hd .title{ font-size: 18px; }
.root_3zyde4l1y > .bd{ color: blue; }
</style>
根节点上的class命名带个hash小尾巴,仍然很不优雅。其实hash字符只是为了保证这个名称全局唯一而已,你也可以使用另外的方法来保证。如果你为工程设计一个有意义的目录结构,那么完全可以使用目录路径来替代hash字符串,比如你的工程目录如下:
src
├── components
│ ├── moduleA
│ │ ├── componentX
│ │ ├── componentY
│ ├── moduleB
│ │ ├── componentZ
那么:components-moduleA-componentX这个目录路径一定是全局唯一的,所以你可以使用这个路径来替代hash字符,css_module提供了自定义转换className的方法:
type getLocalIdent = (
context: LoaderContext,
localIdentName: string,
localName: string
) : string;
你可以通过该方法来将目录路径映射为class名称,并替换掉一些固定的目录,比如工程目录如下:
src
├── assets
│ ├── css
│ ├── global.module.scss //全局样式
│ ├── :local(.loading) {} //全局样式只需要加个g-前缀,编译成.g-loading
├── components
│ ├── NavBar
│ ├── index.module.scss
│ ├── :local(.root) {} //根据目录路径可编译成即可.comp-NavBar
│
├── modules
│ ├── user
│ ├── components
│ ├── LoginForm
│ ├── index.module.scss
│ ├── :local(.root) {} //根据目录路径可编译成.user-LoginForm,
│
注意的是src/modules/user/components/LoginForm/index.module.scss,根据目录路径可以生成:modules-user-components-LoginForm,但因为user是一个module,其名称是唯一的,且内部结构遵循约定,所以可以简化为:user-LoginForm
.g-loading - 带g-前缀,说明它是一个全局class,对应的文件一定是src/assets/css/global.module.scss.comp-NavBar - 带comp-前缀,说明它是一个公共组件,对应的组件一定是src/components/NavBar.user-LoginForm - 根据约定,对应的组件一定是src/modules/user/components/LoginForm如果你也使用类似的工程目录,那么可以直接使用我封装好了的路径映射函数getCssScopedName:
const {getCssScopedName} = require('@elux/cli-utils');
const srcPath = path.resolve(__dirname, '../src');
// webpack css-loader
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: {
getLocalIdent: (context, localIdentName, localName) => {
return getCssScopedName(srcPath, localName, context.resourcePath);
},
localIdentContext: srcPath,
},
},
};
当然你也可自己实现个性化的getLocalIdent,无非就是一些正则匹配与替换罢了...
采用css_namespace + css_module的实际案例:
或者使用任意一个elux工程模版:npm create elux@latest 或 yarn create elux
如图所示,通过class名称基本上就能推测出组件位置...
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我在MiniTest::Spec和Capybara中使用以下规范:find_field('Email').must_have_css('[autofocus]')检查名为“电子邮件”的字段是否具有autofocus属性。doc说如下:has_css?(path,options={})ChecksifagivenCSSselectorisonthepageorcurrentnode.据我了解,字段“Email”是一个节点,因此调用must_have_css绝对有效!我做错了什么? 最佳答案 通过JonasNicklas得到了答案:No
我正在学习如何在我的Ruby代码中使用Module.prepend而不是alias_method_chain,我注意到有些人使用send调用它(example):ActionView::TemplateRenderer.send(:prepend,ActionViewTemplateRendererWithCurrentTemplate)而其他人直接调用它(example):ActionView::TemplateRenderer.prepend(ActionViewTemplateRendererWithCurrentTemplate)而且,虽然我还没有看到任何人使用这种风格,但我从
当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?
我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use
我有一个div,它根据表单是否正确提交而改变。我想知道是否可以检查类的特定元素?开始元素看起来像这样。如果输入不正确,添加错误类。 最佳答案 试试这个:browser.div(:id=>"myerrortest").class_name更多信息:http://watir.github.com/watir-webdriver/doc/Watir/HTMLElement.html#class_name-instance_method另一种选择是只查看具有您期望的类的div是否存在browser.div((:id=>"myerrortes
我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty
文章目录git常用命令(简介,详细参数往下看)Git提交代码步骤gitpullgitstatusgitaddgitcommitgitpushgit代码冲突合并问题方法一:放弃本地代码方法二:合并代码常用命令以及详细参数gitadd将文件添加到仓库:gitdiff比较文件异同gitlog查看历史记录gitreset代码回滚版本库相关操作远程仓库相关操作分支相关操作创建分支查看分支:gitbranch合并分支:gitmerge删除分支:gitbranch-ddev查看分支合并图:gitlog–graph–pretty=oneline–abbrev-commit撤消某次提交git用户名密码相关配置g
使用rails4,ruby2。我在rails配置中为我的cookiesession设置了30分钟的超时时间。问题是,如果我转到表单,让session超时,然后提交表单,我会收到此ActionController::InvalidAuthenticityToken错误。如何在Rails中优雅地处理这个错误?比如说,重定向到登录屏幕? 最佳答案 在您的ApplicationController:rescue_fromActionController::InvalidAuthenticityTokendoredirect_tosome_p
Rails中有没有一种方法可以提取与路由关联的HTTP动词?例如,给定这样的路线:将“users”匹配到:“users#show”,通过:[:get,:post]我能实现这样的目标吗?users_path.respond_to?(:get)(显然#respond_to不是正确的方法)我最接近的是通过执行以下操作,但它似乎并不令人满意。Rails.application.routes.routes.named_routes["users"].constraints[:request_method]#=>/^GET$/对于上下文,我有一个设置cookie然后执行redirect_to:ba