为什么不建议在 Vue <style> 中使用 scoped?

前言

亲爱的小伙伴,你好!我是 嘟老板。我们使用 Vue 开发页面时,经常需要在 <style> 标签下编写样式。不知你是否留意,在 <style> 标签下有一个属性经常出现 - scoped。你知道它起到什么作用吗?原理是怎样的?有没有什么弊端呢?今天我们就来聊聊它。

1. 什么是 scoped

scoped 顾名思义,与作用域有关,因为是设计组件样式的,所以可以叫他 css 作用域样式作用域。当 <style> 标签带有 scoped 属性时,<style> 内的样式只会影响当前组件内的元素。如果你对 WebComponent 有了解的话,会发现 scoped 的作用域 Shadow DOM 比较类似。

我们先来看一段代码:

<template><div class="home">parent</div>
</template>
<script setup></script>
<style lang="scss" scoped>
.home {width: 200px;height: 200px;background-color: lightblue;
}
</style>

这是一个很简陋的 Vue 组件, 只需要在 <style> 便签上添加 scoped 属性,就能达到 限制样式作用域 的目的。

2. scoped 的作用是什么?

2.1 限制样式作用域

保证 <style> 标签内的样式仅在当前组件生效,而不会影响其他组件的样式,包括子组件。

我们来强化一下上面的代码:

<!-- Home.vue -->
<template><div class="home">parent<Child /></div>
</template>
<script setup>
import Child from './components/Child.vue'
</script>
<style lang="scss" scoped>
.home {width: 200px;height: 200px;background-color: lightblue;
}
</style>

新增一个 Child.vue 组件,有两个 div 元素,其中根节点添加 child 样式类,内部节点添加 child-inner 样式类:

<template><div class="child">child<div class="child-inner">child-inner</div></div>
</template><script setup lang="ts"></script><style lang="scss" scoped>
.child {width: 100px;height: 100px;background-color: lightcoral;.child-inner {width: 50px;height: 50px;background-color: lightpink;}
}
</style>

运行效果如下:

image.png

然后我们在 Home.vue 中设置 Child.vue 组件的 child-inner 样式类,将文字颜色设为红色:

<!-- Home.vue -->
<style lang="scss" scoped>
.home {width: 200px;height: 200px;background-color: lightblue;.child-inner {color: red;}
}
</style>

然而样式没有变化,说明 Home.vue 的样式没有渗透到 Child.vue 组件内部样式

2.2 控制子组件根节点样式

使用了 scope 的样式虽然无法影响子组件的内部样式,但是可以影响子组件的根节点。也就是说子组件的根节点同时受 父组件的作用域样式子组件的作用域样式 影响。

为什么要这样设计呢?

父组件可能存在需要控制子组件布局的情况。比如,列表数据也可能需要以栅格布局展示,这就需要通过按钮触发切换不同的布局效果。

假设子组件用于列表展示,父组件提供按钮入口,允许父组件作用域控制子组件的布局,那么切换列表的展示形式就轻而易举了。

我们继续调整下 Home.vue 的样式,将 child 改为 flex 布局,内容居中:

<style lang="scss" scoped>
.home {width: 200px;height: 200px;background-color: lightblue;.child {display: flex;justify-content: center;align-items: center;}
}
</style>

运行效果如下:

image.png

3. scoped 原理是什么?

scoped 的原理主要是 通过为当前组件的模板添加一个独一无二的属性,然后在 CSS 选择器中添加这个属性,从而实现样式的局部作用域

它的实现可以分为几个步骤:

  1. 当 Vue 编译器编译一个包含 scoped<style> 标签时,会为每个 CSS 规则添加一个独特的属性,比如 data-v-4533200f。这个属性是自动生成的,确保了在整个应用中的唯一性。

image.png

  1. 编译器将模板中的每一个 HTML 标签都添加上相同的属性。这样,当浏览器解析和应用 CSS 样式时,只有带有这个属性的元素才会被这些规则影响,实现了样式的局部作用域。

