理解vue中less的scoped和/deep/工作原理

理解vue中less的scoped和/deep/工作原理

scoped

vue项目一般是单页面、多组件,整个项目共用一个css样式表,有时候我们在写组件的过程中并不希望组件的样式污染全局作用域(毕竟不同组件之间重名的class很正常),因此我们会在组件的样式标签上加上scoped,例如下面这个最基本vue组件框架:

<template>
...
</template>

<script>
import ...
export defualt {
	data(){
	...
	}
	...
}
</script>

<style lang="less" scoped>
...
</style>

那么这个scoped是什么意思呢?其实就是给每条样式的 最后面 加上一个属性选择器[哈希值],这个哈希值在项目里全局唯一,代表了当前这个组件。例如当前组件用到了 haha.vue , 那么在打包的时候就会编译出一个data-v-5cfc4ef6来唯一代表这个组件。注意一个vue文件里可能有多个哈希值,因为一个组件里还可能嵌套了其他组件。

废话不多说,直接看scoped是怎么工作的。例如:

<style lang="less" scoped>
	.a{
		.b{
			background-color:#bfa
		}
	}
</style>

则打包编译后这个属性会变成这样:

	.a .b[data-v-5cfc4ef6]

注意了,.a和.b之间有空格,表示父子元素;.b和[data-v-5cfc4ef6]无空格,表示并集。那么这条css语句什么意思呢?class为a的元素下的 class为b且具有data-v-5cfc4ef6属性的元素。这样就做到了css样式只针对本组件(哈希值为data-v-5cfc4ef6)的元素

/deep/

那么deep是什么呢?博主找遍全网,找到的信息大意都是:“能够让被scoped限制住的样式属性穿透到子组件”,简直tm在坑爹!这话是不错,但是说了等于没说:为什么平时写项目,同样都是引用自组件,有些地方用/deep/有些地方不用呢?经过我自己的摸索,发现/deep/的工作规律是这样的:
/deep/ === [哈希值]
啥意思呢?还是刚才那个例子,加一个deep:

<style lang="less" scoped>
	.a{
		/deep/.b{
			background-color:#bfa
		}
	}
</style>

那么编译后的结果就会是:

	.a[data-v-5cfc4ef6] .b

注意这个.a[data-v-5cfc4ef6]之间没有空格,表示并集;.a[data-v-5cfc4ef6].b之间是有空格的,表示子元素。
结合less的嵌套语法,我们发现是这样的:
/deep/某个属性前,表示父元素要拥有 哈希值这个属性,而如果没有写/deep/,这个 哈希值是会被scoped到叶子元素上的(最深的子元素,就像上一个例子所演示的那样)。
再举个例子:

/deep/div

会被打包编译成

[data-v-5cfc4ef6] div

注意有空格,表示父元素有 哈希值这个属性的所有div元素,也就是这个组件下的所有div元素了。

实战

有同学会问了,既然scoped会自己帮我们把哈希值放在叶子元素上,为什么还要自己写/deep/来调整哈希值的位置呢?我曾经也有这样的疑问,直到我用了antd…
话不多说,直接看代码:

<template>
  <div class="user-detail-wrap">
    <a-card :bodyStyle="{padding:'20px'}">
      <a-row
        :gutter="8"
      >
        <a-col :sm="5" :xs="5" class="title">编辑角色
          <a @click="goBack">
            <img
              :src="returnIcon"
              style="height: 18px" />
          </a>
        </a-col>
        <a-col :sm="3" :xs="3" style="float:right;">
          <a-button type="primary" style="width:80px;float:right;" v-action:save @click="goSave">保存</a-button>
          <a-modal
            :visible="confirmVisible"
            @cancel="handleCancel"
          >
            <p class="title">
              <img :src="warningIcon" alt="" class="warning-icon">
              <span class="confirm-title">{{ confirmTitle }}</span>
            </p>
            <p class='confirm-text'>{{ confirmText }}</p>
            <template slot="footer">
              <a-button key="back" @click="handleCancel">取消</a-button>
              <a-button key="submit" type="primary" :loading="confirmLoading" @click="handleConfirm">修改</a-button>
            </template>
          </a-modal>
        </a-col>
      </a-row>
    </a-card>
    <a-card :bodyStyle="{padding:'20px'}" class="table-card">
      <a-row
        :gutter="8"
      >
        <a-col :sm="5" :xs="5" class="title">基础信息</a-col>
      </a-row>
      <a-card-grid
        style="width:25%;padding:10px"
        v-for="(record, index) in roleInfoColums"
        :key="index"
      >{{ record.title }}: {{ roleInfo[record.dataIndex] }}</a-card-grid>
    </a-card>
    <a-card :bodyStyle="{padding:'20px'}" class="table-card">
      <a-row
        :gutter="8"
      >
        <a-col :sm="5" :xs="5" class="title">权限信息</a-col>
      </a-row>
      <permission-tree
        :treeData="treeData"
        :disableAll="false"
        @onSelectChange="onSelectChange"
      ></permission-tree>
    </a-card>
  </div>
</template>

打包之后呈现出的部分DOM树是这样的:
在这里插入图片描述

可以看到,父元素ant-modal-root有哈希值,而子元素ant-modal-footer却没有,但是ant-modal-footer的两个button自元素又有哈希值了(可能是因为ant-modal-footer是我插入的另一个template slot的根元素)

 <template slot="footer">
 	<a-button key="back" @click="handleCancel">取消</a-button>
 	<a-button key="submit" type="primary" :loading="confirmLoading" @click="handleConfirm">修改</a-button>
 </template>

这时候,如果不写deep,而是让scoped自己来的话

.ant-modal-root {
  .ant-modal-footer {
    border-top: 0;
    overflow: hidden;
    padding: 32px;
    padding-top:18px;
  }
}

就会编译出这样的css样式:

 .ant-modal-root .ant-modal-footer[data-v-5cfc4ef6]

可是我tm上哪里找有data-v-5cfc4ef6属性的ant-modal-footer…

写上deep:

.ant-modal-root {
  /deep/.ant-modal-footer {
    border-top: 0;
    overflow: hidden;
    padding: 32px;
    padding-top:18px;
  }
}

就编译成了:

 .ant-modal-root[data-v-5cfc4ef6] .ant-modal-footer

这下就能选中了。

总结

用到第三方组件的时候,经常会自己定义插槽slot来替换原组件里的内容,这时候就很容易遇到要手动用/deep/的问题。遇到这类问题的时候,不要盲目地用!important来提高优先级(这样不管用),甚至不加scoped写样式,或者直接通过import .less 引入外部样式来污染全局了(这样会有副作用)

Vue,/deep/是深度作用选择器的简写形式,用于对子组件的样式进行选择。它在Vue2.x版本可用,但在Vue3.x版本会报错。/deep/可以应用于CSS,但不支持CSS预加载器(如less或scss)。 举例来说,如果你想在scoped的scss样式修改子组件的样式,你可以使用/deep/来实现。比如,你可以这样写/scoped/: ```html <style scoped lang="scss"> /deep/ .position-el-steps { /deep/ .el-step.is-vertical { /deep/ .el-step__description { margin-top: -20px; } } } </style> ``` 这样就能够选择到子组件的相应元素,并对其应用样式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [scss使用/deep/深度选择器报错的解决办法](https://blog.csdn.net/weixin_44900104/article/details/126164236)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [【脸脸酱】css /deep/ 深度选择器的用法(在scoped文件修改外部组件样式)](https://blog.csdn.net/qq_42557882/article/details/106871329)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [解决vue scoped scss 无效的问题](https://download.csdn.net/download/weixin_38706603/13126415)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值