当前位置:   article > 正文

Vue实战篇三十二:实现新闻的无限加载_vue分页组件用于新闻

vue分页组件用于新闻

系列文章目录

Vue基础篇一:编写第一个Vue程序
Vue基础篇二:Vue组件的核心概念
Vue基础篇三:Vue的计算属性与侦听器
Vue基础篇四:Vue的生命周期(秒杀案例实战)
Vue基础篇五:Vue的指令
Vue基础篇六:Vue使用JSX进行动态渲染
Vue提高篇一:使用Vuex进行状态管理
Vue提高篇二:使用vue-router实现静态路由
Vue提高篇三:使用vue-router实现动态路由
Vue提高篇四:使用Element UI组件库
Vue提高篇五:使用Jest进行单元测试
Vue提高篇六: 使用Vetur+ESLint+Prettier插件提升开发效率
Vue实战篇一: 使用Vue搭建注册登录界面
Vue实战篇二: 实现邮件验证码发送
Vue实战篇三:实现用户注册
Vue实战篇四:创建多步骤表单
Vue实战篇五:实现文件上传
Vue实战篇六:表格渲染动态数据
Vue实战篇七:表单校验
Vue实战篇八:实现弹出对话框进行交互
Vue实战篇九:使用省市区级联选择插件
Vue实战篇十:响应式布局
Vue实战篇十一:父组件获取子组件数据的常规方法
Vue实战篇十二:多项选择器的实际运用
Vue实战篇十三:实战分页组件
Vue实战篇十四:前端excel组件实现数据导入
Vue实战篇十五:表格数据多选在实际项目中的技巧
Vue实战篇十六:导航菜单
Vue实战篇十七:用树型组件实现一个知识目录
Vue实战篇十八:搭建一个知识库框架
Vue实战篇十九:使用printjs打印表单
Vue实战篇二十:自定义表格合计
Vue实战篇二十一:实战Prop的双向绑定
Vue实战篇二十二:生成二维码
Vue实战篇二十三:卡片风格与列表风格的切换
Vue实战篇二十四:分页显示
Vue实战篇二十五:使用ECharts绘制疫情折线图
Vue实战篇二十六:创建动态仪表盘
Vue实战篇二十七:实现走马灯效果的商品轮播图
Vue实战篇二十八:实现一个手机版的购物车
Vue实战篇二十九:模拟一个简易留言板
Vue项目实战篇一:实现一个完整的留言板(带前后端源码下载)
Vue实战篇三十:实现一个简易版的头条新闻
Vue实战篇三十一:实现一个改进版的头条新闻


一、背景

  • 在上一篇文章中,我们加入了新闻频道,可以让用户选择不同的频道,阅读新闻。
  • 但每次点击频道时,APP只能加载固定的10条新闻列表。
  • 我们这次需要实现新闻的无限加载:即当用户滚动新闻列表到达底部时,APP自动加载下一页新闻。

在这里插入图片描述

二、引入无限滚动组件

  • 我们引入element-uiInfiniteScroll组件,该组件可以判断容器的垂直滚动条滚动至底部时,自动执行加载方法。

在这里插入图片描述

  • 基础代码
<template>
  <ul class="infinite-list" v-infinite-scroll="load" style="overflow:auto">
    <li v-for="i in count" class="infinite-list-item">{{ i }}</li>
  </ul>
</template>

<script>
  export default {
    data () {
      return {
        count: 0
      }
    },
    methods: {
      load () {
        this.count += 2
      }
    }
  }
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

三、加载新闻事件

3.1 接口解析

  • 我们仍然通过极数数据接口,来获取新闻频道的数据
  • 在这个接口中,我们观察到请求参数中,有个start参数,可以通过传入偏移值offset,来获取下一页的新闻。
  • 即当前浏览的是第1页的新闻,当滚动条到达底部触发自动加载方法时,需要给start参数传值为2,即加载第2页的新闻,依次类推。

在这里插入图片描述

3.2 编写加载方法

