Css has 选择器
has 选择器是什么?
CSS 中的 "has 选择器" 是 CSS 级联样式表的一种选择器,用于选择含有满足指定选择器的子元素的父元素。它使用 :has() 伪类来实现。
":has()" 伪类接受一个选择器作为参数,表示要选择包含满足该选择器的子元素的父元素。它在 CSS 选择器中常用于在父元素中选择特定的子元素。用更为直白的话来说,它是一个条件满足的情况下,能够子改父 | 父辈的选择。
它的用法也相当的简单,比如现在要针对只要子元素含有child
类的parent
类更改背景色,就可以如下:
.parent:has(.child) {
/* 对含有特定子元素的父元素应用样式 */
background-color: red;
}
.parent:has(.child) {
/* 对含有特定子元素的父元素应用样式 */
background-color: red;
}
咋一眼看起来这个选择器平淡无奇, 但其实它可以实现非常实用的样式效果,比如说聚焦悬浮列表以及一些骚操作等。
聚焦列表
当观察表格的时候,如果行和列过于多的时候,为了提醒以及方便用户观察表格数据,一般的 UI 表格组件都会在:hover
行的时候给予当前悬浮行一个背景颜色。
但万一行数据量十分的爆炸(动不动百|千万量级别数据量,30+列的需求我都麻木了),而且单元格的间距设置的密密麻麻呢? ok 这个时候过于追求再添加背景色等一系列手段效果也会逐渐降低,悬浮是一个不错的方案,但悬浮也不是一个最有效果的效果。 那最有效果的效果是什么? 看不见 不就是最有效的效果吗。
ok,这里就可以完美的使用has
的选择器的时机了,当然这个还需要借助相邻兄弟选择器
。拿 el-table 举例;
.el-table__row:has(+ tr:hover),
.el-table__row:hover + .el-table__row {
filter: blur(2px);
}
.el-table__row:has(+ tr:hover),
.el-table__row:hover + .el-table__row {
filter: blur(2px);
}
.el-table__row:has(+ tr:hover)
:选择拥有下一个兄弟元素处于:hover 状态的.el-table__row 元素。也就是当兄弟元素行处于鼠标悬停状态时,选择当前行。.el-table__row:hover+.el-table__row
:选择当前行的兄弟元素行。也就是当前行的下一个兄弟元素行。
最后让它们都赋予filter(滤镜)
就可以达到“看不见”的最佳聚焦效果,
复选 el-tree 组件强行改单选组件
相信前端都用过el-tree
这个树形组件,它是用于展示和选择用途,但它可惜只能多选。 但是现在产品需求中要求类似树状展开,同时点击某个节点即位选中,以及如果叶子节点不满足条件的时候点击不可以选中。 这个需求一点都不过分,因为树状展开确实比下拉框有更好的可视关系,但el-tree
是多选呀,代表了不能使用v-model
来实现需求。 当前面临两个方向解决这个问题:
- 自己搓一个下拉树组件,单带选择的功能, 可是时间工期不允许,时间短未必实现有
el-tree
那么稳定和流畅(~~血与泪经历,之前单搓自研了一个 colorPicker ~~) - 说服产品改为下拉树状选择器
(摆烂)
后面认真观察发现,el-tree
在点击节点的时候,会默认给当前选中节点一个背景色,提示用户它在这里选中了展开下面的节点或者点击该节点(同时回调函数抛出当前选中节点数据)。 那其实把它能成选中不就可以吗? 只需要考虑如何告诉节点它是不能点击的,哪怕被点击了也要伪装
不就可以?
沿着这个思路往下发散,因为数据层面上,肯定是能知道什么节点的能点击,什么节点不能点击 (在数据层面上植入了disabled
, true 代表不能点击,反之则能点击), 然后再观察el-tree
输出的 DOM 结构,可以观察是一个行(它的类为el-tree-node__content
)包裹了在代码中写的插槽(<template #default="{ node, data }"></template>
)的html内容
,它们属于父子关系。
那么就可以在内容上,根据数据判断能不能点输入一个类,举个例子比如:
<el-tree>
<template #default="{ node, data }">
<div :class="data.disabled ? 'isDisabled' : ''" ></div>
</template>
</el-tree>
<el-tree>
<template #default="{ node, data }">
<div :class="data.disabled ? 'isDisabled' : ''" ></div>
</template>
</el-tree>
然后再使用:has
,伪装当前效果(当前它还是会抛出事件,但那个好控制,可以根据标识判断要不要给上层组件),
.el-tree-node__content:has(.isDisabled) {
background: #fff !important;
color: #a8abb2 !important;
cursor: no-drop !important;
}
.el-tree-node__content:has(.isDisabled) {
background: #fff !important;
color: #a8abb2 !important;
cursor: no-drop !important;
}
这样就可以设置了只要节点含有isDisabled
类(不能点击),当点击后样式就不会发生变化,同时cursor: no-drop
也让用户悬浮在当前节点上呈不可点击手势图标(视觉上)。 当然的它点击还是会抛出数据,不过既然有标识,那么拦截它不让该数据往上层传递就非常简单的事情了。