效果:
:先上效果
使用:
这里的vue3 ts不做类型限制,可以后期自行加约束。
父组件中使用子组件:
<template>
<el-quarter-picker @change="getQuart" ref="quaRef" v-model="quartDate" />
<div @click="onClick" >点击</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import ElQuarterPicker from "../components/ElQuarterPicker.vue";
const quartDate = ref('')
const quaRef = ref<any>(null)
const getQuart = (date:any)=>{
console.log(date,"<====v-date");
console.log(quartDate.value,"<====v-model");
}
const onClick = ()=>{
quaRef.value?.inputFocus()
}
</script>
主要是当选择年和季度时触发change回调,这里接收date参数,为2023年第一季度的三个月,起始日期和终止日期。后面季度也是入此。
onClick函数主要是点击右侧按钮聚焦输入框,显示popver内容。
子组件代码:ElQuarterPicker
<template>
<div class="el-quarter-picker">
<el-popover :visible="visible" :width="322" placement="bottom-start" trigger="click">
<div>
<div class="top-box"> <el-icon @click="preYear">
<DArrowLeft />
</el-icon>
<span>{{ currYear }} 年</span>
<el-icon @click="nextYear">
<DArrowRight />
</el-icon>
</div>
<div class="content-box">
<span :style="{ color: i.color }" @click="handleQuart(i)" v-for="i in quartlist" :key="i.id">{{ i.label
}}</span>
</div>
</div>
<template #reference>
<el-input v-model="innerValue" @focus="onFocus" ref="inputRef" @blur="onBlur"
:placeholder="placeholder" :prefix-icon="Calendar" :readonly="false" >
<template #suffix>
<el-icon @click="clear" v-show="clearVisble"><CircleClose/></el-icon>
</template>
</el-input>
</template>
</el-popover>
</div>
</template>
<script setup lang="ts">
import { ref, computed, reactive, watch, nextTick } from 'vue';
import { Calendar, DArrowRight, DArrowLeft, CircleClose } from '@element-plus/icons-vue'
const props = defineProps({
placeholder: {
type: String,
default: '选择季度'
},
modelValue: {
type: String,
default: ''
},
})
const emit = defineEmits(['change', 'update:modelValue'])
// v-model 双向绑定
const innerValue = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
})
const visible = ref(false)
const currYear = ref<any>('')
const quartlist = ref<any>([
{
label: '第1季度',
id: 1,
color: "var(--el-datepicker-text-color)"
}, {
label: '第2季度',
id: 2,
color: "var(--el-datepicker-text-color)"
}, {
label: '第3季度',
id: 3,
color: "var(--el-datepicker-text-color)"
}, {
label: '第4季度',
id: 4,
color: "var(--el-datepicker-text-color)"
}
])
const currQuart = reactive<any>({})
currQuart.value = quartlist.value[0]
const getCurrYear = () => {
let date = new Date()
currYear.value = date.getFullYear()
}
getCurrYear()
// 获取现在的年份季度
function getCurrQuarter() {
const now = new Date();
const month = now.getMonth() + 1; // 月份从 0 开始计数,需要加 1
let index = 0
if (month <= 3) {
index = 0;
} else if (month <= 6) {
index = 1;
} else if (month <= 9) {
index = 2;
} else {
index = 3;
}
// 高亮当前季度
quartlist.value[index].color = "var(--el-color-primary)"
}
getCurrQuarter()
const startDate = ref([
'-01-01',
'-04-01',
'-07-01',
'-10-01',
])
const endDate = ref([
'-03-31',
'-06-30',
'-09-30',
'-12-31',
])
// 可以根据传来的默认日期 进行回显 自行拓展
// const setCurrQuart = ()=>{
// console.log(innerValue.value);
// }
// setCurrQuart()
const inputRef = ref<any>(null)
const inputFocus = ()=>{
inputRef.value?.focus()
}
defineExpose({
inputFocus
})
const nextYear = () => {
// 获取焦点防止丢失焦点隐藏
inputFocus()
let year = new Date(new Date().setFullYear(currYear.value + 1)).getFullYear()
currYear.value = year
innerValue.value = currYear.value + '-' + currQuart.value.label
let emitDate = {
startDate: currYear.value + startDate.value[currQuart.value.id - 1],
endDate: currYear.value + endDate.value[currQuart.value.id - 1],
}
emit('change', emitDate)
}
const preYear = () => {
inputFocus()
let year = new Date(new Date().setFullYear(currYear.value - 1)).getFullYear()
currYear.value = year
innerValue.value = currYear.value + '-' + currQuart.value.label
let emitDate = {
startDate: currYear.value + startDate.value[currQuart.value.id - 1],
endDate: currYear.value + endDate.value[currQuart.value.id - 1],
}
emit('change', emitDate)
}
const handleQuart = (item: any) => {
quartlist.value.forEach((v: any) => {
v.color = "var(--el-datepicker-text-color)"
if (v.id == item.id) {
v.color = "var(--el-color-primary)"
}
});
currQuart.value = item
let emitDate = {
startDate: currYear.value + startDate.value[currQuart.value.id - 1],
endDate: currYear.value + endDate.value[currQuart.value.id - 1],
}
emit('change', emitDate)
innerValue.value = currYear.value + '-' + currQuart.value.label
nextTick(()=>{
inputRef.value?.blur()
visible.value = false
console.log(inputRef.value.blur);
})
}
const clearVisble = ref(false)
const clear = ()=>{
innerValue.value = ''
let emitDate = {
startDate: '',
endDate: '',
}
emit('change', emitDate)
}
const onFocus = ()=>{
visible.value =true
}
const onBlur = ()=>{
visible.value =false
}
watch(()=>innerValue.value,(val)=>{
// 内容不为空时显示清除
nextTick(()=>{
clearVisble.value = !!val
})
})
</script>
<style scoped>
.el-quarter-picker {
display: inline-block;
}
.top-box {
font-size: 16px;
cursor: pointer;
display: flex;
padding-bottom: 12px;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid var(--el-border-color-lighter);
}
.content-box {
width: 100%;
height: 100px;
display: flex;
padding-top: 12px;
flex-wrap: wrap;
}
.content-box>span {
width: 148px;
height: 40px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
</style>