VUE篇之推送+瀑布流

html 复制代码
<template>
  <div class="root">
    <div class="container" ref="container" @scroll="onScroll">
      <!-- 瀑布流列表 -->
      <transition-group name="list" tag="div" class="list">
        <div
          v-for="(item, index) in items"
          :key="item._uid"
          class="list-item"
        >
          {{ item.text }}
        </div>
      </transition-group>

      <!-- 加载状态 -->
      <div class="loading" v-if="loading">加载中...</div>
      <div class="loading" v-else-if="allLoaded">没有更多数据了</div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: [],
      page: 1,
      pageSize: 10,
      allLoaded: false,
      loading: false,
      pushTimer: null, // 定时器
    };
  },
  created() {
    this.loadMore();

    // 定时推送消息,每 3 秒一次
    this.pushTimer = setInterval(() => {
      this.pushMessage();
    }, 3000);
  },
  beforeDestroy() {
    // 清理定时器
    if (this.pushTimer) {
      clearInterval(this.pushTimer);
    }
  },
  methods: {
    loadMore() {
      if (this.loading || this.allLoaded) return;
      this.loading = true;

      setTimeout(() => {
        const newItems = Array.from({ length: this.pageSize }).map((_, i) => ({
          _uid: Date.now() + Math.random() + i,
          text: `列表数据 第${(this.page - 1) * this.pageSize + i + 1}条`,
        }));

        this.items = [...this.items, ...newItems];
        this.page++;
        this.loading = false;

        if (this.page > 5) this.allLoaded = true;
      }, 500);
    },

    pushMessage() {
      const message = {
        _uid: Date.now() + Math.random(),
        text: `【推送消息】 ${new Date().toLocaleTimeString()}`,
      };
      // 插入到最前面
      this.items = [message, ...this.items];
    },

    onScroll() {
      const container = this.$refs.container;
      if (!container) return;

      const scrollBottom =
        container.scrollHeight - container.scrollTop - container.clientHeight;
      if (scrollBottom < 100) {
        this.loadMore();
      }
    },
  },
};
</script>

<style scoped>
.root {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.container {
  width: 400px;
  height: 500px;
  overflow-y: auto;
  border: 1px solid #ccc;
  padding: 10px;
  box-sizing: border-box;
  margin-bottom: 10px;
}

.list {
  display: flex;
  flex-direction: column;
}

.list-item {
  background: #f0f0f0;
  margin-bottom: 10px;
  padding: 15px;
  border-radius: 8px;
  transition: all 0.3s ease;
}

/* transition-group 动画 */
.list-enter-active {
  animation: fadeInDown 0.4s;
}
.list-leave-active {
  animation: fadeOutUp 0.4s;
}

@keyframes fadeInDown {
  from {
    opacity: 0;
    transform: translateY(-20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fadeOutUp {
  from {
    opacity: 1;
    transform: translateY(0);
  }
  to {
    opacity: 0;
    transform: translateY(-20px);
  }
}

.loading {
  text-align: center;
  padding: 10px;
  color: #999;
}
</style>
相关推荐
mayaairi38 分钟前
Vue2 事件绑定完全指南:从入门到原理
前端·javascript·vue.js
ℋᙚᵐⁱᒻᵉ鲸落6 小时前
移动端滑动手势冲突:overflow: auto导致外层横向滑动失效
前端·javascript·css·vue.js·html
慧一居士11 小时前
Vite项目中使用Less步骤,详细使用示例
前端·css
用户500937683903913 小时前
热敏小票 Web 打印:我在 58/80mm 上折腾的两周
前端·vue.js
慧一居士16 小时前
Sass和Less功能、使用场景、用法对比
前端·css·less·sass
慧一居士19 小时前
Less功能介绍和完整使用示例
css
snow@li21 小时前
服务器运维:Alibaba Cloud Linux 4 LTS・Vue前端 Java 后端 K3S 部署 CICD 目录规范清单
linux·前端·vue.js
honkun621 小时前
vue 表格组件 vxe-table 实实现专业记账凭证编辑表格与自动汇总
前端·javascript·vue.js
右耳朵猫AI1 天前
Web前端周刊2026W34 | CSS类前缀选择器采纳、Lovable迁移TanStack Start、Fastify 6.0 Alpha
前端·css
web打印社区1 天前
网页静默打印热敏小票:从 HTML 到出纸的完整指南
前端·javascript·vue.js·electron·pdf·html