refactor: ♻️ 重构使用 requestAnimationFrame 的逻辑修复微信小程序报错方法重复定义的问题 (#749)

 Closes: #549
This commit is contained in:
不如摸鱼去 2024-11-30 15:01:09 +08:00 committed by GitHub
parent c136f54cda
commit e9b147ea96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 144 additions and 172 deletions

View File

@ -443,7 +443,7 @@ export const requestAnimationFrame = (cb = () => {}) => {
* @param ms
* @returns
*/
export const pause = (ms: number) => {
export const pause = (ms: number = 1000 / 30) => {
return new AbortablePromise((resolve) => {
const timer = setTimeout(() => {
clearTimeout(timer)

View File

@ -63,7 +63,7 @@ export default {
<script lang="ts" setup>
import wdPickerView from '../../wd-picker-view/wd-picker-view.vue'
import { computed, ref, watch, onMounted } from 'vue'
import { debounce, isArray, isEqual, isNumber, requestAnimationFrame } from '../../common/util'
import { debounce, isArray, isEqual, isNumber, pause } from '../../common/util'
import { compareMonth, formatMonthTitle, getMonthEndDay, getMonths, getTimeData, getWeekLabel } from '../utils'
import Month from '../month/month.vue'
import { monthPanelProps, type MonthInfo, type MonthPanelTimeType, type MonthPanelExpose } from './types'
@ -185,8 +185,9 @@ onMounted(() => {
/**
* 使当前日期或者选中日期滚动到可视区域
*/
function scrollIntoView() {
requestAnimationFrame(() => {
async function scrollIntoView() {
//
await pause()
let activeDate: number | null = 0
if (isArray(props.value)) {
activeDate = props.value![0]
@ -206,10 +207,9 @@ function scrollIntoView() {
top += months.value[index] ? Number(months.value[index].height) : 0
}
scrollTop.value = 0
requestAnimationFrame(() => {
//
await pause()
scrollTop.value = top
})
})
}
/**
* 获取时间 picker 的数据

View File

@ -33,7 +33,7 @@ export default {
<script lang="ts" setup>
import { computed, ref, onMounted } from 'vue'
import { compareYear, formatYearTitle, getYears } from '../utils'
import { isArray, isNumber, requestAnimationFrame } from '../../common/util'
import { isArray, isNumber, pause } from '../../common/util'
import Year from '../year/year.vue'
import { yearPanelProps, type YearInfo, type YearPanelExpose } from './types'
@ -68,8 +68,8 @@ onMounted(() => {
scrollIntoView()
})
function scrollIntoView() {
requestAnimationFrame(() => {
async function scrollIntoView() {
await pause()
let activeDate: number | null = null
if (isArray(props.value)) {
activeDate = props.value![0]
@ -89,10 +89,8 @@ function scrollIntoView() {
top += years.value[index] ? Number(years.value[index].height) : 0
}
scrollTop.value = 0
requestAnimationFrame(() => {
await pause()
scrollTop.value = top
})
})
}
const yearScroll = (event: { detail: { scrollTop: number } }) => {

View File

@ -122,7 +122,7 @@ import wdActionSheet from '../wd-action-sheet/wd-action-sheet.vue'
import wdButton from '../wd-button/wd-button.vue'
import { ref, computed, watch } from 'vue'
import { dayjs } from '../common/dayjs'
import { deepClone, isArray, isEqual, padZero, requestAnimationFrame } from '../common/util'
import { deepClone, isArray, isEqual, padZero, pause } from '../common/util'
import { getWeekNumber, isRange } from '../wd-calendar-view/utils'
import { useCell } from '../composables/useCell'
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
@ -313,7 +313,7 @@ function scrollIntoView() {
calendarView.value && calendarView.value && calendarView.value.$.exposed.scrollIntoView()
}
//
function open() {
async function open() {
const { disabled, readonly } = props
if (disabled || readonly) return
@ -323,10 +323,9 @@ function open() {
lastCalendarValue.value = deepClone(calendarValue.value)
lastTab.value = currentTab.value
lastCurrentType.value = currentType.value
requestAnimationFrame(() => {
//
await pause()
scrollIntoView()
})
setTimeout(() => {
if (props.showTypeSwitch) {
calendarTabs.value.scrollIntoView()

View File

@ -32,7 +32,7 @@ export default {
<script lang="ts" setup>
import wdIcon from '../wd-icon/wd-icon.vue'
import { computed, getCurrentInstance, onMounted, ref, watch, type CSSProperties } from 'vue'
import { addUnit, getRect, isArray, isDef, isPromise, isString, objToStyle, requestAnimationFrame, uuid } from '../common/util'
import { addUnit, getRect, isArray, isDef, isPromise, isString, objToStyle, pause, uuid } from '../common/util'
import { useParent } from '../composables/useParent'
import { COLLAPSE_KEY } from '../wd-collapse/types'
import { collapseItemProps, type CollapseItemExpose } from './types'
@ -103,10 +103,10 @@ async function updateExpand(useBeforeExpand: boolean = true) {
}
function initRect() {
getRect(`#${collapseId.value}`, false, proxy).then((rect) => {
getRect(`#${collapseId.value}`, false, proxy).then(async (rect) => {
const { height: rectHeight } = rect
height.value = isDef(rectHeight) ? Number(rectHeight) : ''
requestAnimationFrame(() => {
await pause()
if (isSelected.value) {
expanded.value = true
} else {
@ -116,7 +116,6 @@ function initRect() {
inited.value = true
}
})
})
}
function handleTransitionEnd() {

View File

@ -27,7 +27,7 @@
import type { AnchorIndex } from './type'
import { indexBarInjectionKey, indexBarProps } from './type'
import { ref, getCurrentInstance, onMounted, reactive, nextTick, watch } from 'vue'
import { getRect, isDef, uuid, requestAnimationFrame } from '../common/util'
import { getRect, isDef, uuid, pause } from '../common/util'
import { useChildren } from '../composables/useChildren'
const props = defineProps(indexBarProps)
@ -131,13 +131,12 @@ function handleTouchMove(e: TouchEvent) {
setScrollTop(getAnchorByPageY(clientY).$.exposed!.top.value - offsetTop)
}
function handleTouchEnd(e: TouchEvent) {
async function handleTouchEnd(e: TouchEvent) {
const clientY = e.changedTouches[0].pageY
state.activeIndex = getAnchorByPageY(clientY).index
setScrollTop(getAnchorByPageY(clientY).$.exposed!.top.value - offsetTop)
requestAnimationFrame(() => {
await pause()
scrollState.touching = false
})
}
function setScrollTop(top: number) {

View File

@ -87,7 +87,7 @@ export default {
<script lang="ts" setup>
import wdIcon from '../wd-icon/wd-icon.vue'
import { computed, onBeforeMount, ref, watch } from 'vue'
import { isDef, objToStyle, pause, requestAnimationFrame } from '../common/util'
import { isDef, objToStyle, pause } from '../common/util'
import { useCell } from '../composables/useCell'
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
import { useParent } from '../composables/useParent'
@ -230,14 +230,14 @@ function formatValue(value: string | number) {
function togglePwdVisible() {
isPwdVisible.value = !isPwdVisible.value
}
function handleClear() {
async function handleClear() {
clearing.value = true
focusing.value = false
inputValue.value = ''
if (props.focusWhenClear) {
focused.value = false
}
requestAnimationFrame(() => {
await pause()
if (props.focusWhenClear) {
focused.value = true
focusing.value = true
@ -247,7 +247,6 @@ function handleClear() {
})
emit('update:modelValue', inputValue.value)
emit('clear')
})
}
async function handleBlur() {
// 150clear

View File

@ -1,7 +1,5 @@
<template>
<view :class="rootClass" :style="customStyle">
<!--自定义label插槽-->
<!--搜索框主体-->
<view class="wd-search__block">
<slot name="prefix"></slot>
<view class="wd-search__field">
@ -9,9 +7,7 @@
<wd-icon name="search" custom-class="wd-search__search-icon"></wd-icon>
<text class="wd-search__placeholder-txt">{{ placeholder || translate('search') }}</text>
</view>
<!--icon:search-->
<wd-icon v-if="showInput || str || placeholderLeft" name="search" custom-class="wd-search__search-left-icon"></wd-icon>
<!--搜索框-->
<input
v-if="showInput || str || placeholderLeft"
:placeholder="placeholder || translate('search')"
@ -27,14 +23,11 @@
:maxlength="maxlength"
:focus="isFocused"
/>
<!--icon:clear-->
<wd-icon v-if="str" custom-class="wd-search__clear wd-search__clear-icon" name="error-fill" @click="clearSearch" />
</view>
</view>
<!--the button behind input,care for hideCancel without displaying-->
<slot v-if="!hideCancel" name="suffix">
<!--默认button-->
<view class="wd-search__cancel" @click="handleCancel">
{{ cancelTxt || translate('cancel') }}
</view>
@ -56,7 +49,7 @@ export default {
<script lang="ts" setup>
import wdIcon from '../wd-icon/wd-icon.vue'
import { type CSSProperties, computed, onMounted, ref, watch } from 'vue'
import { objToStyle, requestAnimationFrame } from '../common/util'
import { objToStyle, pause } from '../common/util'
import { useTranslate } from '../composables/useTranslate'
import { searchProps } from './types'
@ -110,22 +103,17 @@ const coverStyle = computed(() => {
return objToStyle(coverStyle)
})
function hackFocus(focus: boolean) {
async function hackFocus(focus: boolean) {
showInput.value = focus
requestAnimationFrame(() => {
await pause()
isFocused.value = focus
})
}
function closeCover() {
async function closeCover() {
if (props.disabled) return
requestAnimationFrame()
.then(() => requestAnimationFrame())
.then(() => requestAnimationFrame())
.then(() => {
await pause(100)
showPlaceHolder.value = false
hackFocus(true)
})
}
/**
* @description input的input事件handle
@ -141,16 +129,13 @@ function inputValue(event: any) {
/**
* @description 点击清空icon的handle
*/
function clearSearch() {
async function clearSearch() {
str.value = ''
clearing.value = true
if (props.focusWhenClear) {
isFocused.value = false
}
requestAnimationFrame()
.then(() => requestAnimationFrame())
.then(() => requestAnimationFrame())
.then(() => {
await pause(100)
if (props.focusWhenClear) {
showPlaceHolder.value = false
hackFocus(true)
@ -163,7 +148,6 @@ function clearSearch() {
})
emit('update:modelValue', '')
emit('clear')
})
}
/**
* @description 点击搜索按钮时的handle

View File

@ -32,7 +32,7 @@ export default {
<script setup lang="ts">
import { computed, getCurrentInstance, onMounted, reactive, watch } from 'vue'
import { requestAnimationFrame, getRect, isObj, objToStyle, addUnit } from '../common/util'
import { getRect, isObj, objToStyle, addUnit, pause } from '../common/util'
import type { CSSProperties } from 'vue'
import { segmentedProps, type SegmentedExpose, type SegmentedOption } from './types'
const $item = '.wd-segmented__item'
@ -65,11 +65,10 @@ watch(
const { proxy } = getCurrentInstance() as any
onMounted(() => {
onMounted(async () => {
updateCurrentIndex()
requestAnimationFrame(() => {
await pause()
updateActiveStyle(false)
})
})
/**

View File

@ -128,7 +128,7 @@ import wdLoading from '../wd-loading/wd-loading.vue'
import { getCurrentInstance, onBeforeMount, ref, watch, nextTick, computed } from 'vue'
import { useCell } from '../composables/useCell'
import { getRect, isArray, isDef, isFunction, requestAnimationFrame } from '../common/util'
import { getRect, isArray, isDef, isFunction, pause } from '../common/util'
import { useParent } from '../composables/useParent'
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
import { useTranslate } from '../composables/useTranslate'
@ -261,7 +261,7 @@ onBeforeMount(() => {
const { proxy } = getCurrentInstance() as any
function setScrollIntoView() {
async function setScrollIntoView() {
let wraperSelector: string = ''
let selectorPromise: Promise<UniApp.NodeInfo>[] = []
if (isDef(selectList.value) && selectList.value !== '' && !isArray(selectList.value)) {
@ -274,8 +274,7 @@ function setScrollIntoView() {
wraperSelector = '#wd-checkbox-group'
}
if (wraperSelector) {
requestAnimationFrame().then(() => {
requestAnimationFrame().then(() => {
await pause(2000 / 30)
Promise.all([getRect('.wd-select-picker__wrapper', false, proxy), getRect(wraperSelector, false, proxy), ...selectorPromise]).then((res) => {
if (isDef(res) && isArray(res)) {
const scrollView = res[0]
@ -294,8 +293,6 @@ function setScrollIntoView() {
}
}
})
})
})
}
}

View File

@ -24,7 +24,7 @@ export default {
<script lang="ts" setup>
import wdResize from '../wd-resize/wd-resize.vue'
import { computed, getCurrentInstance, reactive, ref, type CSSProperties } from 'vue'
import { addUnit, getRect, objToStyle, requestAnimationFrame, uuid } from '../common/util'
import { addUnit, getRect, objToStyle, pause, uuid } from '../common/util'
import { stickyProps } from './types'
import { useParent } from '../composables/useParent'
import { STICKY_BOX_KEY } from '../wd-sticky-box/types'
@ -108,14 +108,13 @@ function createObserver() {
/**
* 当前内容高度发生变化时重置监听
*/
function handleResize(detail: any) {
async function handleResize(detail: any) {
stickyState.width = detail.width
stickyState.height = detail.height
requestAnimationFrame(() => {
await pause()
observerContentScroll()
if (!stickyBox || !stickyBox.observerForChild) return
stickyBox.observerForChild(proxy)
})
}
/**
* 监听吸顶元素滚动事件

View File

@ -74,7 +74,7 @@ export default {
<script lang="ts" setup>
import wdIcon from '../wd-icon/wd-icon.vue'
import { computed, onBeforeMount, ref, watch } from 'vue'
import { objToStyle, requestAnimationFrame, isDef, pause } from '../common/util'
import { objToStyle, isDef, pause } from '../common/util'
import { useCell } from '../composables/useCell'
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
import { useParent } from '../composables/useParent'
@ -221,14 +221,14 @@ function formatValue(value: string | number) {
return `${value}`
}
function handleClear() {
async function handleClear() {
clearing.value = true
focusing.value = false
inputValue.value = ''
if (props.focusWhenClear) {
focused.value = false
}
requestAnimationFrame(() => {
await pause()
if (props.focusWhenClear) {
focused.value = true
focusing.value = true
@ -238,7 +238,6 @@ function handleClear() {
})
emit('update:modelValue', inputValue.value)
emit('clear')
})
}
async function handleBlur({ detail }: any) {
// 150clear

View File

@ -17,7 +17,7 @@ export default {
<script lang="ts" setup>
import { computed, onBeforeMount, ref, watch } from 'vue'
import { isObj, isPromise, requestAnimationFrame } from '../common/util'
import { isObj, isPromise, pause } from '../common/util'
import { transitionProps, type TransitionName } from './types'
import { AbortablePromise } from '../common/AbortablePromise'
@ -127,16 +127,16 @@ function enter() {
const duration = isObj(props.duration) ? (props.duration as any).enter : props.duration
status.value = 'enter'
emit('before-enter')
enterLifeCyclePromises.value = requestAnimationFrame()
enterLifeCyclePromises.value = pause()
await enterLifeCyclePromises.value
emit('enter')
classes.value = classNames.enter
currentDuration.value = duration
enterLifeCyclePromises.value = requestAnimationFrame()
enterLifeCyclePromises.value = pause()
await enterLifeCyclePromises.value
inited.value = true
display.value = true
enterLifeCyclePromises.value = requestAnimationFrame()
enterLifeCyclePromises.value = pause()
await enterLifeCyclePromises.value
enterLifeCyclePromises.value = null
transitionEnded.value = false
@ -162,11 +162,11 @@ async function leave() {
status.value = 'leave'
emit('before-leave')
currentDuration.value = duration
leaveLifeCyclePromises.value = requestAnimationFrame()
leaveLifeCyclePromises.value = pause()
await leaveLifeCyclePromises.value
emit('leave')
classes.value = classNames.leave
leaveLifeCyclePromises.value = requestAnimationFrame()
leaveLifeCyclePromises.value = pause()
await leaveLifeCyclePromises.value
transitionEnded.value = false
classes.value = classNames['leave-to']