1. Vue中scoped属性的渲染规则:

  1. 给DOM节点添加一个不重复的data属性(比如data-v-7ba5bd90)来表示他的唯一性
  2. 在每个CSS选择器末尾(编译后生成的CSS)加一个当前组件的data属性选择器(如[data-v-7ba5bd90])来私有化样式。选择器末尾的data属性和其对应的DOM中的data属性相匹配
  3. 子组件最外层标签上有一个类已经在这个父组件中定义过了,那么这个父组件的样式就也会应用到子组件上。只不过其权重没有子组件同类名的重。
  4. 如果组件内部包含有其他组件,只会给其他组件的最外层标签加上当前组件的data属性
  5. 如果父组件想要改变子组件中某个标签样式可以使用>>>连接符或者/deep/来解决
<!-- Button.vue -->
   <template> 
     <button class="btn"> 
        <span> <slot></slot> </span>
     </button>
   </template>
    <style scoped> 
        .btn { color: red; }
     </style>
<!-- App.vue -->
<template>
	<div id="app">
		<Button class="btn-lg">click</Button> </div>
</template>
<script>
	import Button from "./components/Button";
	export default {
		name: "App",
		components: {
			Button
		}
	};
</script>
<style scoped>
	.btn>>> span {
		color: green;
		font-weight: bold;
		border: 1px solid green;
		padding: 10px;
	}
</style>
  1. 子组件(‘button class=“btn”’) v-html中内在的标签样式不生效,原理以及解决方案同4、5

其实上述中父组件想要修改子组件的样式,在开发中其实是经常遇到的,就我个人开发项目过程中就会遇到在使用element-ui时,对element-ui封装的组件样式并不是很满意,想要修改,我用到的是个比较笨的方法,

<style lang="scss" type="text/scss" rel="stylesheet/scss" scoped>
	//这里可以写该父组件的样式,以及子组件最外层元素样式
</style>
<style lang="scss" type="text/scss" rel="stylesheet/scss">
	//这里可以写子组件中的样式,但是一定要父组件的唯一标识,表明这个样式只是在特定父组件下的这个组件内部的样式才有变化
	#父组件id{
		.子组件样式{
			.子组件标题样式
		}
	}
</style>

但是不论上面的使用>>>连接符或者/deep/来解决,还是我的笨方法其实都破坏了已封装好的组件中的样式,但这也失去了组件封装的效果。再次回到以前CSS中令人头痛的问题:CSS作用域。

2. Vue中使用CSS Modules:

这里只是简单说一下,因为还没有使用过CSS Modules接触scope较多,再者个人觉得CSS Modules的使用太过繁琐,而且scope就够解决Css样式管理了,以上只是个人的一点见解,如果下面有不对的地方请多指教!
1. 基本使用方式

在style标签中添加module属性,表示打开CSS-loader的模块模式

<style module> 
	.btn {
		 color: red;
	 }
</style>

在模板中使用动态类绑定:class,并在类名前面加上’$style.’

<template> <button :class="$style.btn">{{msg}}</button> </template>

效果如下所示::class="$style.btn"会被编译成为.Button_btn_3ykLd这个类名,并且样式的选择器也自动发生了相应的变化。
在这里插入图片描述
需要注意的点:

  • 如果类名包含中划线,或者类名是驼峰式命名,则使用中括号语法
	<h4 :class="$style['header-tit']">类别推荐</h4>
  • 也可以使用数组或对象语法
	<p :class="{ [$style.red]: isRed }">
      Am I red?
    </p>
    <p :class="[$style.red, $style.bold]">
      Red and bold
    </p>
  • 更复杂的对象语法
	<ul 
    :class="{
        [$style.panelBox]:true,
        [$style.transitionByPanelBox]:needTransition
      }">
    </ul>

相当不好用啊,scss不能用,二层嵌套样式也不能选择生效,

<template>
	<div class="warp">
		<div :class="$style['aa']">
			123
			<div :class="$style['bb']">
				ffff
			</div>
		</div>
		<div :class="$style['bb']">
			ddddddd
		</div>
	</div>
	
</template>

