04-vue移动端项目(接上一篇主页index:拦截器带token,$set给动态添加的数据渲染在页面上,上拉加载下拉刷新发送请求版)

主页

10 - 加载频道数据

步骤:

  • a. 在 mounted&created 中请求服务器接口,得到频道数据
    • 接口: 获取用户频道列表
  • b. 将返回的频道数据保存起来
  • c. 将频道数据渲染到页面上
    在这里插入图片描述
    在这里插入图片描述

11- 给请求设置 token

获取频道数据的接口其实是这一种情况:

没有传入 Authorization(token): 只会得到默认的 7 条频道数据

传入了 Authorization(token) :就会得到当前登录用户的频道数据

由于在项目中有很多像获取频道数据一样的接口,它们都可以传入 Authorization,来得到用户自己的信息。也可以不传 Authorization 得到默认数据

需求:如果在 localstorage(vuex) 中 token 就应该放到请求头中,如果 localstorage(vuex) 中没有频道数据,就不用传。

解决方案:在每次发送请求(不管是任意请求)时,都先判断一个 vuex 中是否有用户的 token,如果有,将 token 添加到请求头中,如果没有,不管了。可以在 axios 的请求拦截器中判断 vuex 中是否存在 token,如果存在直接将 token 携带在请求头中

步骤:

  • a. 在 utils/myhttp.js 文件中的请求拦截器
    • 得到 store 对象
    • 判断 store 中的 state 下的 userInfo 是否存在属性 token
      • 如果存在 ,就将 tokenAuthorization 为键,以 token 为值,传入到请求头中
      • 如果不存在,不用理会

注意点:

  • 1.0 向请求头中添加 token 时:
    • 键为: Authorization
    • 值为: Bearer + token (格式为: Bearer + 空格)
  • 2.0 取得 store 中的 token 中时
    • 先将 store 对象导入
  • 3.0 如果添加了 Authroization 之后反而得到不频道数据:
    • 需要重新登录(token 过期了)
  • 4.0 token 的效期只有 2 个小时
    在这里插入图片描述

12 - 判断频道数据

频道数据来源:

如果登录

直接从服务器中得到当前用户的频道数据

如果没有登录

判断:当前 localstorage 中是否存在频道数据

存在:直接从 localstorage 中取出频道数据,进行渲染

不存在:直接从服务器中得到默认的 7 条频道数据