image.png

  1. 对于子组件,它们的根元素也会被添加上父组件的属性,所以父组件的 scoped 样式可以影响到子组件的根节点。然而,这个属性不会被添加到子组件的内部元素,所以父组件的样式不会影响到子组件的内部样式。

image.png

这种实现方法主要利用了 **CSS 选择器的属性选择器和浏览器的样式解析机制。

4. 为什么我不建议使用 scoped

4.1. 样式优先级问题

由于 scoped 通过添加唯一的属性来工作,这会增加选择器的特异性,可能导致由于特异性不同而出现样式优先级问题。

例如父组件 Home.vue 中有一个 warning 类,表示警告信息。子组件 Child.vue 同样有包含 warning 类的警告信息,想要通过在父组件中设置 warning 类的样式,统一控制父子组件的警告样式。

    <!-- Home.vue --><template><div class="home"><div class="warning">parent</div><Child /></div></template><script setup>import Child from './components/Child.vue'</script><style lang="scss" scoped>.home {width: 200px;height: 200px;background-color: lightblue;.warning {background-color: lightsalmon;}}</style>
    <!-- Child.vue --><template><div class="child"><div class="warning">child</div><div class="child-inner">child-inner</div></div></template><script setup lang="ts"></script><style lang="scss" scoped>.child {width: 100px;height: 100px;background-color: lightcoral;.child-inner {width: 50px;height: 50px;background-color: lightpink;}}</style>

运行后会发现,Child.vue 样式应没有生效,为什么呢?

因为父组件的 warning 拼接了该元素上特有的属性,无法作用到子组件的 dom 节点。

4.2. 无法跨组件边界工作

这其实是对上一个问题的延伸,scoped 无法控制其他组件的样式,包括子组件。这在构建大型应用程序时可能会限制你的样式选项。

当然啦,针对这种场景,vue 也为我们提供了解决方案,那就是 深度选择器 - :deep() 。可以使用 :deep() 包括需要穿透的类,达到影响子元素的效果。

    <style lang="scss" scoped>.home {width: 200px;height: 200px;background-color: lightblue;:deep(.warning) {background-color: lightsalmon;}}</style>

不过若是频繁使用 :deep(),影响代码美观和整洁度是必然的。

4.3. 性能问题

使用 scoped 可能会导致性能问题,因为浏览器在渲染时必须查找和匹配这些唯一的属性。

5. 相似方案

5.1 CSS 模块 (CSS Modules)

这是一个在编译时将类名和动画名进行本地范围限定的 CSS 文件,可以有效地实现样式隔离。

5.2 BEM(Block Element Modifier)或者其他 CSS 命名策略

恰当的命名策略可以帮助更好地组织和理解样式设计,并实现一定程度的样式隔离。

5.3 使用 CSS-in-JS 库,如 Styled Components 或者 Emotion

这些库可以提供更强大和灵活的样式封装选项,实现完全的样式隔离。

简单列举几个可行的方案,暂时先不做详细讲解.小伙伴感兴趣的话,后续会逐步更新。

个人在项目有用过 BEM 命名策略和 CSS Module

BEM 结合工具函数和 scss 预处理函数,可以极大地减轻应用的心智负担,比较典型的 ElementPlus 中就有 BEM 命名策略的应用。

CSS Module 我更多的是在 React 项目中使用,Vue 项目中用的不多,需要借助插件实现。

结语

好啦,今天的内容就到这里啦。关于 scoped 这个特性,必定是 仁者见仁,各有想法。不得不说,它还是一个比较实用的特性,可以帮助我们比较方便的实现样式隔离的需求,且不需要额外的 polyfil。亲爱的小伙伴,你怎么看呢,欢迎评论区留言讨论。

