vue下拉刷新实现案例
Vue 下拉刷新实现案例
使用第三方库(如 vue-pull-refresh)
安装 vue-pull-refresh 库:
npm install vue-pull-refresh --save
在 Vue 组件中引入并使用:
<template>
<pull-refresh :on-refresh="onRefresh">
<!-- 你的列表内容 -->
<ul>
<li v-for="item in list" :key="item.id">{{ item.text }}</li>
</ul>
</pull-refresh>
</template>
<script>
import PullRefresh from 'vue-pull-refresh';
export default {
components: {
PullRefresh
},
data() {
return {
list: [] // 初始数据
};
},
methods: {
onRefresh() {
return new Promise((resolve) => {
setTimeout(() => {
// 模拟异步加载数据
this.list = [...this.fetchNewData(), ...this.list];
resolve();
}, 1000);
});
},
fetchNewData() {
// 替换为实际的数据获取逻辑
return [{ id: Date.now(), text: '新数据' }];
}
}
};
</script>
原生实现(基于 Touch 事件)
通过监听触摸事件实现自定义下拉刷新:
<template>
<div
class="pull-refresh"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
>
<div class="refresh-indicator" :style="{ height: `${pullHeight}px` }">
{{ refreshText }}
</div>
<ul>
<li v-for="item in list" :key="item.id">{{ item.text }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
startY: 0,
pullHeight: 0,
isRefreshing: false,
maxPullHeight: 80
};
},
computed: {
refreshText() {
if (this.isRefreshing) return '加载中...';
return this.pullHeight >= this.maxPullHeight ? '释放刷新' : '下拉刷新';
}
},
methods: {
handleTouchStart(e) {
if (this.isRefreshing) return;
this.startY = e.touches[0].pageY;
},
handleTouchMove(e) {
if (this.isRefreshing) return;
const currentY = e.touches[0].pageY;
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
// 只有在顶部且下拉时才触发
if (scrollTop === 0 && currentY > this.startY) {
const distance = currentY - this.startY;
this.pullHeight = Math.min(distance, this.maxPullHeight);
}
},
handleTouchEnd() {
if (this.isRefreshing || this.pullHeight < this.maxPullHeight) {
this.pullHeight = 0;
return;
}
this.isRefreshing = true;
this.fetchData().finally(() => {
this.isRefreshing = false;
this.pullHeight = 0;
});
},
fetchData() {
return new Promise(resolve => {
setTimeout(() => {
this.list = [...this.generateNewData(), ...this.list];
resolve();
}, 1500);
});
},
generateNewData() {
return [{ id: Date.now(), text: '新数据' }];
}
}
};
</script>
<style>
.pull-refresh {
position: relative;
}
.refresh-indicator {
display: flex;
align-items: flex-end;
justify-content: center;
overflow: hidden;
color: #666;
}
</style>
使用浏览器原生 API(IntersectionObserver)
结合 IntersectionObserver 实现无感知刷新:
<template>
<div class="container">
<ul>
<li v-for="item in list" :key="item.id">{{ item.text }}</li>
</ul>
<div ref="loader" class="loader" v-if="!allLoaded">
{{ loading ? '加载中...' : '上拉加载更多' }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
loading: false,
allLoaded: false,
page: 1
};
},
mounted() {
this.initObserver();
this.loadData();
},
methods: {
initObserver() {
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && !this.loading && !this.allLoaded) {
this.loadData();
}
});
observer.observe(this.$refs.loader);
},
loadData() {
this.loading = true;
setTimeout(() => {
const newData = Array(10).fill(0).map((_, i) => ({
id: this.page * 10 + i,
text: `项目 ${this.page * 10 + i}`
}));
this.list = [...this.list, ...newData];
this.page++;
this.loading = false;
if (this.page > 3) {
this.allLoaded = true;
}
}, 1000);
}
}
};
</script>
<style>
.loader {
padding: 10px;
text-align: center;
color: #666;
}
</style>
注意事项
- 移动端适配需确保
touch事件正确触发 - 性能优化:大数据列表应配合虚拟滚动
- 加载状态需明确反馈给用户
- 网络错误情况需处理异常状态
- 原生实现需注意事件冲突(如与滚动条的交互)







