Initial commit

This commit is contained in:
tanxin
2026-10-29 10:08:39 +08:00
commit 4c6243a274
124 changed files with 17359 additions and 0 deletions
@@ -0,0 +1,526 @@
<template>
<view slot="refresher" class="uni-refresh-box-buildin"> <!-- TODO 鸿蒙需要在这个view上补属性slot="refresher",不认外层传入-->
<slot name="loading" :state="currentState">
<loading ref="loadingRef" :paused="currentState != 2" class="uni-loading-class-buildin" :class="loadingClass" bold></loading>
</slot>
<text class="uni-text-class-buildin" :class="textClass">{{ tipText }}</text>
</view>
</template>
<script setup lang="ts">
/**
* 自定义下拉刷新
* @description 自定义下拉刷新组件
* @uniPlatform {
* "app": {
* "android": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.21"
* },
* "ios": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.11"
* },
* "harmony": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.07"
* }
* },
* "mp": {
* "weixin": {
* "uniVer": "x",
* "unixVer": "5.07"
* },
* "alipay": {
* "uniVer": "x",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "5.07"
* }
* }
*/
defineOptions({
externalClasses: ['loading-class', 'text-class']
})
const props = defineProps({
/**
* @description 当前下拉距离(px),通常由外部 scroll-view 的 refresher 状态传入
* @default 0
* @uniPlatform {
* "app": {
* "android": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.21"
* },
* "ios": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.11"
* },
* "harmony": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.07"
* }
* },
* "mp": {
* "weixin": {
* "uniVer": "x",
* "unixVer": "5.07"
* },
* "alipay": {
* "uniVer": "x",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "5.07"
* }
* }
*/
pullingDistance: {
type: Number,
default: 0
},
/**
* @description 是否正在刷新中,外部控制;为 true 时显示 loading 动画
* @default false
* @uniPlatform {
* "app": {
* "android": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.21"
* },
* "ios": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.11"
* },
* "harmony": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.07"
* }
* },
* "mp": {
* "weixin": {
* "uniVer": "x",
* "unixVer": "5.07"
* },
* "alipay": {
* "uniVer": "x",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "5.07"
* }
* }
*/
refreshing: {
type: Boolean,
default: false
},
/**
* @description 触发刷新的下拉阈值(px),下拉距离超过该值时进入“松手刷新”状态
* @default 45
* @uniPlatform {
* "app": {
* "android": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.21"
* },
* "ios": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.11"
* },
* "harmony": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.07"
* }
* },
* "mp": {
* "weixin": {
* "uniVer": "x",
* "unixVer": "5.07"
* },
* "alipay": {
* "uniVer": "x",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "5.07"
* }
* }
*/
threshold: {
type: Number,
default: 45
},
/**
* @description 下拉过程中(未达到阈值)显示的提示文字
* @default "下拉刷新"
* @uniPlatform {
* "app": {
* "android": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.21"
* },
* "ios": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.11"
* },
* "harmony": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.07"
* }
* },
* "mp": {
* "weixin": {
* "uniVer": "x",
* "unixVer": "5.07"
* },
* "alipay": {
* "uniVer": "x",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "5.07"
* }
* }
*/
pullingText: {
type: String,
default: '下拉刷新'
},
/**
* @description 下拉超过阈值后显示的提示文字
* @default "松手刷新"
* @uniPlatform {
* "app": {
* "android": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.21"
* },
* "ios": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.11"
* },
* "harmony": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.07"
* }
* },
* "mp": {
* "weixin": {
* "uniVer": "x",
* "unixVer": "5.07"
* },
* "alipay": {
* "uniVer": "x",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "5.07"
* }
* }
*/
loosingText: {
type: String,
default: '松手刷新'
},
/**
* @description 刷新中显示的提示文字
* @default "正在刷新"
* @uniPlatform {
* "app": {
* "android": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.21"
* },
* "ios": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.11"
* },
* "harmony": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.07"
* }
* },
* "mp": {
* "weixin": {
* "uniVer": "x",
* "unixVer": "5.07"
* },
* "alipay": {
* "uniVer": "x",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "5.07"
* }
* }
*/
loadingText: {
type: String,
default: '正在刷新'
},
/**
* @description 刷新完成瞬间显示的提示文字,为空则不展示
* @default ""
* @uniPlatform {
* "app": {
* "android": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.21"
* },
* "ios": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.11"
* },
* "harmony": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.07"
* }
* },
* "mp": {
* "weixin": {
* "uniVer": "x",
* "unixVer": "5.07"
* },
* "alipay": {
* "uniVer": "x",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "5.07"
* }
* }
*/
completeText: {
type: String,
default: ''
},
/**
* @description 提示文字的自定义样式类
* @default ""
* @uniPlatform {
* "app": {
* "android": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.21"
* },
* "ios": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.11"
* },
* "harmony": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.07"
* }
* },
* "mp": {
* "weixin": {
* "uniVer": "x",
* "unixVer": "5.07"
* },
* "alipay": {
* "uniVer": "x",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "5.07"
* }
* }
*/
textClass: {
type: String,
default: ''
},
/**
* @description loading 图标的自定义样式类
* @default ""
* @uniPlatform {
* "app": {
* "android": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.21"
* },
* "ios": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.11"
* },
* "harmony": {
* "uniVer": "x",
* "unixVer": "5.07",
* "unixVaporVer": "5.07"
* }
* },
* "mp": {
* "weixin": {
* "uniVer": "x",
* "unixVer": "5.07"
* },
* "alipay": {
* "uniVer": "x",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "5.07"
* }
* }
*/
loadingClass: {
type: String,
default: ''
}
})
// Data
const loadingRef = ref<UniElement | null>(null)
const resetting = ref(false)
// 标记是否正在归位中(从刷新结束到完全收起)
const restoring = ref(false)
// 状态:0-下拉中 1-松手可刷新 2-刷新中 3-刷新完成 4-归位中(不显示文字)
const currentState = computed((): number => {
if (resetting.value) {
return 3
}
if (props.refreshing) {
return 2
}
// 归位中不显示文字
if (restoring.value) {
return 4
}
if (props.pullingDistance > props.threshold) {
return 1
}
return 0
})
// 提示文字
const tipText = computed((): string => {
switch (currentState.value) {
case 0:
return props.pullingText
case 1:
return props.loosingText
case 2:
return props.loadingText
case 3:
return props.completeText
case 4:
return '' // 归位中不显示文字
default:
return props.pullingText
}
})
// 监听外部 refreshing 变化
watch((): boolean => props.refreshing, (newVal: boolean, oldVal: boolean) => {
if (!newVal && oldVal) {
// 外部结束刷新,显示完成状态
resetting.value = true
restoring.value = true
setTimeout(() => {
resetting.value = false
}, 300)
}
})
// 监听 pullingDistance 变化
watch((): number => props.pullingDistance, (distance: number, oldDistance: number) => {
// 归零时结束归位状态
if (distance == 0 && restoring.value) {
restoring.value = false
}
// 开始新的下拉时(从0变为大于0),重置归位状态
if (distance > 0 && oldDistance == 0 && !props.refreshing) {
restoring.value = false
}
// 更新 loading 旋转角度
const el = loadingRef.value
if (el != null && !props.refreshing) {
const maxDistance = 200
const maxRotation = 540
const rotation = Math.min((distance / maxDistance) * maxRotation, maxRotation)
el.style.setProperty('transform', `rotate(${rotation}deg)`)
}
})
// 暴露状态给外部
defineExpose({
currentState
})
</script>
<style>
.uni-refresh-box-buildin {
justify-content: center;
align-items: center;
flex-direction: row;
width: 100%;
height: 30px;
}
.uni-loading-class-buildin {
width: 14px;
height: 14px;
border-color: #888;
}
.uni-text-class-buildin {
color: #888;
font-size: 14px;
margin-left: 4px;
}
</style>