实现一:
一、组件 search.vue
<template>
<div class="search-area">
<!-- <div class="search-area__container" :style="{height:`${contentHeight}px`, 'transition-duration': duration }" :class="{ limitHeight: limitHeight && itemLen > splitNum }"> -->
<div class="search-area__container" :style="{'transition-duration': duration }" :class="{ limitHeight: limitHeight && itemLen > splitNum }">
<div ref="content" class="search-area__content">
<slot />
</div>
</div>
<div class="search-area__btn">
<el-button type="primary" icon="el-icon-search" @click="$emit('search')">查 询</el-button>
<el-button class="btn-theme" icon="el-icon-refresh-left" @click="$emit('clear')">重 置</el-button>
<el-button v-if="itemLen > splitNum" class="btn-theme" :icon="limitHeight ? 'el-icon-arrow-down' : 'el-icon-arrow-up'" @click="searchMore">高级查询</el-button>
</div>
</div>
</template>
<script>
export default {
name: 'Search',
props: {
splitNum: {
type: Number,
default: 3
},
twoCol: {
type: Array,
default: () => {
return []
}
},
limitHeightParam: {
type: Boolean,
default: true
}
},
data() {
return {
instanceTemCom: null,
contentHeight: 0,
duration: 0,
// limitHeight: true,
limitHeight: this.limitHeightParam,
itemLen: 0,
labelWidth: 95
}
},
mounted() {
this.initSettings()
const height = this.$refs.content.scrollHeight < 40 ? 40 : this.$refs.content.scrollHeight
this.contentHeight = height + 10
this.duration = (this.contentHeight + 10) * 0.7 + 'ms'
const hasChildNodesArr = []
const childNodesArr = this.$refs.content.childNodes
childNodesArr?.forEach((item, index) => {
if (item?.childNodes[0]) {
hasChildNodesArr.push(item?.childNodes[0])
}
})
this.itemLen = hasChildNodesArr?.length || 0
},
created() {
// this.itemLen = this.$slots.default.length
},
methods: {
initSettings() {
const len = this.$refs.content.childNodes.length
const notMarginIndex = len - len % this.splitNum - 1
let fNum = 0
const splitMap = {
1: 'one-in-line',
2: 'two-in-line',
3: 'three-in-line',
4: 'four-in-line'
}
Array.from(Array(len)).forEach((item, index) => {
if (this.$refs.content.childNodes[index].childNodes[0]) {
fNum = Math.max(fNum, this.$refs.content.childNodes[index].childNodes[0].innerText.length)
}
// fNum = Math.max(fNum, this.$refs.content.childNodes[index].childNodes[0].innerText.length)
})
Array.from(Array(len)).forEach((item, index) => {
if (this.$refs.content.childNodes[index].childNodes[0]) {
this.$refs.content.childNodes[index].childNodes[0].style.width = `${fNum * 14}px`
this.$refs.content.childNodes[index].className = (this.$refs.content.childNodes[index].className + ` ${splitMap[this.splitNum]}`).trim()
}
// this.$refs.content.childNodes[index].childNodes[0].style.width = `${fNum * 12}px`
// this.$refs.content.childNodes[index].className = (this.$refs.content.childNodes[index].className + ` ${splitMap[this.splitNum]}`).trim()
if (this.twoCol.length && this.twoCol.includes(index)) {
this.$refs.content.childNodes[index].className = (this.$refs.content.childNodes[index].className + ' two-col').trim()
} else {
if (index <= notMarginIndex && this.$refs.content.childNodes[index]) {
this.$refs.content.childNodes[index].className = (this.$refs.content.childNodes[index].className + ' m-b-10').trim()
}
}
})
},
searchMore() {
this.contentHeight = this.$refs.content.scrollHeight + 10
this.limitHeight = !this.limitHeight
this.$emit('clickSearchMore')
}
}
}
</script>
<style lang="scss" scoped>
.search-area {
display: flex;
margin-bottom: 15px;
.search-area__container {
display: flex;
flex-grow: 1;
overflow: hidden;
transition: height .3s ease-in-out;
// transition-property: height;
// transition-duration: .3s;
// transition-timing-function: linear;
// transition: height .3s ease;
// transform: scale(1);
// transition: transform 1s linear;
&.limitHeight {
height: 40px !important;
}
}
.search-area__content {
flex-wrap: wrap;
display: flex;
width: 100%;
// font-size: 12px;
font-size: 14px;
> div {
display: flex;
align-items: center;
padding-right: 20px;
box-sizing: content-box;
&.one-in-line {
flex-basis: 100%;
}
&.two-in-line {
flex-basis: calc(50% - 20px);
}
&.three-in-line {
flex-basis: calc(33.3% - 20px);
}
&.four-in-line {
flex-basis: calc(25% - 20px);
}
&.two-col {
flex-basis: calc(66.6% - 20px);
}
&.m-b-10 {
margin-bottom: 8px;
}
> span {
flex-shrink: 0;
text-align: right;
margin-right: 12px;
}
}
.el-select {
width: 100%;
}
.el-range-editor.el-input__inner {
width: 100%;
}
}
.search-area__btn{
display: flex;
height: 32px;
.btn-theme {
border: 1px solid #e0e2f0;
}
}
}
</style>
二、组件使用
<template>
<div class="searchBox">
<Search
:key="boxType"
v-show="showSearch"
label-width="100"
:limit-height-param="false"
@search="handleQuery"
@clear="resetQuery"
>
<div>
<span class="label">公司</span>
<el-select v-model="queryParams.companyCode1" placeholder="请选择公司" clearable filterable default-first-option size="small">
<el-option
v-for="dict in companyCodeOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</div>
<div v-if="iscode">
<span class="label">公司</span>
<el-select v-model="queryParams.companyCode2" placeholder="请选择公司" clearable filterable default-first-option size="small">
<el-option
v-for="dict in companyCodeOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</div>
<div v-if="iscode">
<span class="label">公司</span>
<el-select v-model="queryParams.companyCode3" placeholder="请选择公司" clearable filterable default-first-option size="small">
<el-option
v-for="dict in companyCodeOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</div>
<div v-if="iscode">
<span class="label">公司</span>
<el-select v-model="queryParams.companyCode4" placeholder="请选择公司" clearable filterable default-first-option size="small">
<el-option
v-for="dict in companyCodeOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</div>
</Search>
</div>
</template>
<script>
export default {
data() {
return {
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 20,
companyCode1: null,
companyCode2: null,
companyCode3: null,
companyCode4: null,
},
companyCodeOptions: [],
// 显示搜索条件
showSearch: true,
// boxType改变 searchBox 重新加载
boxType: '',
iscode: false,
}
},
methods: {
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.queryParams = this.$options.data().queryParams
this.handleQuery()
},
}
}
</script>
实现二:
<script>
export default {
name: 'Search',
props: {
labelWidth: {
type: [String, Number],
default: 'auto'
}
},
data() {
return {
isExpand: false,
conditionNum: 0
}
},
watch: {
conditionNum(val) {
this.$nextTick(this.initSettings)
}
},
updated() {
const len = this.$slots.default.filter(item => item.tag).length
if (this.conditionNum !== len) { this.conditionNum = len }
},
methods: {
initSettings() {
const defaultSearchList = this.$refs.defaultSearch.childNodes
const moreSearchList = this.$refs.moreSearch ? this.$refs.moreSearch.childNodes : []
const allSearchList = [...defaultSearchList, ...moreSearchList].filter(item => item.nodeType !== 8)
allSearchList.forEach((item, index) => {
const childrenList = item.childNodes
if (childrenList[0] && childrenList[0].tagName && childrenList[0].tagName.toLowerCase() === 'span') {
childrenList[0].style.width = isNaN(parseFloat(this.labelWidth)) ? 'auto' : `${parseFloat(this.labelWidth)}px`
}
if (index > 3) {
const lastLineIndex = allSearchList.length % 4
item.className = item.className.replace(/\s*no-margin-bottom/g, '')
if (allSearchList.length - (lastLineIndex || 4) <= index) {
item.className = (item.className + ' no-margin-bottom').trim()
}
}
})
},
searchBtn() {
this.$emit('search')
}
},
render(h) {
const slotList = this.$scopedSlots.default()
// this.moreSearchHeight = 0
return (
<div class='search-area'>
<div class='search__default' ref='defaultSearch'>
{ [...slotList.slice(0, 3), ...Array(3).fill(h('div'))].slice(0, 3) }
<div class='search-area__btn'>
<el-button type='primary' size='small' class='btn-search' onClick={ this.searchBtn }>搜索</el-button>
<el-button size='small' onClick={() => this.$emit('clear')}>重置</el-button>
{
slotList.length > 3
? <el-button size='small' onClick={ () => { this.isExpand = !this.isExpand } }>
高级查询
<i class={ this.isExpand ? 'el-icon-arrow-up' : 'el-icon-arrow-down' }></i>
</el-button>
: ''
}
</div>
</div>
{ slotList.length > 3
? <div class={{ 'search__more': true, 'no-expand': !this.isExpand }} style={{ maxHeight: '350px' }} ref='moreSearch'>
{ slotList.slice(3) }
</div>
: ''
}
</div>
)
}
}
</script>
<style lang="scss" scoped>
.search-area {
overflow: hidden;
margin-bottom: 20px;
}
.search__default,
.search__more {
display: flex;
flex-wrap: wrap;
align-items: center;
width: 100%;
font-size: 12px;
> div {
display: flex;
align-items: center;
justify-content: flex-end;
width: calc((100% - 45px) / 4);
margin-bottom: 8px;
box-sizing: border-box;
&.no-margin-bottom {
margin-bottom: 0;
}
&:not(:nth-of-type(4n)) {
margin-right: 15px;
}
> span {
flex-shrink: 0;
text-align: right;
}
}
}
.search__default {
min-height: 32px;
}
.search__more {
transition: all .3s ease-in-out;
&.no-expand {
max-height: 0 !important;
}
}
.search-area__btn{
display: flex;
height: 32px;
}
</style>