<script>
</script>
//错误示例
<style module  lang="scss">
	.aa{
		background-color: #00B43C;
		.bb{
			border: 1px solid #66512C;
		}
	}
	/*.aa*/ 
</style>
正确示例:
<style module>
	.aa{
		background-color: #00B43C;
	}
	.aa .bb{
		border: 1px solid #66512C;
	}
</style>

2.子组件调用父组件样式

<!-- Button.vue -->
<template> <button :class="[$style.btn, primaryClass]">{{msg}}</button> </template>
<script>
	export default {
		name: 'Button',
		props: {
			msg: String,
			primaryClass: ''
		}
	}
</script>
<style module>
	.btn {
		border: 1px solid #ccc;
		border-radius: 3px;
		padding: 5px 15px;
		background: #fefefe;
		margin: 5px;
	}
</style>
<!-- App.vue -->
<template>
	<div id="app">
		<Button msg="Default Button" />
		<Button :class="{[$style['btn-lg']]: isLg}" msg="Larger Button" />
		<Button :class="{[$style['btn-sm']]: isSm}" msg="Smaller Button" />
		<Button msg="Primary Button" :primaryClass="$style['btn-primary']" /> </div>
</template>
<script>
	import Button from './components/Button'
	export default {
		name: 'app',
		components: {
			Button
		},
		data() {
			return {
				isLg: true,
				isSm: false
			}
		}
	}
</script>
<style module>
	.btn-lg {
		padding: 15px 30px;
	}
	
	.btn-sm {
		padding: 5px;
	}
	
	.btn-primary {
		background: rgb(54, 152, 244);
		border-color: rgb(32, 108, 221);
		color: #fff;
	}
</style>

效果图如下所示:
在这里插入图片描述
(虽然上面的方法可以实现子组件调用父组件的样式,但是我还是想吐槽,子组件的样式不就应该写在子组件的样式里吗?这样写不是扰乱了组件样式封装的原本意图了吗?r如果真的想要修改子组件的样式,就像上诉遇到的vue项目中element-ui封装的组件样式并不是很满意,想要修改也不能往element-ui封装的组件里传入一个props来修改样式吧???)
3.配置
官方配置:

// webpack.config.js
{
  module: {
    rules: [
      // ... 其它规则省略
      {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          {
            loader: 'css-loader',
            options: {
              // 开启 CSS Modules
              modules: true,
              // 自定义生成的类名
              localIdentName: '[local]_[hash:base64:8]'
            }
          }
        ]
      }
    ]
  }
}

还有一种方式:在vue.config.js中添加如下配置

css: {
 loaderOptions: {
  css: {
  localIdentName: '[name]__[local]-[hash:base64:5]',
  camelCase: true
  }
 }
 }
//localIdentName是格式化类名:name是当前文件名称,local是当前定义的类名名,hash是hash生成的字符串,长度为5
//camelCase:在类名有中横线时,'only'在标签上绑定类名时只支持大驼峰,true:支持大驼峰也支持中括号命名

反正两种方式我都没有成功,求大神指教!出来的样式都是这样
在这里插入图片描述

总结:

就目前情况可能更适合用scope来实现css样式的局域化管理。通过项目功能的越来越多,由于前期没有一个很好的css样式规划管理,经常删除没用组件页面时需要调整整个项目样式,这就是因为css样式没有局域化的后果。维护起来找不到导致现在标签样式变化的CSS文件等等,综上以下是开发时要注意的点。

  1. css一定要有标识:方便样式修改查找。

在这里插入图片描述在这里插入图片描述
2. 使用scope区域化Css样式
3. 想要修改子组件封装好的样式,一定要在外层写清楚哪个父组件下的子组件的样式,以免修改全局的样式

<style lang="scss" type="text/scss" rel="stylesheet/scss" scoped>
   //这里可以写该父组件的样式,以及子组件最外层元素样式
</style>
<style lang="scss" type="text/scss" rel="stylesheet/scss">
   //这里可以写子组件中的样式,但是一定要父组件的唯一标识,表明这个样式只是在特定父组件下的这个组件内部的样式才有变化
   #父组件id{
   	.子组件样式{
   		.子组件标题样式
   	}
   }
</style>
Logo

前往低代码交流专区

更多推荐