场景
通过点击“收起”/"展开"按钮,显示部分/全量的搜索框。
实现
在代码中发现,搜索框名称和搜索框均用v-show="!item.isShow"来控制展示和隐藏;
且在点击“收起”/"展开"按钮时,会触发 btnswitch()方法以修改每个元素的isShow属性。
<template>
<div>
<el-form ref="loginForm" class="login-form" autocomplete="on" label-position="left">
<el-row>
<el-col
v-for="(item, index) in queryArr"
:key="index"
>
<!-- 搜索框名称 -->
<label class="padding-right20 itme-title" v-show="!item.isShow">
{{ item.label }}
</label>
<!-- 搜索框 -->
<div class="item-col" v-show="!item.isShow">
<el-input
v-model.trim="item.val"
class="font-xs item-form-doc"
v-if="item.type == 'input'"
></el-input>
</el-col>
</el-row>
</el-form>
<slot></slot>
<div class="switch" @click.stop="btnswitch" v-if="this.isSwitch">
{{ this.open ? '收起' : '展开' }}
<el-icon :class="{ arrow_down: this.open ? true : false }"><ArrowDown /></el-icon>
</div>
</div>
</template>
export default{
methods:{
btnswitch() {
this.open = !this.open
if (this.open) {
for (var i in this.queryArr) {
this.queryArr[i].isShow = false
}
} else {
for (var j in this.queryArr) {
this.queryArr[j].isShow = true
}
}
}
}
}
// 其中,this.queryArr数据如下
[
{
"label": "用户ID",
"id": "userId",
"placeholder": "请输入",
"val": "",
"type": "input",
"isShow": true
},
{
"label": "用户账号",
"id": "name",
"placeholder": "请输入",
"val": "",
"type": "input",
"isShow": true
},
{
"label": "所属租户",
"id": "tenantId",
"type": "input",
"placeholder": "请输入",
"val": "",
"isShow": true
},
{
"label": "是否兑换/分配",
"id": "redeemed",
"type": "select",
"val": null,
"placeholder": "请选择",
"option": [
{
"val": false,
"label": "否"
},
{
"val": true,
"label": "是"
}
],
"isShow": true
}
]
问题
在点击“收起按钮后”,item的isShow被修改为true,则 !isShow=false,v-show绑定的值也变为false,在这种情况下,前三个搜索框仍然可以正常展示,并未被隐藏。
也就是说,v-show对于前三个元素失效了,但对于最后一个元素【是否兑换/分配】是生效的。
分析
既然是部分失效,肯定不是我眼花,也不是v-show指令的问题。
通过强大的baidu分析得知,v-show 生效是基于 css 的权重。
v-show在元素上实际是使用内联样式display:none去达到隐藏的效果的。
因此对于比内联样式权重低的样式,v-show 会生效;
但如果 v-show 使用的元素上有一个 display: block !important,v-show 是失效的。
于是回过头来看代码,注意观察搜索框名称和搜索框各自绑定了样式itme-title和item-col,观察这两个样式,发现它的CSS如下:
.el-form {
.el-row {
.el-col {
&:nth-child(1) {
.itme-title {
display: block !important; //根因
}
.item-col {
display: block !important; //根因
}
}
&:nth-child(2) {
.itme-title {
display: block !important; //根因
}
.item-col {
display: block !important; //根因
}
}
&:nth-child(3) {
.itme-title {
display: block !important; //根因
}
.item-col {
display: block !important; //根因
}
}
}
}
}
el-col的第1、2、3个元素的itme-title和item-col样式都写入了display: block !important。
这也就是为什么前三个搜索框的v-show失效的原因,而第四个搜索框v-show生效。
扩展
以前也写过类似“收起/展开”的需求,但并非像上述代码这样实现,贴上自己以前的写法。
我是通过把固定显示的部分摘出来正常显示,不用v-show来控制它;
而把需要点击隐藏的部分单独作为一个整体,通过v-show="isExpand"去控制显示/隐藏的。
<template>
<div class="search-content">
<!-- 搜索条件 -->
<el-form :inline="true" :model="searchForm" ref="formRef" class="search-form">
<el-row>
<!-- 固定显示的部分 -->
</el-row>
<div v-show="isExpand">
<!-- 收起时隐藏,展开时显示的部分 -->
</div>
<div class="search-form-btn">
<el-button class="search-btn" type="primary" @click="handleSearch">查询</el-button>
<el-button class="search-btn" @click="handleReset('formRef')">重置</el-button>
<el-button type="text" @click="handleExpand">
{{ isExpand ? '收起' : '展开' }}
<i class="i-more-search el-icon-arrow-down" :class="{ 'icon-expand': isExpand }" />
</el-button>
</div>
</el-form>
</div>
</template>
handleExpand() {
this.isExpand = !this.isExpand
},