Skip to content

<style>中的scoped原理

Vue <style> 中的 scoped 有什么作用吗

1、认识<style> 中的 scoped

我们在写样式的时候,经常会遇到一个习惯,就是在style样式之中加一个scoped达到css局部作用域的作用,那么,你了解过这个 scoped 属性吗

实际使用之中限制局部样式

javascript
<style scoped>

</style>

2、<style> 中的 scoped原理

我们先来简单看看这个scoped 属性是如何实现在加入css之中影响当前的vue组件的

当一个style标签拥有scoped属性时候,css样式只能用于当前的Vue组件,原理是通过PostCSS来实现,通过给想对应的dom新增一个属性,同时给css选择器新增一个对应的属性,来对应这个唯一的dom,如下所示,我们可以看看具体转译。

javascript

//编译前
<template>
  <div class="example">
    Scoped style example
  </div>

</template>

<style scoped>
.example {
  color: red;
}
</style>


// 编译后
.example[data-v-xxxx] {
  color: red;
}

PostCSS简单介绍

PostCSS 是一个用于处理 CSS 的工具,它可以将 CSS 转换为不同的格式或应用特定的插件来增强 CSS 功能。它允许你使用各种插件,例如自动添加浏览器前缀、支持最新的 CSS 语法、优化 CSS 文件大小等。通过配置 postcss.config.js 文件,你可以定制它的行为以适应项目的需求。

<style scoped> 可能实现的原理略微不同,有以下几种:

  1. CSS 属性选择器: 在 Vue.js 中,scoped 属性通过给组件的根元素添加一个唯一的属性(如 data-v-xxxx),然后将 CSS 选择器调整为匹配这些唯一属性。Vue.js 会将 <style scoped> 中的 CSS 转换为类似 div[data-v-xxxx] .my-class 的选择器,这样 CSS 规则只应用于包含该属性的元素。
  2. CSS 模块: 一些工具和框架(如 React 的 CSS 模块)通过将 CSS 类名自动生成唯一标识符来实现作用域隔离,意味着组件中的 CSS 类名被转换为独特的名称,从而避免样式冲突。
  3. Shadow DOM: Web Components 标准的 Shadow DOM 允许将样式和结构封装在一个组件的私有 DOM 中,从而实现样式的隔离。虽然 scoped 属性与 Shadow DOM 并不直接相关,但它们都旨在实现局部样式作用域。

3、<style> 中的 scoped优点和缺点:

他能起到的作用也非常明显:

优点:

js
- 限制组件样式当前作用域
- 控制子组件根节点样式

缺点:

但是它的缺点你却可能有些忽略(这里其实一开始我也忽略了)

⭐子组件样式想在父组件之中干涉必须强制

这个其实就是只能强制去进行更改子组件的样式,例如:

javascript
:deep()

也就是必须通过下面的干涉才能生效css样式

image.png

⭐性能问题

使用scoped这个会造成你浏览器性能消耗

没错,使用scoped这个是会造成你浏览器性能消耗的!!!!!

因为浏览器在渲染时需要额外的步骤来查找和匹配这些唯一的属性选择器。具体来说,使用 scoped 属性时,框架(如 Vue.js)会为每个组件生成独特的属性选择器,这会增加浏览器的计算负担,尤其是在包含大量组件或复杂样式的应用中。每次渲染时,浏览器需要检查这些属性选择器并应用相应的样式,这可能导致额外的开销,尤其在大规模应用或复杂的样式层级中。

在实践中,这种性能影响通常较小,但在极端情况下或对于性能要求极高的应用,可能需要注意优化和性能测试。

所以,其实我加个类名的事,所以我尽量减少它的使用!

4、类似实现

除了 <style scoped> 之外,类似用于实现 CSS 的局部作用域或样式隔离,以避免样式冲突和提高组件化开发的灵活性方法和技术还有几种:

(1) CSS 模块(CSS Modules)

概念:CSS 模块通过为每个 CSS 类名生成唯一的标识符来实现局部作用域,避免类名冲突。

实现:在构建过程中,工具(如 Webpack、Vite)会自动为每个类名生成唯一的哈希值,从而避免全局样式冲突。

下面是示例

js
/* styles.module.css */
.example {
  color: red;
}
js
// Component.jsx
import styles from './styles.module.css';

function Component() {
  return <div className={styles.example}>CSS Modules example</div>;
}

(2)CSS-in-JS

概念:CSS-in-JS 是一种在 JavaScript 文件中编写和管理 CSS 的技术,使样式与组件逻辑紧密结合,通常会生成唯一类名避免冲突。

实现:使用类似 styled-components 或 Emotion 的库,可以在组件中直接编写样式,库会处理样式的局部作用域和唯一性。

下面是示例:(使用 styled-components):

js
import styled from 'styled-components';

const Example = styled.div`
  color: red;
`;

function Component() {
  return <Example>CSS-in-JS example</Example>;
}

(3) Shadow DOM

概念:Shadow DOM 是 Web Components 的一部分,允许将样式和 DOM 结构封装在组件内部,实现样式完全隔离。

实现:浏览器会为 Shadow DOM 中的样式创建独立的作用域,外部样式和内部样式不会相互影响。

下面是示例

js
html
<template id="my-component">
  <style>
    .example {
      color: red;
    }
  </style>

  <div class="example">Shadow DOM example</div>

</template>

<script>
  class MyComponent extends HTMLElement {
    constructor() {
      super();
      const template = document.getElementById('my-component').content.cloneNode(true);
      const shadowRoot = this.attachShadow({ mode: 'open' });
      shadowRoot.appendChild(template);
    }
  }
  customElements.define('my-component', MyComponent);
</script>

<my-component></my-component>

(4) BEM(块、元素、修饰符)

概念:BEM 是一种 CSS 命名约定,用于创建可复用的组件并避免样式冲突。虽然 BEM 本身不提供局部作用域,但它通过命名规则减少了样式冲突的可能性。

实现:使用特定的命名模式,如 block__element--modifier,可以帮助确保样式的唯一性和可维护性。

示例

js
css
/* BEM 命名规范 */
.button {
  color: red;
}
.button--primary {
  background-color: blue;
}
js
html
<button class="button button--primary">BEM example</button>

(5) 前缀化(Prefixing)

概念:通过在 CSS 规则中添加特定的前缀,可以帮助确保样式的作用范围仅限于特定的组件或部分。

实现:可以手动或通过工具(如 PostCSS 插件)为 CSS 类名添加前缀。

示例

js
css
/* 带有前缀的样式 */
.component-button {
  color: red;
}
js
<button class="component-button">Prefixing example</button>

Released under the MIT License.