scoped的原理
vue中的scoped 通过在DOM结构以及css样式上加唯一不重复的标记:data-v-hash的方式,以保证唯一(而这个工作是由过PostCSS转译实现的),达到样式私有化模块化的目的。
总结一下scoped三条渲染规则:
- 给HTML的DOM节点加一个不重复data属性(形如:data-v-123)来表示他的唯一性
- 在每句css选择器的末尾(编译后的生成的css语句)加一个当前组件的data属性选择器(如[data-v-123])来私有化样式
- 如果组件内部包含有其他组件,只会给其他组件的最外层标签加上当前组件的data属性
deep主要使用场景
主要是第三方的组件库如vant element 等
PostCSS会给一个组件中的所有dom添加了一个独一无二的动态属性data-v-xxxx,然后,给CSS选择器额外添加一个对应的属性选择器来选择该组件中dom,这种做法使得样式只作用于含有该属性的dom——组件内部dom, 从而达到了'样式模块化'的效果.
案例修改Element ui Input样式
发现没有生效
如果不写Scoped 就没问题
原因就是Scoped 搞的鬼 他在进行PostCss转化的时候把元素选择器默认放在了最后
Vue 提供了样式穿透:deep() 他的作用就是用来改变 属性选择器的位置
插槽选择器
<template><div><A><div class="a">私人定制div</div></A></div>
</template><script setup>
import A from "@/components/A.vue"
</script><style scoped>
//最新版的vue已支持这个class的写法
.a {
color:red
}:slotted(.a) {color:red
}
</style>
全局选择器
在之前我们想加入全局 样式 通常都是新建一个style 标签 不加scoped 现在有更优雅的解决方案
<style>div{color:red}
</style><style lang="less" scoped></style>
<style lang="less" scoped>
:global(div){color:red
}
:global(.cus){color:red
}
</style>
动态 CSS
单文件组件的 <style>
标签可以通过 v-bind
这一 CSS 函数将 CSS 的值关联到动态的组件状态上:
color:v-bind(red)
<template><div class="div">text</div>
</template><script lang="ts" setup>
import { ref } from 'vue'
const red = ref<string>('red')
</script><style lang="less" scoped>
.div{color:v-bind(red)
}</style>
如果是对象 v-bind 请加引号 color: v-bind('red.color');
<template><div class="div">text</div>
</template><script lang="ts" setup>
import { ref } from "vue"
const red = ref({color:'pink'
})
</script><style lang="less" scoped>
.div {color: v-bind('red.color');
}
</style>
css module
<style module>
标签会被编译为 CSS Modules 并且将生成的 CSS 类作为 $style
对象的键暴露给组件
<template><div :class="$style.red">text</div>
</template><style module>
.red {color: red;font-size: 20px;
}
</style>
自定义注入名称(多个可以用数组)
你可以通过给 module
attribute 一个值来自定义注入的类对象的 property 键
<template><div :class="[ck.red,ck.border]">text</div>
</template><style module="ck">
.red {color: red;font-size: 20px;
}
.border{border: 1px solid #ccc;
}
</style>
与组合式 API 一同使用
注入的类可以通过 useCssModule API 在 setup() 和 <script setup> 中使用。对于使用了自定义注入名称的 <style module> 模块,useCssModule 接收一个对应的 module attribute 值作为第一个参数
<template><div :class="[ck.red,ck.border]">text</div>
</template><script setup lang="ts">
import { useCssModule } from 'vue'
const css = useCssModule('ck')
</script><style module="ck">
.red {color: red;font-size: 20px;
}
.border{border: 1px solid #ccc;
}
</style>
在tsx使用css moudle
css moudle使用场景一般用于TSX 和 render 函数 居多
test.tsx
内联样式不能和className一起使用
import { defineComponent } from "vue";
import styles from "./styles.css";
export default defineComponent({setup() {return () => (/* <div style={{ color: "blue", fontSize: "16px" }}>tsx -内联样式</div> */<div className={styles.container}>tsx -CSS Modules</div>);},
});
styles.module.css
/* styles.module.css */
container { padding: 20px; border: 1px solid #ccc; }
.title { font-size: 2em; color: #333; }