在列表中如何实现这样的展开收起效果,常规方案是每条数据维护一个展开收起的状态,点击的时候改变这个状态。其实用伪类 :checked 也可以实现相同的效果,需要注意的是上图的 HTML 结构相对复杂一些,触发区(点击处)和内容区(展开收起的内容)不在同一层级,甚至不在同一父元素下,那么 <input type="checkbox" id="xxx" /> 和 <label for="xxx">展开</label> 就不能按常规那样放在一块(其实也可以,用父元素选择器 :has 能实现, 但目前 :has 兼容性要求还比较高),<input type="checkbox" id="xxx" /> 需要放到能通过 CSS 选择器同时覆盖触发区和内容区的层级。
<div v-for="item in taskList" :key="item.id">
<input type="checkbox" :id="'result-' + item.id" class="task-checkbox" />
<div class="task-item">
<span class="task-item_name">{{ item.name }}</span>
<span class="task-item_action">
<el-tag :type="TaskAction[item.action].type" size="small">{{
TaskAction[item.action].label
}}</el-tag>
</span>
<span class="task-item_expand">
<label :for="'result-' + item.id" class="result-expand"
>展开审批意见 <FeIcon name="xia"
/></label>
<label :for="'result-' + item.id" class="result-collapse"
>收起审批意见 <FeIcon name="shang"
/></label>
</span>
</div>
<div class="task-result">{{ item.result }}</div>
</div>
.task-item {
display: flex;
align-items: center;
&_name {
flex: 1;
}
&_action {
flex: 1;
}
&_expand {
flex-shrink: 0;
label {
user-select: none;
cursor: pointer;
}
.result-collapse {
display: none;
}
}
}
.task-result {
display: none;
}
.task-checkbox {
display: none;
&:checked ~ .task-item {
.result-expand {
display: none;
}
.result-collapse {
display: inline-block;
}
}
&:checked ~ .task-result {
display: block;
}
}
使用 :has 会更优雅一点,:has 提供了一种针对引用元素选择父元素或者先前的兄弟元素的方法。这样 <input type="checkbox" id="xxx" /> 就不用放到外层了。
<div v-for="item in taskList" :key="item.id">
<div class="task-item">
<span class="task-item_name">{{ item.name }}</span>
<span class="task-item_action">{{ item.action }}</span>
<span class="task-item_expand">
<input
type="checkbox"
:id="'result-' + item.id"
class="task-checkbox"
/>
<label :for="'result-' + item.id" class="result-expand"
>展开审批意见 <FeIcon name="xia"
/></label>
<label :for="'result-' + item.id" class="result-collapse"
>收起审批意见 <FeIcon name="shang"
/></label>
</span>
</div>
<div class="task-result">{{ item.result }}</div>
</div>
.task-item {
display: flex;
align-items: center;
&_name {
flex: 1;
}
&_action {
flex: 1;
}
&_expand {
flex-shrink: 0;
.task-checkbox {
display: none;
}
label {
user-select: none;
cursor: pointer;
}
.result-collapse {
display: none;
}
}
&:has(.task-checkbox:checked) {
.result-expand {
display: none;
}
.result-collapse {
display: inline-block;
}
& + .task-result {
display: block;
}
}
}
.task-result {
display: none;
}