Vue3+vant4 二次封装“选择2个日期区间“的日历组件
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
免费下载资源
·
前言
最近在开发H5酒店项目,但项目中有好几个地方都用到 “选择2个日期”的日历,各个页面的日历处理逻辑都一样,那就干脆封装一个,需要改时就直接在日历组件中改,方便后期维护和减少代码量。
版本号:vue3.3 + vant4
先看效果图
逻辑说明
1、在 src/components 下创建一个SecondaryCalendar.vue
2、通信方式
父组件:
引入子组件,通过props向子组件传入startTime 开始时间、endTime结束时间,时间格式为时间戳
例如:startTime:1717121848239,endTime: 1717378597104
子组件:
①、接收父传来的两个时间戳,由于props接收的值是只读的,所以将它们保存到新变量中,子组件就拿这两个变量进行逻辑操作
②、剩下的就是选中后时间格式化,最后整合我们要的数据到一个对象中,用emit自定义事件发送给父组件,父组件接收后直接给后端和页面展示,大概逻辑是这样,不难的。
完整代码
home.vue 父组件
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
const showCalendar = ref(false) // 默认不显示日历
const startTim =ref( new Date().getTime())
const endTim = ref(new Date().getTime() + 24 * 60 * 60 * 1000)
const ruzhuDay_num = ref(1) // 入住天数
// 展示用的结束和开始时间
const client_startTim = ref('')
const client_endTim = ref('')
// 切换获取 Rili.vue 子组件传来的选中时间数据
const onConfirm = selectedValues => {
console.log(selectedValues, 'selectedValues')
let { sel_startTime, sel_endTime, show_startTime, show_endTime, ruzhu_day_num } = selectedValues
startTime.value = sel_startTime // 用户选中的时间
endTime.value = sel_endTime
client_startTime.value = show_startTime // 页面展示的两个时间
client_endTime.value = show_endTime
ruzhuDay_num.value = ruzhu_day_num // 天数
showCalendar.value = false // 拿到子组件传来的数据后隐藏日历组件
}
// 日历显/隐
const toggleRili = () => {
showCalendar.value = !showCalendar.value
}
// 格式化选中日历的数据格式
// type 年月日或月日
// inputDateStr 时间戳
const formatDate = (type, inputDateStr) => {
// 创建Date对象
let date = new Date(inputDateStr)
// 获取年、月、日
let year = date.getFullYear()
let month = date.getMonth() + 1 // getMonth返回的月份是从0开始的,所以需要加1
let day = date.getDate()
// 格式化月份和日期,保证始终为两位数
month = month < 10 ? '0' + month : month
day = day < 10 ? '0' + day : day
if (type == 'ymd') {
// 返回格式化后的日期字符串
return year + '年' + month + '月' + day + '日'
} else if (type == 'md') {
// 返回格式化后的日期字符串
return month + '月' + day + '日'
}
}
onMounted(() => {
// 默认日历组件 展示今天和明天的日期
client_startTime.value = formatDate('md', new Date().getTime())
client_endTime.value = formatDate('md', new Date().getTime() + 24 * 60 * 60 * 1000)
})
</script>
</template>
<div>
<van-button type="primary" @click="toggleRili">点击显示</van-button>
<div>入住{{ client_startTime }} ------ 共{{ ruzhuDay_num }}晚 ------- 离店{{ client_endTime }} </div>
<!-- 日历组件 -->
<SecondaryCalendar :show-calendar="showCalendar"
:start-time="startTime"
:end-time="endTime"
@confirm="onConfirm"
@changeValue="showCalendar = false"
/>
</div>
</template>
SecondaryCalendar.vue 二次封装的日历子组件
<script lang="ts">
// 日历组件
export default {
name: 'Rili',
}
</script>
<script lang="ts" setup>
import { ref, computed, onMounted, PropType, reactive, toRefs, watch } from 'vue'
const props = defineProps({
// 两个时间接收的都是时间戳,例如 1717121848239
// 开始时间
startTime: {
type: [String, Number] as PropType<string | number>,
default: new Date().getTime(),
},
// 结束时间
endTime: {
type: [String, Number] as PropType<string | number>,
default: new Date().getTime() + 24 * 60 * 60 * 1000,
},
// 传入的显影状态
showCalendar: {
type: Boolean,
},
})
//定义要向父组件传递的事件
const emit = defineEmits(['changeValue', 'confirm'])
const useShowList = () => {
const state = reactive({
local_rili_startTime: props.startTime, // 复制一份传入的时间用于操作
local_rili_endTime: props.endTime,
show_rili_one: new Date().getTime(), // 入住月日
show_rili_two: new Date().getTime() + 24 * 60 * 60 * 1000, // 离店月日
ruzhu_day_num: 0, // 入住天数
})
return toRefs(state)
}
const { show_rili_one, show_rili_two, ruzhu_day_num, local_rili_startTime, local_rili_endTime } = useShowList()
// 是否显示日历 将父组件传来的值存起来,用于控制日历的显/隐
const isShowBottom = computed(() => props.showCalendar)
// 格式化日历数据格式
const formatter = day => {
if (day.type === 'start') {
day.bottomInfo = '入住'
} else if (day.type === 'end') {
day.bottomInfo = '离店'
}
return day
}
// 确认日历
const onConfirm = dates => {
emit('changeValue')
// console.log(dates, 'dates')
// // 格式化四个数据
local_rili_startTime.value = formatDate('ymd', dates[0])
local_rili_endTime.value = formatDate('ymd', dates[1])
show_rili_one.value = formatDate('md', dates[0])
show_rili_two.value = formatDate('md', dates[1])
// console.log(local_rili_startTime.value, 'local_rili_startTime')
// console.log(local_rili_endTime.value, 'local_rili_endTime')
// 防止默认直接选择时日历不显示几晚的bug
onSelect(dates)
let selectData = {
// 用户选的完整 开始和结束时间
sel_startTime: local_rili_startTime.value,
sel_endTime: local_rili_endTime.value,
// 页面展示 开始和结束时间
show_startTime: show_rili_one.value,
show_endTime: show_rili_two.value,
ruzhu_day_num: ruzhu_day_num.value, // 选中天数
}
emit('confirm', selectData)
}
// 触发自身暴露出去的改变日历显/隐方法
const onClose = () => {
emit('changeValue')
}
// 格式化选中日历的数据格式
// type 年月日或月日
const formatDate = (type, inputDateStr) => {
// 创建Date对象
let date = new Date(inputDateStr)
// 获取年、月、日
let year = date.getFullYear()
let month = date.getMonth() + 1 // getMonth返回的月份是从0开始的,所以需要加1
let day = date.getDate()
// 格式化月份和日期,保证始终为两位数
month = month < 10 ? '0' + month : month
day = day < 10 ? '0' + day : day
if (type == 'ymd') {
// 返回格式化后的日期字符串
return year + '年' + month + '月' + day + '日'
} else if (type == 'md') {
// 返回格式化后的日期字符串
return month + '月' + day + '日'
}
}
// 计算入住天数
const onSelect = dates => {
if (dates.length > 1) {
// 将日期字符串转换为Date对象
const date1 = new Date(dates[0])
const date2 = new Date(dates[dates.length - 1])
// 计算时间差,单位为毫秒
const diff = date2 - date1
// 将毫秒转换为天数
ruzhu_day_num.value = diff / (1000 * 60 * 60 * 24)
console.log(`选择的日期间隔为${ruzhu_day_num.value}天`)
}
}
onMounted(() => {
local_rili_startTime.value = formatDate('ymd', local_rili_startTime.value)
local_rili_endTime.value = formatDate('ymd', local_rili_endTime.value)
show_rili_one.value = formatDate('md', show_rili_one.value)
show_rili_two.value = formatDate('md', show_rili_two.value)
})
</script>
<template>
<!-- 日历 -->
<van-calendar
v-model:show="isShowBottom"
type="range"
title="请选择入住离店日期"
:formatter="formatter"
safe-area-inset-bottom
@confirm="onConfirm"
@select="onSelect"
@close="onClose"
/>
</template>
<style scoped lang="scss"></style>
GitHub 加速计划 / vu / vue
80
16
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:4 个月前 )
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 6 个月前
e428d891
Updated Browser Compatibility reference. The previous currently returns HTTP 404. 7 个月前
更多推荐
已为社区贡献15条内容
所有评论(0)