后台管理系统中大多数都有列表的搜索,那么用户的需求又需要必要时收缩搜索区域,需要时再展开。
而且怪的是他还需要一些部分不可收缩,不需要的地方才收缩。使用v-if来解决吧又不咋美观,我们还需要一个简单的动画效果。我们先写一个组件,直接上代码。
<template>
<div
class="collapse-el">
<div
ref="CollapseElRef"
class="collapse-el-container">
<div class="collapse-el-container-container">
<slot></slot>
</div>
</div>
<div
v-if="showBt"
class="collapse-el-show-container">
<div
@click="handleClick"
class="container">
<div
:class="{
'bt':true,
'show':show,
}">
<SvgIcon
:style="'width:15px;height:15px;'"
name="sort-down"></SvgIcon>
</div>
{{show?'收缩':'展开'}}
</div>
</div>
</div>
</template>
<script>
/**
* 折叠组件
*/
import {
defineComponent,ref,toRef,
onMounted,
watch,onBeforeUnmount,
} from 'vue';
import SvgIcon from "@/components/svgIcon/index.vue";
export default defineComponent({
name:'Collapse',
components: {
SvgIcon,
},
props:{
show:{ //是否显示
type:Boolean,
default:true,
},
showBt:{ //是否显示展开按钮
type:Boolean,
default:false,
},
anchorPointSignName:{ //锚点标识(可用querySelector查询出来的标识)
type:String,
default:'.anchor-point-target',
},
},
emits:['onClick'],
setup(props,{emit}){
const CollapseElRef = ref(null);
const show = toRef(props,'show');
const showBt = toRef(props,'showBt');
const anchorPointSignName = toRef(props,'anchorPointSignName');
onMounted(() => {
const childEl = CollapseElRef.value.firstChild;
const resizeObserver = new ResizeObserver((entries) => {
computHeight();
});
resizeObserver.observe(childEl);
});
let timer = null;
watch(show,(newValue)=>{
computHeight();
},{
immediate:false,
});
/** 表示是显示的 */
function isActive(){
if(!CollapseElRef.value) return false;
const elRect = CollapseElRef.value.getBoundingClientRect();
if(elRect.top==0 && elRect.bottom==0 && elRect.left==0 && elRect.right==0) return false;
return true;
}
/** 设置显示高度 */
function computHeight(){
clearTimeout(timer);
timer = setTimeout(()=>{
if (!isActive()) return;
if(show.value){
const childHight = CollapseElRef.value.firstChild.getBoundingClientRect().height;
CollapseElRef.value.style.height = childHight + 'px';
}else{
//如果是隐藏的话找出锚点元素
const anchorPointEl = CollapseElRef.value.querySelector(anchorPointSignName.value);
if(!anchorPointEl){
CollapseElRef.value.style.height = 0 + 'px';
}else{ //表示只隐藏到锚点元素
const parentRect = CollapseElRef.value.getBoundingClientRect();
const anchorPointElRect = anchorPointEl.getBoundingClientRect();
const height = anchorPointElRect.y - parentRect.y + anchorPointElRect.height;
CollapseElRef.value.style.height = height + 'px';
}
}
}, 26);
}
onBeforeUnmount(()=>{
clearTimeout(timer);
});
/** 收缩组件点击事件,向外部抛出 */
function handleClick(){
emit('onClick');
}
return {
CollapseElRef,
show,
showBt,
handleClick,
};
},
});
</script>
<style lang='scss' scoped>
.collapse-el{
position: relative;
width: 100%;
height: auto;
>.collapse-el-container{
position: relative;
width: 100%;
overflow: hidden;
transition: all 0.2s;
height: 0;
>.collapse-el-container-container{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: fit-content;
}
}
>.collapse-el-show-container{
display: flex;
justify-content: center;
align-items: center;
position: absolute;
bottom: -7.5px;
left: 0;
width: 100%;
pointer-events: none;
>.container{
width: fit-content;
height: fit-content;
cursor: pointer;
display: flex;
align-items: center;
font-size: 12px;
opacity: 0.5;
pointer-events: initial;
line-height: 1;
>.bt{
width: 15px;
height: 15px;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.2s;
transform: rotate(0deg);
&.show{
transform: rotate(180deg);
}
}
}
}
}
</style>
这样我们就有了一个可伸缩的容器组件,只需要把相应元素放在这个组件中就行了
<DifinCollapse
:show="dataContainer.showSearch"
:showBt="true"
@onClick="dataContainer.showSearch=!dataContainer.showSearch">
<el-col :span="24" :xs="24">
<el-form
:model="dataContainer.form"
ref="QueryFormRef"
:inline="true"
label-width="110px">
<el-row :gutter="0">
<el-col
class="anchor-point-target"
:span="6" :xs="6">
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="dataContainer.form.userName"
placeholder="请输入"
clearable
@clear="handleQuery"
@keyup.enter="handleQuery"/>
</el-form-item>
</el-col>
<el-col :span="6" :xs="6">
<el-form-item label="昵称" prop="nickName">
<el-input
v-model="dataContainer.form.nickName"
placeholder="请输入"
clearable
@clear="handleQuery"
@keyup.enter="handleQuery"/>
</el-form-item>
</el-col>
<el-col :span="6" :xs="6">
<el-form-item label="数据编号" prop="id">
<el-input
v-model="dataContainer.form.id"
placeholder="请输入"
clearable
@clear="handleQuery"
@keyup.enter="handleQuery"/>
</el-form-item>
</el-col>
<el-col :span="6" :xs="6">
<el-form-item label="手机号码" prop="phone">
<el-input
v-model="dataContainer.form.phone"
placeholder="请输入"
clearable
@clear="handleQuery"
@keyup.enter="handleQuery"/>
</el-form-item>
</el-col>
<el-col :span="6" :xs="6">
<el-form-item label="可选择" prop="disabled">
<el-select
style="width:100%;"
v-model="dataContainer.form.disabled"
placeholder="请选择"
clearable
@clear="handleQuery"
@change="handleQuery"
>
<el-option
v-for="item in dataContainer.optionList"
:key="item.id"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6" :xs="6">
<el-form-item label="邮箱" prop="email">
<el-input
v-model="dataContainer.form.email"
placeholder="请输入"
clearable
@clear="handleQuery"
@keyup.enter="handleQuery"/>
</el-form-item>
</el-col>
<el-col :span="12" :xs="12">
<el-form-item label=" ">
<el-button
type="primary"
@click="handleQuery">
<SvgIcon
:style="'width:15px;height:15px;margin-right:5px;'"
name="search-bt"></SvgIcon>
查询
</el-button>
<el-button
@click="resetQuery">
<SvgIcon
:style="'width:15px;height:15px;margin-right:5px;'"
name="redo"></SvgIcon>
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-col>
</DifinCollapse>
是不是非常简单呢,我们可以指定一个元素使收缩的时候只能收缩到相应位置就行了,完美解决需求。DEMO。