methods: {
	  // 自动加载方法,获取下一页新闻
    load() {
     // 从状态管理器中获取当前新闻列表是第几页
      let start = this.$store.state.news.start
      start++
      // 接口限制最大不超过400页
      if (start < 400) {
        this.getNews(this.$store.state.news.channel, start, this.$store.state.news.num).then(res => {
          console.log('loading more news', res)
          if (res && res.data.result) {
            const newsData = this.$store.state.news.newsData
            newsData.push.apply(newsData, res.data.result.list)
            this.$store.commit('SET_NEWS', newsData)
            this.$store.commit('SET_START', start)
          }
        })
      }
    },
    ...
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 附上状态管理器源码
// 用于存储各种变量
const news = {
  state: {
    // 频道
    channel: '',
    // 起始位置
    start: 0,
    // 一次向接口接取新闻的条数
    num: 10,
    // 存放拉取下来的新闻
    newsData: [],
    // 当前正在查看的新闻
    newsIndex: -1,
    // 是否加载状态
    loading: false
  },

  mutations: {

    SET_CHANNEL: (state, channel) => {
      state.channel = channel
    },
    SET_START: (state, start) => {
      state.start = start
    },
    SET_NUM: (state, num) => {
      state.num = num
    },

    SET_NEWS: (state, news) => {
      state.newsData = news
    },

    SET_NEWS_INDEX: (state, newsIndex) => {
      state.newsIndex = newsIndex
    },
    SET_LOADING: (state, loading) => {
      state.loading = loading
    }

  },

  actions: {
    setChannel({ commit }, channel) {
      return new Promise(resolve => {
        commit('SET_CHANNEL', channel)
      })
    },

    setStart({ commit }, start) {
      return new Promise(resolve => {
        commit('SET_START', start)
      })
    },

    setNum({ commit }, num) {
      return new Promise(resolve => {
        commit('SET_NUM', num)
      })
    },

    setNews({ commit }, news) {
      return new Promise(resolve => {
        commit('SET_NEWS', news)
      })
    },
    setNewsIndex({ commit }, newsIndex) {
      return new Promise(resolve => {
        commit('SET_NEWS_INDEX', newsIndex)
      })
    },
    setLoading({ commit }, loading) {
      return new Promise(resolve => {
        commit('SET_LOADING', loading)
      })
    }
  }
}

export default news

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

四、改造主页,实现无限加载

1、在新闻列表中引入无限滚动加载功能,并关联自动加载方法
2、在底部放入加载条,显示正在努力加载

在这里插入图片描述
3、向接口获取数据成功后,重新渲染新闻列表
在这里插入图片描述

  • 以下是改造后的完整源码:
<template>
  <div>
    <!-- 标题栏 -->
    <div class="header">
      <span />
      <span>新闻</span>
      <span />
    </div>
    <channel />
    <div ref="container" class="nav-content">
      <!-- 在新闻列表中引入无限滚动加载功能 -->
      <div v-if="loading == false" v-infinite-scroll="load" class="news-list">
        <div
          v-for="(item, index) in newData"
          :key="index"
          class="section"
          @click="toNews(index)"
        >
          <div class="news">
            <div class="news-left">
              <img :src="item.pic" alt="">
            </div>
            <div class="news-right">
              <div class="newsTitle">{{ item.title }}</div>
              <div class="newsMessage">
                <span>{{ item.time }}</span>
                <span>{{ item.src }}</span>
              </div>
            </div>
          </div>
        </div>
        <!-- 在底部放入加载条 -->
        <div class="loading-more">正在努力加载</div>
      </div>
      <el-main
        v-else
        v-loading="loading"
        class="load"
        element-loading-background="rgba(0,0,0,0)"
        element-loading-text="正在加载中"
      />
    </div>
  </div>
</template>

<script>
import Channel from './channel'
import { getNewList } from '@/api/news'
export default {
  name: 'Home',
  components: { Channel },
  data() {
    return {
    }
  },
  computed: {
    newData() {
      return this.$store.state.news.newsData
    },
    loading() {
      return this.$store.state.news.loading
    }
  },
  methods: {
    load() {
      // 获取下一页新闻
      console.log('已到达底部,自动触发加载方法')
      let start = this.$store.state.news.start
      start++
      if (start < 400) {
        this.getNews(this.$store.state.news.channel, start, this.$store.state.news.num).then(res => {
          console.log('加载下一页新闻列表', res)
          if (res && res.data.result) {
            const newsData = this.$store.state.news.newsData
            newsData.push.apply(newsData, res.data.result.list)
            this.$store.commit('SET_NEWS', newsData)
            this.$store.commit('SET_START', start)
          }
        })
      }
    },
    // 异步获取新闻
    async getNews(channel, start, num) {
      const data = await getNewList(channel, start, num)
      return data
    },
    // 打开新闻阅读
    toNews(index) {
      this.$store.commit('SET_NEWS_INDEX', index)
      this.$router.push('/news')
    }
  }

}
</script>

<style lang="scss"  scoped>
.header {
  width: 100%;
  height: 1.2rem;
  background-color: #d43d3d;
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: #fff;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 3px;
  z-index: 99;
  position: fixed;
  top: 0;
  img {
    width: 0.67rem;
    height: 0.67rem;
    cursor: pointer;
  }
}

.nav-content {
  margin-top: 2.4rem;
}

.news-list {
  position: relative;
  height:calc(100vh - 2.4rem - 49px);
  overflow-y:auto;
  width: 100%;
}

.section {
  width: 100%;
  height: 2.5rem;
  border-bottom: 1px solid #ccc;
}

.news {
  height: 2.25rem;
  box-sizing: border-box;
  margin: 10px 10px;
  display: flex;
}
.news-left {
  height: 100%;
  width: 2.8rem;
  display: inline-block;
}
.news-left img {
  width: 100%;
  height: 100%;
}
.news-right {
  flex: 1;
  padding-left: 10px;
}
.newsTitle {
  width: 100%;
  height: 62%;
  color: #404040;
  font-size: 17px;
  overflow: hidden;
}
.newsMessage {
  width: 100%;
  height: 38%;
  display: flex;
  align-items: flex-end;
  color: #888;
  justify-content: space-between;
}
.load {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
 .loading-more {
  margin-top: 5px;
  width: 100%;
  height: 20px;
  text-align: center;
 }
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182

五、效果演示

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/396345
推荐阅读
相关标签
  

闽ICP备14008679号