在表格页面中,我们经常用到带有展开收起功能的过滤表单,看似很简单的功能,但是实现起来通常不那么优雅。
我们使用grid
布局来实现这个就非常简单:
.search-form {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 10px;
&:not(.expend) {
.el-form-item {
// 前三个和最后一个一直显示,其他的隐藏
&:nth-child(n + 4):not(:nth-last-child(-n + 1)) {
display: none;
}
}
}
.el-form-item {
margin-bottom: 0;
}
我们把它封装成通用组件
SearchForm.vue
<script setup lang="ts">
import { computed, ref, useCssModule, watch } from 'vue'
import type { FormInstance, FormProps } from 'element-plus'
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue'
interface SearchFormProps extends Omit<FormProps, 'inline'> {
column?: number
offset?: boolean
}
const props = withDefaults(defineProps<SearchFormProps>(), {
column: 4,
offset: true
})
const emits = defineEmits<{
toggle: [boolean]
reset: []
confirm: []
}>()
const style = useCssModule()
const formRef = ref<FormInstance | null>(null)
const expand = ref(false)
const offsetNum = ref(0)
const formProps = computed(() => {
const { column, ...formProps } = props
return formProps
})
const handleToggle = () => {
handleSetOffset()
expand.value = !expand.value
emits('toggle', expand.value)
}
const handleReset = () => {
emits('reset')
}
const handleConfirm = () => {
emits('confirm')
}
const styleEl = ref<HTMLStyleElement | null>(null)
const handleGenerateCss = (column: number) => {
const { searchForm } = style
const css = `
.${searchForm}:not(.expend) .el-form-item:nth-child(n + ${column}):not(:nth-last-child(-n + 1)) {
display: none;
}
`
const cssText = document.createTextNode(css)
if (styleEl.value) {
styleEl.value.removeChild(styleEl.value.firstChild)
styleEl.value.appendChild(cssText)
} else {
const style = document.createElement('style')
style.appendChild(cssText)
styleEl.value = style
document.head.appendChild(style)
}
}
const handleCalcOffset = () => {
const { column, offset } = props
if (!offset) return 0
const formEl: HTMLElement = formRef.value?.$el
if (!formEl) return 0
const formLength = formEl.querySelectorAll(
'.el-form-item:not(.virtual)'
).length
if (formLength < column) return column - formLength
return column - (formLength % column)
}
const handleSetOffset = () => {
offsetNum.value = handleCalcOffset()
}
watch(
() => props.column,
(column) => {
handleGenerateCss(column)
handleSetOffset()
},
{ immediate: true }
)
defineExpose({
form: formRef
})
</script>
<template>
<el-form
ref="formRef"
v-bind="formProps"
@submit.prevent="handleConfirm"
@reset.prevent="handleReset"
:class="[style.searchForm, { expend: expand }]"
>
<slot></slot>
<div v-for="item of offsetNum" :key="item" class="el-form-item virtual" />
<el-form-item>
<el-button @click="handleToggle" :icon="expand ? ArrowUp : ArrowDown">
{{ expand ? '收起' : '展开' }}
</el-button>
<el-button type="primary" native-type="submit">查询</el-button>
<el-button native-type="reset">重置</el-button>
</el-form-item>
</el-form>
</template>
<style module lang="scss">
.searchForm {
display: grid;
grid-template-columns: repeat(v-bind(column), 1fr);
grid-gap: 10px;
:global(.el-form-item) {
margin-bottom: 0;
}
}
</style>
Usage
<script setup lang="ts">
import { reactive, ref } from 'vue'
import SearchForm from './Search.vue'
const formStore = reactive({
name: '',
region: '',
type: '',
age: '',
title: '',
color: '',
tag: '',
date: '',
time: ''
})
</script>
<template>
<SearchForm :model="formStore" labelWidth="100px">
<el-form-item label="name" prop="name">
<el-input v-model="formStore.name" />
</el-form-item>
<el-form-item label="region" prop="region">
<el-input v-model="formStore.region" />
</el-form-item>
<el-form-item label="type" prop="type">
<el-input v-model="formStore.type" />
</el-form-item>
<el-form-item label="age" prop="age">
<el-input v-model="formStore.age" />
</el-form-item>
<el-form-item label="title" prop="title">
<el-input v-model="formStore.title" />
</el-form-item>
<el-form-item label="color" prop="color">
<el-input v-model="formStore.color" />
</el-form-item>
<el-form-item label="tag" prop="tag">
<el-input v-model="formStore.tag" />
</el-form-item>
<el-form-item label="date" prop="date">
<el-input v-model="formStore.date" />
</el-form-item>
<el-form-item label="time" prop="time">
<el-input v-model="formStore.time" />
</el-form-item>
<el-form-item label="time" prop="time">
<el-input v-model="formStore.time" />
</el-form-item>
</SearchForm>
</template>
标签:style,const,form,实现,value,column,grid,选择器,Css
From: https://www.cnblogs.com/coderDemo/p/17812342.html