<template>
<div
ref="wrapper"
class="pull-refresh-wrapper"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
>
<div class="spinner" :style="spinnerStyle"></div>
<slot></slot>
</div>
</template>
<script>
export default {
name: 'PullToRefresh',
props: {
onRefresh: { type: Function, required: true },
disabled: { type: Boolean, default: false }
},
data() {
return {
startY: 0,
moveY: 0,
isRefreshing: false,
threshold: 160,
minPullDuration: 400
};
},
computed: {
spinnerStyle() {
const translateY = Math.min(this.moveY * 0.4, this.threshold);
const scale = Math.min(this.moveY / this.threshold, 1);
return {
transform: `translateY(${translateY}px) scale(${scale})`,
opacity: scale
};
}
},
methods: {
touchStart(e) {
if (this.disabled || this.isRefreshing) return;
if (this.$refs.wrapper.scrollTop <= 0) {
this.startY = e.touches[0].pageY;
this.startTime = new Date().getTime();
}
},
touchMove(e) {
if (this.startY > 0) {
this.moveY = e.touches[0].pageY - this.startY;
if (this.moveY > 0) {
e.preventDefault();
this.$refs.wrapper.style.transform =
`translateY(${Math.min(this.moveY / 2, this.threshold)}px)`;
}
}
},
async touchEnd() {
const duration = new Date().getTime() - this.startTime;
if (this.moveY >= this.threshold &&
duration >= this.minPullDuration &&
!this.isRefreshing) {
this.isRefreshing = true;
try {
await this.onRefresh();
} finally {
this.isRefreshing = false;
}
}
this.reset();
},
reset() {
this.startY = 0;
this.moveY = 0;
setTimeout(() => {
this.$refs.wrapper.style.transition = 'transform 0.3s ease';
this.$refs.wrapper.style.transform = 'translateY(0)';
}, 0);
}
}
};
</script>
<style scoped>
.pull-refresh-wrapper {
overflow-y: auto;
position: relative;
height: 100%;
}
.spinner {
height: 2rem;
width: 2rem;
border: 3px solid rgba(0, 0, 0, 0.1);
border-top: 3px solid #999;
border-radius: 50%;
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
animation: rotation 1s linear infinite;
}
@keyframes rotation {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>
<template>
<div class="app">
<PullToRefresh :onRefresh="handleRefresh">
<div class="content">
<div>
<!-- 컨텐츠 -->
</div>
</div>
</PullToRefresh>
</div>
</template>
<script>
import PullToRefresh from './components/PullToRefresh.vue'
export default {
components: { PullToRefresh },
data() {
return { .. }
},
methods: {
async handleRefresh() {
// 새로고침 시 수행할 작업 (예: API 호출)
await new Promise(resolve => setTimeout(resolve, 1000));
this.items = [
...this.items,
{ id: this.items.length + 1, text: `항목 ${this.items.length + 1}` }
];
}
}
}
</script>
<style>
..
</style>
야매로 만들어 보았읍ㄴ다람쥐
'Vue' 카테고리의 다른 글
선택항목 개수 계산 (0) | 2024.10.28 |
---|---|
템플릿에서 조건식 vs Computed (0) | 2024.10.28 |
vue-query 맛보기 (1) | 2024.10.18 |
스크립트 요소 순서 (2) | 2024.10.18 |
promise 사용 (0) | 2024.10.18 |