步骤:

  • 1.0 找到 mounted, 将直接获取频道数据的操作删除掉
  • 2.0 进行判断:
    • 判断用户是否登录(判断 vuex 中是否存在 token
      • 如果登录:
        • 直接从服务器中得到用户自己的频道信息
      • 如果未登录:
        • 判断 localstorage 中是否存在频道数据
          • 如果存在:
            • 直接取出渲染到页面上
          • 如果不存在:
            • 直接从服务器中得到默认的 7条频道数据

13 - 将不同频道下的数据分开

由于不同的频道下的数据源是不一样的,所以将来要正确渲染数据需要给每个频道都设置一组自己的数据

文章的数据源:articleList

list 组件的加载状态: loading

list 组件的加载完结状态: finished

pull-refresh 组件的加载状态: isLoading

步骤:

  • 1.0 当我们从服务器中得到了频道数据之后:

    {
    	channels: [
    		{id:0,name:'推荐'},
    		{id:11,name:'后端'}
    	]
    }
    
  • 2.0 应该在每个频道数据下添加这些额外属性: articleList & loading & finished & isLoading

    {
    	channels: [
    		{id:0,name:'推荐',articleList:[],loading:false,finished:false,isLoading:false},
    		{id:11,name:'后端',articleList:[],loading:false,finished:false,isLoading:false}
    	]
    }
    
  • 3.0 将添加的数据在页面上动态渲染
    在这里插入图片描述

14 - 渲染频道下的文章数据

得到当前选中频道的数据对象:可以给 van-tab 设置一个 v-model 属性

步骤:

  • 1.0 确定当前切换的频道的 id
    • 给 van-tbas 添加一个属性:v-model=“active”
    • 在 data 中添加一个属性:active: 0
    • 可以通过以下表达式得到频道的 idthis.channelList[this.active].id
  • 2.0 在 list 组件的 onload 事件中添加逻辑代码
    • 得到当前切换的频道的 id
    • 发送请求到服务器去得到当前频道对应的文章数据
      • 接口:频道新闻推荐_V1.1
    • 将数据渲染到页面上

注意点:

  • 1.0 请求频道下的新闻有两个接口,需要使用第二个:频道新闻推荐_V1.1
  • 2.0 加载完文章数据之后,页面不会马上显示这个数据,先切换到另一个频道之后再切换回来才会执行
    • 这个问题的解决方案:this.$set()

15 - 解决数据无法直接渲染的 bug用$set

表现:打开页面时,文章数据已经加载了,但是无法渲染到页面上

原因:因为 articleList 数据是 channelList 定义之后,动态添加上去的数据,而这样的数据是没有响应式特点的

解决方案:可以使用 $set()

基本用法:

this.$set(obj, prop, value)
// obj:要添加属性的对象
// props:要添加的属性
// value:添加属性对应的值

16 - 上拉加载更多

  • 问题1:文章数据渲染完成之后,页面上一直处于加载状态。
    • 原因: list 刚执行完 load 事件,load事件会将 List的加载状态改为 true。
    • 解决方式:将当前频道下的 list 的加载状态手动改为 false
  • 问题2:当修改加载状态之后,页面就像抽风了一样。请求发一直发送,页面上显示的数据会一直切换。
    • 原因:就是我们每次得到数据之后,使用新的数据将老的数据覆盖掉了,我们页面上的数据永远只有一页的数据(10条)
    • 解决方式:只需要将每次得到的数据接收到原来的数据中就可以了
  • 问题3:当我们切换到某一频道下时, 会一直发送请求,但是没有数据
    • 原因:是因为当前频道下面没有数据
    • 解决方式:只需要判断一个从服务器中返回的文章数据的长度是否为 0
      • 如果为 0 :将当前频道下的 finished 属性改为 true
      • 如果不为0:不用理会

17 - 下拉刷新

步骤:

  • a. 在 onRefresh 事件中
    • 清除当前频道下的所有数据
    • 重新加载数据

注意点:

  • 如果 10 条数据的高度不能让容器的高度占满一个屏幕就无法继续上拉加载更多:所以需要给每个单元格设置一个高度
    在这里插入图片描述
    主页index的详细代码。style没复制:
<template>
  <div class="index">
      <!-- 头部标题-->
    <van-nav-bar title="主页" fixed />
    <!-- 频道区域 -->
    <van-tabs v-model="active">
      <van-tab v-for="(item,index) in channelList" :title="item.name" :key="index">
        <!-- 下拉刷新 -->
        <van-pull-refresh v-model="item.isLoading" @refresh="onRefresh">
        <!-- 上拉显示下面数据 -->
          <van-list v-model="item.loading" :finished="item.finished" finished-text="没有更多了" @load="onLoad">
            <van-cell style="height:60px" v-for="(subitem,subindex) in item.articleList" :key="subindex" :title="subitem.title" />
          </van-list>
        </van-pull-refresh>
      </van-tab>
    </van-tabs>
    <!-- 操作按钮 -->
    <div class="process" @click="show=true">
      <van-icon name="bars" />
    </div>
    <!-- 弹出层 -->
    <!-- 把show与频道列表带过去给子组件 -->
    <com :show = "show"  :channelList="channelList"></com>
 </div>
</template>

<script>
// 导入子组件
import com from './com/index'
// 导入网络请求方法
import { apiGetChannel } from '@/api/channel'
import { apiGetArticleList } from '@/api/article'
// 导入得到本地数据的方法
import { getLocal } from '@/utils/mylocal'
export default {
  components: {
    com
  },
  data () {
    return {
      // 存放用户频道的数据
      channelList: [],
      // 当前频道所在的下标
      active: 0,
      // 操作频道的子组件
      show: false
    }
  },
  mounted () {
    this.getChannels()
  },
  methods: {
    // 当list组件滚动到底部是会触发这个事件
    async onLoad () {
      console.log('到底')
      // 1.0 得到当前选中的频道
      const currentChannel = this.channelList[this.active]
      // 2.0 得到当前有切换的频道的 id
      const currentId = currentChannel.id
      // 3.0 发送请求到服务器中,得到对应的文章数据
      const res = await apiGetArticleList(currentId)
      // console.log(res.data.data.results)
      // 4.0 把获取到的res.data.data.results数组(文章列表)与当前所在的频道列表的articleList融合起来保存到当前选中的频道中
      currentChannel.articleList = [...currentChannel.articleList, ...res.data.data.results]
      // 5.0  将 list 组件的加载状态改为 false 因为有数据不要加载动画了
      currentChannel.loading = false
      // 6.0 判断当前频道的文章列表有没有数据,没有数据的话应该将list组件的数据状态设置为finished就会显示没有更多了
      if (res.data.data.results.length === 0) {
        currentChannel.finished = true
      }
      // console.log(this.channelList)
    },
    // 下拉刷新触发的方法
    onRefresh () {
      console.log('到头')
      // 获得当前频道
      const currentChannel = this.channelList[this.active]
      // 清空当期频道的所有数据
      currentChannel.articleList = []
      currentChannel.isLoading = false
      currentChannel.loading = true
      currentChannel.finished = false
      // 重新加载数据
      this.onLoad()
    },
    // 获取用户频道
    async getChannels () {
      try {
        // 1.0  判断用户有没有登录,有登录就有token
        // 有token就直接发送请求得到用户频道
        if (this.$store.state.userInfo.token) {
          const res = await apiGetChannel()
          // console.log(res)
          this.channelList = res.data.data.channels
        } else {
          // 2.0 没有登录的话就判断本地有没有数据
          const myList = getLocal('channelList')
          if (myList) {
            // 2.1 没有登录用户频道列表 就是本地那个列表
            this.channelList = myList
          } else {
            // 2.2 本地没有数据就发送请求得到默认的数据而不是用户账户的数据
            const res = await apiGetChannel()
            this.channelList = res.data.data.channels
          }
        }
      } catch (error) {
        console.log('出错了')
      }
      // 添加额外属性
      this.addOther()
    },
    addOther () {
      // 遍历每个用户频道列表,给每个用户频道列表添加一些自己的属性
      this.channelList.forEach((item) => {
        // item.articleList = []
        this.$set(item, 'articleList', []) // 添加额外的文章数据
        // item.loading = false
        this.$set(item, 'loading', false) // 添加额外的上拉加载更多的状态属性
        // item.isLoading = false
        this.$set(item, 'isLoading', false) // 添加额外的下拉刷新属性
        // item.finished = false
        this.$set(item, 'finished', false) // 添加 list 的完结状态
      })
    }
  }
}
</script>

效果演示:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值