头图

后台管理系统中大多数都有列表的搜索,那么用户的需求又需要必要时收缩搜索区域,需要时再展开。
在这里插入图片描述
而且怪的是他还需要一些部分不可收缩,不需要的地方才收缩。使用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


23朵毒蘑菇
16 声望1 粉丝

一个沙雕前端开发者!!