当前位置: 首页 > news >正文

Vue style中的 scoped 属性

 Vue 中存在 scoped 属性,HTML5中也存在一个 scoped 属性,而且,这两者都是针对 css 样式处理的属性,所以很多文章在 解释 Vue scoped 的时候,都会把两者混为一谈,直接进把 HTML5 scoped 的定义搬到 Vue scoped 上,其实这是不对的,这两个不是一个东西。

HTML5  scoped 

在 W3C 和 MDN 文档上是这么说的:

该属性已被移除,不建议使用。

该属性是一个布尔属性。如果使用该属性,则样式仅仅应用到 style 元素的父元素及其子元素。

第一句话就是,不建议使用这玩意。Vue 这么大受众的框架,肯定不会不考虑到这一点。

 再就是这玩意只有火狐支持,更不符合项目初衷。

使用方法 和 Vue scoped 一致,直接写在 style 标签内部

<div><style type="text/css" scoped>h1 {color: red;}p {color: blue;}</style><h1>这个标题是红色的</h1><p>这个段落是蓝色的。</p></div>

展示效果

控制台DMO结构

 

可以看到,在 DMO 结构中 ,只是把我编写的代码原封不动的渲染了,并没有做任何处理,这就是和 Vue scoped 的最大区别 

后面再讲到 Vue scoped 原理的时候会做个对比,更容易看出区别在哪。

Vue 组件的样式覆盖

Vue 项目中,每个组件内都会存在一个 <style></style> ,用来编写组件样式,如果组件过多,那么在开发过程中难免会出现,类名相同的情况。一旦类名相同,那么在编译的时候,就可能出现问题。

例如 :组件 Student 存在一个 demo 的class,组件 School 也同时存在 demo 的class ,虽然说这两个 class 代表的样式在各自组件中是不一样的,但是,展示的效果却不是我们想要的。

// Student 组件
<template><div><p class="demo">Student组件</p></div>
</template><style>.demo {background:orange}
</style>// School 组件
<template><div><p class="demo">School组件</p></div>
</template><style>.demo {background:red}
</style>// App 组件使用
<template><div id="app"><School /><Student /></div>
</template>

如果按照我们设想的,School 组件展示 红色 ,Student 组件展示橙色,但是实际效果是

两个组件都展示的 橙色,Student 组件的样式覆盖了School 组件的样式。这是因为我们在引入组件的时候,Student 组件是后引入的。如果我们先引入 Student 组件,那展示效果又不一样了。

这是因为在webpack 编译的时候,所有组件内的 style 都会合并,相同类名的样式自然就会放到一起,根据css规则,后面的样式自然会覆盖前面的样式。

我把这个空项目打包一下看看这两个组件的style合并之后长啥样。

可以看到当前只存在一个 .demo 的类名,但是这个类名中存在两个 background 属性,按照顺序也就是 Student 组件的样式 和 School 组件的样式。  

为了避免这个问题, Vue 使用了 scoped 属性,来作为样式隔离。

 Vue scoped 样式隔离

先说使用方法,只需要在组件中的 <style></style> 标签中加入 scoped 属性即可,Vue 会自动处理样式,就像下面这样。

<style scoped>.demo {background:red}
</style>

 我在 School 组件 和 Student 组件 中都加上这个属性,然后再来看看页面展示效果

 打包看下编译后的 css 文件长啥样。

.demo[data-v-2578f57b]{background:orange}
.demo[data-v-5c5da36a]{background:red}

存在两个 demo 类名,但是两个 demo 类名上都新增了一个 [data-v-xxxx] 的属性,这个就是Vue 底层根据我们的 scopde 属性,针对这些样式做了处理,导致在编译的时候,这些样式不被认为是同名样式,所以不会导致样式覆盖。

再来看看控制台上的 DOM节点和样式

 

 可以看到控制台上的样式,和 打包之后的样式是一致的,但是在 DOM 节点上,我们可以发现,两个组件的根元素和子元素上,都添加了一个 data-v-xxxx 属性,而且还是相同的。

这是因为 Vue有一个 自带的插件 Vue-loader,通过这个插件,就可以实现这些转化,而且不用引入别的第三方包。( Vue-loader 使用的是 Post-CSS 来实现这些转换,在深入的源码研究就暂时不说了,我也还没看到那里去。。。 )

Scoped CSS 和 CSS Modules

 一个是在编译之后,给类名上加上属性选择器的同时,还需要给 DOM 节点增加自定义属性用来隔离样式 --  Scoped CSS

一个是在编译之后,直接在 DOM 节点上给类名增加一个hash后缀,不会在节点上增加自定义属性用来隔离样式,且DOM节点与样式文件展示类名一致  --  CSS Modules。

 这样一对比,发现 CSS Modules 是更好用一点哈。所以在  Vue Loader v15 及以上版本 增加了

  CSS Modules 功能,但是需要手动开启该功能

CSS Modules 必须通过向 css-loader 传入 modules: true 来开启

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

 然后在你的 <style> 上添加 module 特性,就和添加 scoped 属性一样

<style module>
.red {color: red;
}
.bold {font-weight: bold;
}
</style>

总结

 Vue scoped 作用

  • 给当前组件的所有标签添加一个不重复的data属性(形如:data-v-40b76154)来表示唯一性

  • 为了避免影响全局样式,给每句CSS选择器末尾(编译后生成的CSS语句)加一个当前组件的data-v-hash属性选择器来私有化样式

  • 为了避免影响子组件的样式,只会给子组件的最外层标签上添加当前组件的data-v-hash属性

 CSS Modules 模块化应用越来越好,也越来越广泛,我觉得还是 CSS Modules 比较好,至少看起来比较清爽一点,不会在节点上增加很多自定义属性

http://www.lryc.cn/news/96935.html

相关文章:

  • 移动端适配rem
  • Go语言开发小技巧易错点100例(八)
  • 100个网络安全测试面试题
  • 7.26 作业 QT
  • Python - Opencv应用实例之树叶自动分割、标签及统计分析系统
  • IC设计工程师,参加IC面试应该注意哪些细节?
  • java poi导入Excel、导出excel
  • 【算法与数据结构】101、LeetCode对称二叉树
  • 【N32L40X】学习笔记04-gpio中断库
  • Godot 4 着色器 - Shader调试
  • liunx时间慢几分钟,定时更新系统时间
  • C# 委托详解
  • chatGPT 学习分享:内含PPT分享下载
  • 使用CRM进行数据分析的四大好处
  • Excel“牛人”变现方案参考
  • vscode和jetbrains IDEA添加免费的gpt代码生成插件
  • 【C#】医学实验室云LIS检验信息系统源码 采用B/S架构
  • linux:AWS LightSail 设置虚拟内存
  • “华为杯”研究生数学建模竞赛2016年-【华为杯】E题:粮食最低收购价问题研究
  • idea项目依赖全部找不到
  • 自动驾驶数据标注有哪些?
  • ChatGPT:人工智能语言模型的巅峰之作
  • 【unity之IMGUI实践】敌方逻辑封装实现【六】
  • llvm向用户抛出warning、error信息
  • 微服务学习笔记-----Nacos安装教程(Windows和Linux版本)
  • 程序员面试系列,docker常见面试题
  • Linux centos7.x系统将/home磁盘分配给/
  • 根据数组元素为对象,对元素对象的某一属性进行排序
  • mysql(三)用户权限管理
  • 字节JAVA岗位面试总结汇总