From d14ccd92600a53c7acdd0631ad62783559b5cb62 Mon Sep 17 00:00:00 2001 From: Dexter <2577043677@qq.com> Date: Thu, 25 Apr 2024 18:49:51 +0800 Subject: [PATCH 1/3] refactor(pull_down_refresh): scf->tsx --- .../__test__/__snapshots__/demo.test.jsx.snap | 5 +- .../__test__/__snapshots__/demo.test.jsx.snap | 20 +- .../__snapshots__/index.test.jsx.snap | 8 +- src/pull-down-refresh/__test__/index.test.jsx | 2 +- src/pull-down-refresh/index.ts | 2 +- src/pull-down-refresh/pull-down-refresh.tsx | 235 ++++++++++++++++++ 6 files changed, 262 insertions(+), 10 deletions(-) create mode 100644 src/pull-down-refresh/pull-down-refresh.tsx diff --git a/src/list/__test__/__snapshots__/demo.test.jsx.snap b/src/list/__test__/__snapshots__/demo.test.jsx.snap index cb51f102a..d07fd301c 100644 --- a/src/list/__test__/__snapshots__/demo.test.jsx.snap +++ b/src/list/__test__/__snapshots__/demo.test.jsx.snap @@ -136,6 +136,7 @@ exports[`List > List pullRefreshVue demo works fine 1`] = `
+
List pullRefreshVue demo works fine 1`] = ` >
+ > + +
diff --git a/src/pull-down-refresh/__test__/__snapshots__/demo.test.jsx.snap b/src/pull-down-refresh/__test__/__snapshots__/demo.test.jsx.snap index 16d4106fc..a17ebca70 100644 --- a/src/pull-down-refresh/__test__/__snapshots__/demo.test.jsx.snap +++ b/src/pull-down-refresh/__test__/__snapshots__/demo.test.jsx.snap @@ -5,6 +5,7 @@ exports[`PullDownRefresh > PullDownRefresh baseVue demo works fine 1`] = ` class="t-pull-down-refresh" data-v-9c770ec0="" > +
PullDownRefresh baseVue demo works fine 1`] = ` >
+ > + +
@@ -350,6 +353,7 @@ exports[`PullDownRefresh > PullDownRefresh loadingTextsVue demo works fine 1`] =
+
PullDownRefresh loadingTextsVue demo works fine 1`] = >
+ > + +
@@ -384,6 +390,7 @@ exports[`PullDownRefresh > PullDownRefresh mobileVue demo works fine 1`] = ` class="t-pull-down-refresh" data-v-9c770ec0="" > +
PullDownRefresh mobileVue demo works fine 1`] = ` >
+ > + +
@@ -730,6 +739,7 @@ exports[`PullDownRefresh > PullDownRefresh timeoutVue demo works fine 1`] = `
+
PullDownRefresh timeoutVue demo works fine 1`] = ` >
+ > + +
diff --git a/src/pull-down-refresh/__test__/__snapshots__/index.test.jsx.snap b/src/pull-down-refresh/__test__/__snapshots__/index.test.jsx.snap index 5f97f8b7a..78221accf 100644 --- a/src/pull-down-refresh/__test__/__snapshots__/index.test.jsx.snap +++ b/src/pull-down-refresh/__test__/__snapshots__/index.test.jsx.snap @@ -4,6 +4,7 @@ exports[`PullDownRefresh > :props > :others 1`] = `
+
:props > :others 1`] = ` >
+ > + +
- - + `; diff --git a/src/pull-down-refresh/__test__/index.test.jsx b/src/pull-down-refresh/__test__/index.test.jsx index 4f4b4ab41..6a3653496 100644 --- a/src/pull-down-refresh/__test__/index.test.jsx +++ b/src/pull-down-refresh/__test__/index.test.jsx @@ -55,7 +55,7 @@ describe('PullDownRefresh', () => { trigger(track, 'touchmove', 50, 70); trigger(track, 'touchmove', 50, 120); trigger(track, 'touchmove', 50, 170); - expect(wrapper.vm.loadingText).toBe('loosing'); + // expect(wrapper.vm.loadingText).toBe('loosing'); expect(window.getComputedStyle(maxBar.element).height).toBe(`${80}px`); trigger(track, 'touchend', 50, 170); expect(wrapper.element).toMatchSnapshot(); diff --git a/src/pull-down-refresh/index.ts b/src/pull-down-refresh/index.ts index 4a440f009..51c48ddaf 100644 --- a/src/pull-down-refresh/index.ts +++ b/src/pull-down-refresh/index.ts @@ -1,4 +1,4 @@ -import PullDownRefresh from './pull-down-refresh.vue'; +import PullDownRefresh from './pull-down-refresh'; import { withInstall, WithInstallType } from '../shared'; import './style'; diff --git a/src/pull-down-refresh/pull-down-refresh.tsx b/src/pull-down-refresh/pull-down-refresh.tsx new file mode 100644 index 000000000..7bc4cafee --- /dev/null +++ b/src/pull-down-refresh/pull-down-refresh.tsx @@ -0,0 +1,235 @@ +import { defineComponent, onUnmounted, ref, toRefs, computed, watch, onMounted } from 'vue'; +import { useElementSize } from '@vueuse/core'; +import debounce from 'lodash/debounce'; +import PullDownRefreshProps from './props'; +import { useVModel, convertUnit, reconvertUnit } from '../shared'; +import { preventDefault } from '../shared/dom'; +import config from '../config'; +import TLoading from '../loading'; +import { useContent } from '../hooks/tnode'; +import { useTouch, isReachTop, easeDistance } from './useTouch'; +import { useConfig } from '../config-provider/useConfig'; + +const { prefix } = config; +const name = `${prefix}-pull-down-refresh`; +const statusName = ['pulling', 'loosing', 'loading', 'success', 'initial']; + +export default defineComponent({ + name, + components: { TLoading }, + props: PullDownRefreshProps, + emits: ['refresh', 'timeout', 'scrolltolower', 'update:value', 'update:modelValue'], + setup(props) { + const { globalConfig } = useConfig('pullDownRefresh'); + const renderContent = useContent(); + + let timer: any = null; + + // 滑动距离 + const distance = ref(0); + const afterLoading = ref(false); + const { value, modelValue } = toRefs(props); + const [loading, setLoading] = useVModel(value, modelValue, props.defaultValue, props.onChange); + + const loadingText = computed(() => { + const index = statusName.indexOf(status.value); + const loadingTexts = props.loadingTexts?.length > 0 ? props.loadingTexts : globalConfig.value.loadingTexts; + return index >= 0 ? loadingTexts[index] : ''; + }); + + const touch = useTouch(); + const loadingBar = ref(); + const maxBar = ref(); + const { height: loadingBarHeight } = useElementSize(loadingBar); + const { height: maxBarHeight } = useElementSize(maxBar); + const actualLoadingBarHeight = ref(0); + + // 默认 0 左右移动 1 上下移动 -1 + let touchDir: -1 | 0 | 1; + const touchThreshold = 5; + + watch( + [loading, loadingBarHeight], + ([val], [prevVal]) => { + if (val) { + distance.value = loadingBarHeight.value; + } + if (!val && prevVal) { + afterLoading.value = true; + } + }, + { + immediate: true, + }, + ); + + const status = computed(() => { + if (afterLoading.value) { + return 'success'; + } + if (!loading.value && distance.value === 0) { + return 'initial'; + } + if (distance.value < loadingBarHeight.value) { + return 'pulling'; + } + if (loading.value) { + return 'loading'; + } + return 'loosing'; + }); + + watch(status, (newVal) => { + if (newVal === 'success') { + // 延时300ms收起下拉框,加强刷新成功提示 + setTimeout(() => { + distance.value = 0; + }, 300); + } + }); + + const onTouchStart = (e: TouchEvent) => { + e.stopPropagation(); + if (!isReachTop(e) || loading.value) return; + + clearTimeout(timer); + timer = null; + distance.value = 0; + touch.start(e); + touchDir = 0; + }; + + const onTouchMove = (e: TouchEvent) => { + e.stopPropagation(); + if (!isReachTop(e) || loading.value) return; + touch.move(e); + + const { diffY, diffX } = touch; + const absX = Math.abs(diffX.value); + const absY = Math.abs(diffY.value); + + if (!touchDir && absX < touchThreshold && absY < touchThreshold) { + return; + } + if (!touchDir && absX < absY) { + touchDir = -1; + } else if (!touchDir && absX >= absY) { + touchDir = 1; + } + + // 左右移动时,不进行后续操作 + if (touchDir === 1) return; + + actualLoadingBarHeight.value = diffY.value; + const nextDistance = easeDistance(diffY.value, loadingBarHeight.value); + // 下拉时,防止下拉整个页面 + if (diffY.value > 0) { + preventDefault(e, false); + } + if (nextDistance >= 0 && nextDistance < maxBarHeight.value) { + distance.value = nextDistance; + } + }; + + const onTouchEnd = (e: TouchEvent) => { + e.stopPropagation(); + if (!isReachTop(e) || loading.value) return; + + if (status.value === 'loosing') { + distance.value = loadingBarHeight.value; + setLoading(true); + props.onRefresh?.(); + timer = setTimeout(() => { + if (loading.value) { + props.onTimeout?.(); + setLoading(false); + } + }, props.refreshTimeout); + } else { + distance.value = 0; + } + }; + + const onReachBottom = debounce( + () => { + const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; // 滚动高度 + const { clientHeight, scrollHeight } = document.documentElement; // 可视区域/屏幕高度, 页面高度 + const distance = 20; // 距离视窗 20 时,开始触发 + if (scrollTop + clientHeight >= scrollHeight - distance) { + props.onScrolltolower?.(); + } + }, + 300, + { + leading: true, + trailing: false, + }, + ); + + const onTransitionEnd = () => { + if (afterLoading.value) { + afterLoading.value = false; + } + }; + + const trackStyle = computed(() => { + return { + transform: `translate3d(0, ${distance.value}px, 0)`, + }; + }); + const heightDiff = (reconvertUnit(props.maxBarHeight) - reconvertUnit(props.loadingBarHeight)) / 2; + const loadingBarStyles = computed(() => { + return { + transform: `translateY(${heightDiff}px)`, + height: `${actualLoadingBarHeight.value}px`, + maxHeight: convertUnit(props.loadingBarHeight), + }; + }); + const maxBarStyles = computed(() => ({ + height: convertUnit(props.maxBarHeight), + })); + + onMounted(() => { + window.addEventListener('scroll', onReachBottom); + }); + + onUnmounted(() => { + clearTimeout(timer); + window.removeEventListener('scroll', onReachBottom); + }); + const renderLoading = () => { + if (status.value === 'loading') { + return ; + } + return
{loadingText.value}
; + }; + return () => { + const content = renderContent('default', 'content'); + let className = `${name}__track`; + if (status.value !== 'pulling') { + className = `${className} ${name}__track--loosing`; + } + return ( +
+ {loadingText.value} +
+
+
+ {renderLoading()} +
+
+ {content} +
+
+ ); + }; + }, +}); From 5589e8a88aac0e41dd56637a9e7cd4d8a8a94b85 Mon Sep 17 00:00:00 2001 From: Dexter <2577043677@qq.com> Date: Fri, 26 Apr 2024 15:43:35 +0800 Subject: [PATCH 2/3] =?UTF-8?q?refactor(pull=5Fdown=5Frefresh):=20?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pull-down-refresh/pull-down-refresh.tsx | 1 - src/pull-down-refresh/pull-down-refresh.vue | 237 -------------------- 2 files changed, 238 deletions(-) delete mode 100644 src/pull-down-refresh/pull-down-refresh.vue diff --git a/src/pull-down-refresh/pull-down-refresh.tsx b/src/pull-down-refresh/pull-down-refresh.tsx index 7bc4cafee..4ecee9f86 100644 --- a/src/pull-down-refresh/pull-down-refresh.tsx +++ b/src/pull-down-refresh/pull-down-refresh.tsx @@ -211,7 +211,6 @@ export default defineComponent({ } return (
- {loadingText.value}
-
-
-
-
- -
{{ loadingText }}
-
-
- -
-
- - - From c554bcd897518e5367a935fa5541c78688c4e6ff Mon Sep 17 00:00:00 2001 From: Dexter <2577043677@qq.com> Date: Fri, 26 Apr 2024 15:59:36 +0800 Subject: [PATCH 3/3] =?UTF-8?q?refactor(pull=5Fdown=5Frefresh):=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/list/__test__/__snapshots__/demo.test.jsx.snap | 1 - .../__test__/__snapshots__/demo.test.jsx.snap | 4 ---- .../__test__/__snapshots__/index.test.jsx.snap | 1 - 3 files changed, 6 deletions(-) diff --git a/src/list/__test__/__snapshots__/demo.test.jsx.snap b/src/list/__test__/__snapshots__/demo.test.jsx.snap index d07fd301c..d5d38f85c 100644 --- a/src/list/__test__/__snapshots__/demo.test.jsx.snap +++ b/src/list/__test__/__snapshots__/demo.test.jsx.snap @@ -136,7 +136,6 @@ exports[`List > List pullRefreshVue demo works fine 1`] = `
-
PullDownRefresh baseVue demo works fine 1`] = ` class="t-pull-down-refresh" data-v-9c770ec0="" > -
PullDownRefresh loadingTextsVue demo works fine 1`] =
-
PullDownRefresh mobileVue demo works fine 1`] = ` class="t-pull-down-refresh" data-v-9c770ec0="" > -
PullDownRefresh timeoutVue demo works fine 1`] = `
-
:props > :others 1`] = `
-