scoped :deep、>>>、/deep/、::v-deep的原理你真的懂吗

196 阅读3分钟

前言

scpoed实现样式隔离,:deep可以在UI框架中修改默认样式。前端基操这谁不知道啊!!!但是,你真的明白原理吗?接我四招!

scoped怎么实现样式隔离来避免样式污染?属性选择器添加在哪里?属性选择器添加位置有特例吗?:deep怎么实现样式穿透呢?

image.png

不知道的话就来看看吧~

scoped原理

scoped原理非常简单,既然你容易重名,那我给你加一个特殊标记不就行了嘛

  1. scoped会给每个组件实例中生成一个唯一的id
  2. 然后把这个id作为属性添加给组件中所有标签元素
  3. 然后给<style scoped>中每个选择器的最后一个选择器单元添加这个id作为属性选择器,实现样式隔离。

是不是看得头晕眼花,我们直接上图!这是Vue初始项目做了一定简化之后打包后dist目录下的结果,你自己可以试试看~眼见为实

<script setup>
</script>

<template>
  <header>
    <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />

    <div class="wrapper">
      
      <Child />
    </div>
  </header>

  <main>
  </main>
</template>

<script setup>
import Child from './component/Child.vue'
</script>

<style scoped>
header {
    display: flex;
    place-items: center;
    padding-right: calc(var(--section-gap) / 2);
  }

  .logo {
    margin: 0 2rem 0 0;
  }

  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }
}
</style>

1735024353630.png

可以看到由于不在同一个组件中,parent组件和child组件的id不一样,分别为3664f99e和ef7759cf, 而且[data-v-hashId]作为属性被添加到每一个标签上。这一步完成了标签的唯一性。

image.png

可以看到打包后红框内父组件的选择器的最后一个选择器单元都加上了一个[data-v-hashId]的属性,来使选择器能够选中生成的唯一性的标签,scoped已经生效了。

:deep原理

原理太简单啦,快来看看怎么穿透的吧

如果在父组件里直接给child组件的元素设置样式会怎么样?

1735025922542.png

说对啦,会直接把父组件的id添加在选择器的最后一个选择单元,也就是child组件的元素选择器上。因为child组件既有父元素id,也有自己的id,所以这里是能够直接生效的,那看scoped的应用场景在哪里呢?

image.png

如果不是child根元素,其余child组件内的元素使用这种方法都会无效。因为child组件内的元素添加的属性使用的是child组件的id,但是在父组件中写的元素选择器被添加上了父组件的id,所以根本选不到child组件内的元素,自然无法生效。

image.png

image.png

那么应该怎么办呢?为什么不问问神奇:deep呢? image.png

生效了!!!这里deep的原理非常简单,把id从最后一个元素选择器移动到deep前的选择器上!就这么简单

image.png

应用

那么看下来,:deep只是一个解决UI框架默认样式的工具吗?不不不,:deep可以用于穿透任何子组件,如果有一个子组件在多处被使用,但是其中一处使用时样式跟其他地方不一样,这时候就可以使用:deep从父组件穿透他!

image.png

既然看到这里了,给个吧,球了~

参考文献:juejin.cn/post/702334…