感谢阅读,愿 你我共同进步,谢谢!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/7800.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Java EE] 多线程(九):ReentrantLock,Semaphore,CountDownLatch与线程安全的集合类(多线程完结)

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (91平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;Java …

PE文件(四)FileBuffer-ImageBuffer作业

C语言实现如下功能 2.编写一个函数&#xff0c;将RVA的值转换成FOA 将文件加载到内存时&#xff0c;已知一个数据在内存中的地址&#xff0c;将此地址转化成文件在硬盘上时的相对于文件起始地址的文件偏移地址。即将虚拟内存偏移地址转换成文件偏移地址。 说明&#xff1a;这里…

记一次DNS故障导致用户无法充值的问题(上)

背景&#xff1a; 刚刚过去了五一劳动节&#xff0c;回来后一上班接到客服运营团队反馈的节日期间的问题&#xff0c;反馈有部分用户无法充值。拿到的反馈资料有&#xff1a; 无法充值操作视频、问题时间、手机机型、手机网络情况。 1、从视频中看到用户点击支付后没有任何反…

Linux系统使用Docker安装青龙面板并实现远程访问管理面板

文章目录 一、前期准备本教程环境为&#xff1a;Centos7&#xff0c;可以跑Docker的系统都可以使用。本教程使用Docker部署青龙&#xff0c;如何安装Docker详见&#xff1a; 二、安装青龙面板三、映射本地部署的青龙面板至公网四、使用固定公网地址访问本地部署的青龙面板 青龙…

聊聊 ASP.NET Core 中间件(三):如何创建自己的中间件?

前言 本质上&#xff0c;中间件类也是一个普通的 .NET 类&#xff0c;它不需要继承任何父类或者实现任何接口。 但是有几个约定&#xff1a; 需要有一个构造方法构造方法至少要有一个 RequestDelegate 类型的参数&#xff0c;用来指向下一个中间件。需要定义一个名字为 Invo…

嵌入式linux学习第一天

参考正点原子Linux开发文档。记录下知识点。 Shell 基本操作 前面我们说 Shell 就是“敲命令”&#xff0c;那么既然是命令&#xff0c;那肯定是有格式的&#xff0c;Shell 命令的格式 如下&#xff1a; command -options [argument] command: Shell 命令名称。 options&…

雷军-2022.8小米创业思考-6-互联网七字诀之专注:有所为,有所不为;克制贪婪,少就是多;一次解决一个最迫切的需求

第六章 互联网七字诀 专注、极致、口碑、快&#xff0c;这就是我总结的互联网七字诀&#xff0c;也是我对互联网思维的高度概括。 专注 从商业角度看&#xff0c;专注就是要“把鸡蛋尽量放在一个篮子里”。这听起来似乎有些不合理&#xff0c;大家的第一反应可能是“风险会不会…

JUC-synchronized练习-交替打印ABC

今天来练习一下synchronized 简单来利用synchronized实现一个字符串的交替打印 主要的实现设置一个全局的变量state&#xff0c;线程执行通过不断累加state&#xff0c;根据state对三取余的结果来判断该线程是否继续执行还是进入等待。并通过synchronized锁住一个共享变量loc…

js 图片渐变

1. 点击图片&#xff0c;使其渐变为另一张图片 通过定义keyframes来创建一个淡入淡出的动画效果。当图片被点击时&#xff0c;先添加淡出动画使图片透明度从0渐变到1&#xff0c;然后在1秒后切换图片源并添加淡入动画使新图片透明度从0渐变到1&#xff0c;实现图片渐变效果。 …

自动化机器学习——贝叶斯优化

自动化机器学习——贝叶斯优化 贝叶斯优化是一种通过贝叶斯公式推断出目标函数的后验概率分布&#xff0c;从而在优化过程中不断地利用已有信息来寻找最优解的方法。在贝叶斯优化中&#xff0c;有两个关键步骤&#xff1a;统一建模和获得函数的优化。 1. 统一建模 在贝叶斯优…

.双链表.

题目&#xff1a; 实现一个双链表&#xff0c;双链表初始为空&#xff0c;支持 55 种操作&#xff1a; 在最左侧插入一个数&#xff1b;在最右侧插入一个数&#xff1b;将第 k&#x1d458; 个插入的数删除&#xff1b;在第 k&#x1d458; 个插入的数左侧插入一个数&#xf…

新型中医揿针如何降血糖呢?

点击文末领取揿针的视频教程跟直播讲解 “新型针贴”专用揿针是为“埋针疗法”特制治的一种特殊针具&#xff0c;它是古代针刺留针方法的发展。具体来说&#xff0c;它是将特制针具刺入皮内&#xff0c;固定后留置一定时间&#xff0c;利用其持续微弱的刺激作用来治疗疾病的一…

做抖音小店需要注意什么?这几点很多人不知道,看完防踩坑

大家好&#xff0c;我是电商笨笨熊 抖音小店虽然推出了一段时间&#xff0c;但是依旧有新手玩家陆陆续续加入其中&#xff1b; 对于很多新手来说&#xff0c;只看到了其中红利&#xff0c;但却没有看到其中包含的一些运营小细节&#xff0c;且这些细节决定你店铺未来发展&…

【redis】Redis数据类型(四)Set类型

目录 Set类型介绍使用场景 Set类型数据结构set的单个元素的添加过程IntSet哈希表内存结构 常用命令SADD示例 SREM示例 SMEMBERS示例 SISMEMBER示例 SCARD示例 SMOVE示例 SPOP示例 SRANDMEMBER示例 SINTER示例 SINTERSTORE示例 SUNION示例 SUNIONSTORE示例 SDIFF示例 SDIFFSTORE…

每日一题(PTAL2):列车调度--贪心+二分

选择去维护一个最小区间 代码1&#xff1a; #include<bits/stdc.h> using namespace std; int main() {int n;cin>>n;int num;vector <int> v;int res0;for(int i0;i<n;i){cin>>num;int locv.size();int left0;int rightv.size()-1;while(left<…

Go语言fmt包深度探索:格式化输入输出的利器

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 &#x1f3ad; 引言一、基础输出函数fmt.Print与fmt.Println&#x1f4cc; fmt.Print&#xff1a;纯粹输出&#xff0c;不带换行&#x1f4cc; fmt.Println&#xff1a;输出后自动添加换行符 二、格式化输出fmt.Printf&…

在Java中如何有效地处理内存泄露

在Java中&#xff0c;处理内存泄露有多种方法&#xff0c;以下是其中三种常见的方法及其原理和适用场景&#xff1a; ## 1. 合理使用垃圾回收机制 Java中的垃圾回收机制&#xff08;Garbage Collection&#xff0c;GC&#xff09;是一种自动化的内存管理技术&#xff0c;它可以…

代码随想录day19day20打卡

二叉树 1 二叉树的最大深度和最小深度 最大深度已经学习过了&#xff0c;实质就是递归的去判断左右子节点的深度&#xff0c;然后对其进行返回。 附加两个学习的部分&#xff1a; &#xff08;1&#xff09;使用前序遍历的方法求解 int result; void getdepth(TreeNode* nod…

保研面试408复习 1——操作系统、计网、计组

文章目录 1、操作系统一、操作系统的特点和功能二、中断和系统调用的区别 2、计算机组成原理一、冯诺依曼的三个要点二、MIPS&#xff08;每秒百万条指令&#xff09;三、CPU执行时间和CPI 3、计算机网络一、各个层常用协议二、网络协议实验——数据链路层a.网络速率表示b.数据…

酷得智能电子方案 早教学习机

早教学习机是用户友好的&#xff0c;易于操作&#xff0c;同时要确保内容的科学性和适宜性&#xff0c;以促进儿童的健康成长和智力发展。 通常包括以下几个方面&#xff1a; 1.年龄分级内容&#xff1a;软件会根据儿童的不同年龄段提供相应的教育内容&#xff0c;从新生儿到…