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
+2
View File
@@ -0,0 +1,2 @@
## 1.0.0(2026-04-30)
- 支持 uni-refresh-box 组件
@@ -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>
+73
View File
@@ -0,0 +1,73 @@
{
"id": "uni-refresh-box",
"displayName": "uni-refresh-box",
"version": "1.0.0",
"description": "uni-refresh-box",
"isExt": true,
"extUrl": "https://ext.dcloud.net.cn/plugin?id=27848",
"keywords": [
"uni-refresh-box",
"uni-app-x",
"uni-app x",
"组件"
],
"repository": "https://gitcode.com/dcloud/uni-ui-x",
"engines": {
"HBuilderX": "^5.07",
"uni-app-x": "^5.07",
"uni-app": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"darkmode": "x",
"i18n": "x",
"widescreen": "x",
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "x",
"aliyun": "x",
"alipay": "x"
},
"client": {
"uni-app-x": {
"web": {
"safari": "√",
"chrome": "√"
},
"app": {
"android": "√",
"ios": "√",
"harmony": "√"
},
"mp": {
"weixin": "√"
}
}
}
}
}
}
+80
View File
@@ -0,0 +1,80 @@
自定义下拉刷新组件。
本组件封装了 scroll-view/list-view等滚动容器的下拉刷新功能,使用者只需在滚动容器中加入本组件,设置组件的属性和样式,即可实现自定义下拉刷新功能。
本组件自带一个全平台通用的下拉刷新样式,即左边一个 loading 圈,右边为下拉刷新相关的文字。也提供了各种自定义方法,包括文字、样式,甚至通过插槽传入完全不同的自定义下拉效果。
### 基本用法
```vue
<template>
<scroll-view
style="flex: 1;"
:refresher-enabled="true"
:refresher-triggered="refreshing1"
refresher-default-style="none"
:refresher-threshold="45"
refresher-max-drag-distance="200px"
@refresherpulling="onRefresherpulling1"
@refresherrefresh="onRefresherrefresh1"
@refresherrestore="onRefresherrestore1"
@refresherabort="onRefresherabort1"
>
<!-- 列表内容 -->
<view v-for="i in listCount1" :key="i" class="content-item">
<text class="text">item-{{ i }}</text>
</view>
<!-- refresher 插槽使用 uni-refresh-box 组件 -->
<uni-refresh-box
slot="refresher"
:pulling-distance="pullingDistance1"
:refreshing="refreshing1"
></uni-refresh-box>
</scroll-view>
</template>
<script setup lang="ts">
const listCount1 = ref(3)
const refreshing1 = ref(false)
const pullingDistance1 = ref(0)
function onRefresherpulling1(e: RefresherEvent) {
pullingDistance1.value = e.detail.dy
}
function onRefresherrefresh1() {
refreshing1.value = true
console.log('列表1 触发刷新')
setTimeout(() => {
listCount1.value += 5
refreshing1.value = false
console.log('列表1 刷新完成')
}, 1500)
}
function onRefresherrestore1() {
pullingDistance1.value = 0
}
function onRefresherabort1() {
pullingDistance1.value = 0
}
</script>
```
#### state 状态说明
| 值 | 说明 |
| :-- | :-- |
| 0 | 下拉中(未达到阈值) |
| 1 | 松手可刷新(已达到阈值) |
| 2 | 刷新中 |
| 3 | 刷新完成 |
| 4 | 归位中(不显示文字) |
### Slots
| 名称 | 说明 | 插槽参数 |
| :-- | :-- | :-- |
| loading | 自定义图标 | - |