Skip to content

Commit

Permalink
修正时间格式化会出现未来时间文案的问题 (#190)
Browse files Browse the repository at this point in the history
* feat: 让 toNow 在遇到0值时的行为是几千年前而不是“刚刚”,提早暴露问题

* fix: 修正在vue复用setup结果的场景下toNow可能出现dateGetter值在now值“未来”的问题

* Update useToNowRef.ts

---------

Co-authored-by: 无语 <[email protected]>
  • Loading branch information
Inori-Lover and wuyu8512 authored Jan 18, 2024
1 parent 42ba870 commit 17af6fd
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 15 deletions.
55 changes: 42 additions & 13 deletions src/composition/useToNowRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,56 @@ export function useToNowRef(dateGetter: MaybeRefOrGetter<Date | Dayjs | undefine
return parseTime(dateVal)
})

/**
* 最后一次更新 nowRef 对应的 dateRef 值
*
* @description
* 新增这个值的用意是应对vue的组件复用;
* 复用的组件不会重新跑setup也就不会重新构建nowRef,
* 导致会出现前一帧时间还在正常更新,下一帧来了新的dateRef,与缓存中的nowRef去进行toNow调用了
*/
const lastDateRef = shallowRef<Dayjs | null>(unref(dateRef))
const nowRef = shallowRef(dayjs())

function refreshNowRef() {
nowRef.value = dayjs()
// 更新 nowRef 时也更新 lastDateRef
// 直接赋值同一个对象,免掉对象内存申请
lastDateRef.value = dateRef.value
}

// 刷新nowRef
watchEffect((onClean) => {
if (
// 如果date传进来是空值,保证一次 nowRef 是最新的
// 防止now是几千年前存下来的值
!unref(dateRef) ||
// 如果date和lastDate不同,更新一次nowRef
// 防止now是几个小时前的值但新的date是个几分钟的值,变相出现未来值了
// 这里故意使用引用全等,意在强调 lastDate 与 date 是公用一份内存(/一个对象)的
unref(dateRef) !== unref(lastDateRef)
) {
refreshNowRef()
}

// 注意先更新,后取值
const date = unref(dateRef)
const now = unref(nowRef)

// 不是同一天的就不更新了
if (!date || !date.isSame(now, 'day')) {
if (
// 如果date传进来是空值,无需定时刷新
// 无效时间无需刷新
!date ||
// 如果date跟现在不在同一天,不刷了,爱咋咋滴
!date.isSame(now, 'day')
) {
return
}

// 秒级别的差异,每半分钟刷新一次
// 秒级别的差异,每秒刷新一次
// => "x秒前"
if (date.diff(now, 'second') < 60) {
const timeout = setTimeout(() => {
nowRef.value = dayjs()
}, 1_000 * 1)
const timeout = setTimeout(refreshNowRef, 1_000 * 1)

onClean(() => clearTimeout(timeout))
return
Expand All @@ -58,24 +91,20 @@ export function useToNowRef(dateGetter: MaybeRefOrGetter<Date | Dayjs | undefine
// 分钟级别的差异,每分钟刷新一次
// => "x分钟前"
if (date.diff(now, 'minute') < 60) {
const timeout = setTimeout(() => {
nowRef.value = dayjs()
}, 1_000 * 60)
const timeout = setTimeout(refreshNowRef, 1_000 * 60)
onClean(() => clearTimeout(timeout))
return
}

// 小时级别的差异,每半小时刷新一次
// => "x小时前"
const timeout = setTimeout(() => {
nowRef.value = dayjs()
}, 1_000 * 60 * 60)
const timeout = setTimeout(refreshNowRef, 1_000 * 60 * 30)
onClean(() => clearTimeout(timeout))
return
})

return computed(() => {
// console.log('re-calc toNow', dateRef.value.format(), nowRef.value.format())
return dateRef.value ? toNow(dateRef.value, { now: nowRef.value }) : null
return dateRef.value ? toNow(dateRef.value, { now: nowRef.value, notNegative: true }) : null
})
}
4 changes: 2 additions & 2 deletions src/utils/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import dayjs, { Dayjs } from 'dayjs'
*
* @param date 接受js时间对象、ISO字符串、dayjs对象
*/
export function parseTime(date: Date | Dayjs | string): Dayjs {
export function parseTime(date: Date | Dayjs | string | undefined | null): Dayjs {
// 字符串格式的时间戳会parse成错误的时间,但目前没有这种场景,先注释,省点
// if (typeof date === 'string' && date === (+date).toString()) {
// date = +date
// }

return dayjs(date)
return dayjs(date || 0)
}

/**
Expand Down

0 comments on commit 17af6fd

Please sign in to comment.