当前位置:首页 > VUE

vue下拉刷新实现案例

2026-02-24 12:37:17VUE

Vue 下拉刷新实现案例

使用第三方库(如 vue-pull-refresh

安装 vue-pull-refresh 库:

vue下拉刷新实现案例

npm install vue-pull-refresh --save

在 Vue 组件中引入并使用:

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 事件正确触发
  • 性能优化:大数据列表应配合虚拟滚动
  • 加载状态需明确反馈给用户
  • 网络错误情况需处理异常状态
  • 原生实现需注意事件冲突(如与滚动条的交互)

标签: 案例vue
分享给朋友:

相关文章

ssh vue 实现

ssh vue 实现

使用SSH连接Vue项目部署的服务器 在Vue项目开发或部署过程中,可能需要通过SSH连接到远程服务器进行配置或维护。以下是实现SSH连接并部署Vue项目的关键步骤: 生成SSH密钥对 在本地终端运…

vue实现粘贴

vue实现粘贴

Vue 实现粘贴功能的方法 在 Vue 中实现粘贴功能通常涉及监听粘贴事件并处理剪贴板数据。以下是几种常见的实现方式: 监听原生粘贴事件 通过 @paste 指令或原生 addEventListen…

vue实现portal

vue实现portal

Vue 实现 Portal 功能 Portal 是一种将子节点渲染到父组件 DOM 层级之外的 DOM 节点的技术,常用于实现模态框、弹出层等需要脱离当前组件层级的场景。Vue 可以通过多种方式实现…

vue实现系统

vue实现系统

Vue 实现系统的核心方法 使用 Vue.js 构建系统时,需结合其响应式特性与组件化开发模式。以下为关键实现路径: 项目初始化与工程配置 通过 Vue CLI 或 Vite 创建项目骨架,推荐选择…

轮播vue实现

轮播vue实现

使用 Vue 实现轮播功能 基础轮播实现 安装依赖(如使用 Swiper): npm install swiper vue-awesome-swiper 组件代码示例: <template&…

vue实现卡片

vue实现卡片

Vue 实现卡片组件的方法 使用 Vue 实现卡片组件可以通过多种方式完成,以下是几种常见的实现方法: 使用原生 HTML 和 CSS 在 Vue 单文件组件中,可以通过模板和样式直接实现卡片效果…