vue2案例--类似今日头条新闻浏览

案例效果

vue2案例--类似今日头条新闻浏览_第1张图片

  1. 点击“首页”和“我的”可以切换页面
  2. 首页可以下拉刷新,请求更多数据
  3. 首页下滑可以加载更多

1.创建并梳理项目结构

  1. 创建项目,记得要安装路由 和 eslint
    vue2案例--类似今日头条新闻浏览_第2张图片
  2. 梳理结构,清空 views和components文件夹

vue2案例--类似今日头条新闻浏览_第3张图片

2. 安装和配置Vant组件库

Vant:轻量、可靠的移动端组件库

Vant官网

1. 安装

# Vue2 项目,安装 Vant 2:
npm i vant -S

2. 导入组件

Vant 支持一次性导入所有组件,引入所有组件会增加代码包体积,因此不推荐这种做法。

但是在开发阶段,我们不用考虑体积的问题,怎么快怎么来。在发布的时候,可以对项目体积进行优化,可以直接把vant从项目中抽出去。

举例如下:

输入网址:http://toutiao.liulongbin.top/report.html 可以看到黑马头条项目(该项目已经发布)打包之后生成的结果,如下:

vue2案例--类似今日头条新闻浏览_第4张图片由上图可以看到没有把vant打包进来

在main.js中配置vant组件库

import Vue from 'vue'; 
import Vant from 'vant'; 
import 'vant/lib/index.css'; 

Vue.use(Vant); // use函数是来安装插件的

之后参考官方文档,根据需求进行使用,看到页面效果出现就成功了。

3. 使用 Tabbar 组件并开启路由模式

<template>
  <div>
    
    <router-view>router-view>
    
    <van-tabbar route>
      <van-tabbar-item  icon="home-o" to="/home">首页van-tabbar-item>
      <van-tabbar-item  icon="user-o" to="/user">我的van-tabbar-item>
    van-tabbar>
  div>
template>

4. 通过路由展示对应的 Tabbar 页面

在router/index.js 中配置路由规则:

vue2案例--类似今日头条新闻浏览_第5张图片

5. 初始化 - 使用Navbar组件以及覆盖默认样式

<template>
  <div class="home-container">
    
    <van-nav-bar title="黑马头条" fixed />
  div>
template>
<script>
export default {
  name: 'Home'
}
script>
<style lang="less" scoped>
  .home-container {
    padding-top:46px;
    padding-bottom: 50px;
    .van-nav-bar {
      background-color: #007bff;
    }
    /deep/.van-nav-bar__title {
        color:#fff;
      }
  }
style>
至此,接下来就是完善主页的文章列表

6. 了解获取列表数据的API接口

请求方式
  • GET
请求根路径
  • https://www.escook.cn
请求URL 地址
  • /articles
查询参数–通过&进行拼接
参数名 数据类型 说明
_page Number 页码值。从 1 开始
_limit Number 每页展示的数据条数。
响应的数据结构
[
    {
        "art_id": "8163",
        "title": "iOS原生混合RN开发最佳实践",
        "aut_id": "1111",
        "comm_count": "254",
        "pubdate": "2019-03-11 09:00:00",
        "aut_name": "黑马先锋",
        "is_top": 0,
        "cover": {
            "type": 3,
            "images": [
                "http://www.liulongbin.top:8000/resources/images/32.jpg",
                "http://www.liulongbin.top:8000/resources/images/80.jpg",
                "http://www.liulongbin.top:8000/resources/images/32.jpg"
            ]
        }
    },
    {
        "art_id": "8089",
        "title": "Typescript玩转设计模式 之 创建型模式",
        "aut_id": "1111",
        "comm_count": "24",
        "pubdate": "2019-03-11 09:00:00",
        "aut_name": "黑马先锋",
        "is_top": 0,
        "cover": {
            "type": 1,
            "images": [
                "http://www.liulongbin.top:8000/resources/images/11.jpg"
            ]
        }
    },
    {
        "art_id": "8145",
        "title": "JAVA消息确认机制之ACK模式",
        "aut_id": "1111",
        "comm_count": "99",
        "pubdate": "2019-03-11 09:00:00",
        "aut_name": "黑马先锋",
        "is_top": 0,
        "cover": {
            "type": 0
        }
    }
]
返回参数说明
参数名 类型 说明
art_id string 文章 id
title string 文章标题
aut_id string 作者的 id
comm_count string 评论数
pubdate string 发布日期
aut_name string 作者名字
|- cover object 文章封面
|---- type number 封面的数量,可选值:0、1、3
|---- images array 文章封面图片的 URL 数组

7. 封装utils目录下的request模块

安装axios

npm i axios -S

封装axios的原理

vue2案例--类似今日头条新闻浏览_第6张图片

创建src/utils/request.js

import axios from 'axios'

const request = axios.create({
  // 指定请求的根路径
  baseURL: 'https://www.escook.cn'
})

export default request

8.在Home组件中封装initArticleList方法

一进入Home组件就要发请求,来拿第一页数据,一般来说是在created里面来调函数,发起请求。

但是,我们先不要写created,先封装一个methods来调接口拿数据:


// 导入 request.js
import request from '@/utils/request.js'
export default {
  name: 'Home',
  data () {
    return {
      // 页码值
      page: 1,
      // 每页显示多少条数据
      limit: 10
    }
  },
  methods: {
    // 封装获取文章列表数据的方法
    async initArticleList () {
      // 发起 GET请求,获取文章的列表数据
      const { data: res } = await request.get('/articles', {
        // 请求参数
        params: {
          _page: this.page,
          _limit: this.limit
        }
      })
      console.log(res)
    }
  },
  created () {
    this.initArticleList()
  }
}

获取到了数据:
vue2案例--类似今日头条新闻浏览_第7张图片

9. 封装 articleAPI 模块

现有这样一个需求:我希望一进入User组件时,也会发起axios请求来获取图书列表,但我希望一次只请求5条数据,即把limit改成5即可

  • 一般方法的话,就是在User.vue中写和之前Home.vue大体一样的代码。
  • 那如果还有一个页面也要调这个接口呢?
  • 可以会发现代码冗余,因此要把代码复用起来

思路

vue2案例--类似今日头条新闻浏览_第8张图片

开始封装

  1. 创建src/api 文件夹,里面存着所有的api接口,有一个文件是articleAPI.js文章相关的API都封装到这个模块中
// 文章相关的 API 接口,都封装到这个模块中
import request from '@/utils/request.js'
// 向外按需导出一个 API 函数
export const getArticleListAPI = function (_page, _limit) {
  return request.get('/articles', {
    // 请求参数
    params: {
      _page,
      _limit
    }
  })
}
  1. 在Home组件中调用这个api接口,User组件同理
// 按需导入 API 接口
import { getArticleListAPI } from '@/api/articleAPI.js'

export default {
  name: 'Home',
  data () {
    return {
      // 页码值
      page: 1,
      // 每页显示多少条数据
      limit: 10
    }
  },
  methods: {
    async initArticleList () {
      const { data: res } = await getArticleListAPI(this.page, this.limit)
      console.log(res)
    }
  },
  created () {
    this.initArticleList()
  }
}

总结:

今后,如果需要调接口来获取用户相关的信息,则在src/api文件夹下新建一个模块专门来定义用户的api如userAPI.js

vue2案例--类似今日头条新闻浏览_第9张图片

10. 封装 ArticleInfo 组件

ArticleInfo组件是可复用的组件,放在components文件夹中

请求回来的数据转存到了data()里面,供我们渲染页面时去使用vue2案例--类似今日头条新闻浏览_第10张图片

渲染页面


    <ArticleInfo v-for="item in artlist" :key="item.id">ArticleInfo>

为ArticleInfo 组件封装 props 属性

  1. 使用 ArticleInfo 组件

    
    
    <ArticleInfo v-for="item in artlist" :key="item.id" :title="item.title" :author="item.aut_name"
     :cmt-count="item.comm_count" :time="item.pubdate">ArticleInfo>
  1. ArticleInfo.vue 中:
export default {
  name: 'ArticleInfo',
  // 自定义属性
  props: {
    // 标题
    title: {
      type: String,
      default: null
    },
    // 作者名字
    author: {
      type: String,
      default: null
    },
    // 评论数
    cmtCount: {
      // 通过数组形式, 为当前属性定义多个可能的类型
      type: [Number, String],
      default: 0
    },
    time: {
      type: String,
      default: null
    }
  }
}

为ArticleInfo 组件封装 cover 属性

        
             
           
 // 封面的信息对象
    cover: {
      type: Object,
      // 通过default函数返回cover属性的默认值
      default: function () {
        return { type: 0 }
      }
    }

11. 实现上拉加载更多

需要用到 Vant 提供的组件 — List

List 组件通过 loading 和 finished 两个变量控制加载状态,当组件滚动到底部时,会触发 load 事件并将 loading 设置成 true。此时可以发起异步操作并更新数据,数据更新完毕后,将 loading 设置成 false 即可。若数据已全部加载完毕,则直接将 finished 设置成 true 即可。

export default {
  name: 'Home',
  components: {
    ArticleInfo
  },
  data () {
    return {
      // 页码值
      page: 1,
      // 每页显示多少条数据
      limit: 10,
      // 文章列表数组
      artlist: [],
      // 是否正在下一页数据,如果loading为true,则不会反复触发onload事件
      // 每当下一页数据请求回来之后,千万要记得 ,把loading 从 true 改为 false
      loading: true,
      // 所有数据是否加载完毕,如果没有更多数据了,要把finished改成true
      finished: false
    }
  },
  methods: {
    async initArticleList () {
      // 返回值 res 就是一个数组
      const { data: res } = await getArticleListAPI(this.page, this.limit)
      // 如果是上拉加载更多,那么应该是:
      // this.artlist=[旧数据在前,新数据在后]
      this.artlist = [...this.artlist, ...res]
      // 当第一页数据请求回来之后把 loading 改为 false
      this.loading = false
      if (res.length === 0) {
        // 证明没有下一页数据了,直接把 finished 改为true,表示数据加载完了!
        this.finished = true
      }
    },
    // 只要onload 被调用,就应该请求下一页数据
    onLoad () {
    // 1.让页码值 +1
      this.page++
      // 2. 重新请求接口获取数据
      this.initArticleList()
    }
  },
  created () {
    this.initArticleList()
  }
}

12. 实现下拉刷新功能

下拉刷新时会触发 refresh 事件,在事件的回调函数中可以进行同步或异步操作,操作完成后将 v-model 设置为 false,表示加载完成。

export default {
  name: 'Home',
  components: {
    ArticleInfo
  },
  data () {
    return {
      // 页码值
      page: 1,
      // 每页显示多少条数据
      limit: 10,
      // 文章列表数组
      artlist: [],
      // 是否正在下一页数据,如果loading为true,则不会反复触发load事件
      // 每当下一页数据请求回来之后,千万要记得 ,把loading 从 true 改为 false
      loading: true,
      // 所有数据是否加载完毕,如果没有更多数据了,要把finished改成true
      finished: false,
      // 是否正在下拉刷新
      isLoading: false
    }
  },
  created () {
    this.initArticleList()
  },
  methods: {
    async initArticleList (isRefresh) {
      // 返回值 res 就是一个数组
      const { data: res } = await getArticleListAPI(this.page, this.limit)
      if (isRefresh) {
        // 下拉刷新: 新数据在前,新数据在后
        this.artlist = [...res, ...this.artlist]
        this.isLoading = false
        // 当
      } else {
        // 上拉加载更多:旧数据在前,新数据在后
        this.artlist = [...this.artlist, ...res]
        // 当第一页数据请求回来之后把 loading 改为 false
        this.loading = false
      }
      if (res.length === 0) {
        // 证明没有下一页数据了,直接把 finished 改为true,表示数据加载完了!
        this.finished = true
      }
    },
    // 只要onload 被调用,就应该请求下一页数据
    onLoad () {
    // 1.让页码值 +1
      this.page++
      // 2. 重新请求接口获取数据
      this.initArticleList()
    },
    // 下拉刷新的处理函数
    onRefresh () {
      // 1. 要页码值 +1
      this.page++
      // 2. 重新请求接口,获取数据
      this.initArticleList(true)
    }
  }
}

13. 定制主题

Vant定制主题的核心原理

该项目的标题“黑马头条" 默认是白色背景,我们是通过 /deep/ 深度选择器再结合审查元素找到了类名进行覆盖

这个方法有一个缺点:如果另一个页面,如用户页面,也有这个标题,那么需要重复这种方法,不然样式仍然是默认的。

因此我们使用 定制主题 这个方法

  1. 引入样式源文件,在main.js 中进行如下修改:

vue2案例--类似今日头条新闻浏览_第11张图片

  1. 如果 vue-cli 搭建的项目,可以在 vue.config.js 中进行配置:
// 这个文件是 vue-cli 创建出来的 项目的 配置文件
// 在 vue.config.js 这个配置文件中,可以对整个项目的打包、构建进行全局性的配置
// webpack 在进行打包的时候,底层用到的是 node.js
// 因此,在 vue.config.js 配置文件中,可以导入并使用 node.js 中的核心模块
const path = require('path')
const themePath = path.join(__dirname, './src/theme.less')
module.exports = {
  css: {
    loaderOptions: {
      less: {
        // 若 less-loader 版本小于 6.0,请移除 lessOptions 这一级,直接配置选项。
        modifyVars: {
          // 可以通过 less 文件覆盖(文件路径为绝对路径)
          // 从 盘符 开始的路径叫做绝对路径
          hack: `true; @import "${themePath}";`
        }
      }
    }
  }
}

vue2案例--类似今日头条新闻浏览_第12张图片
4.上面的配置文件中的less变量在Vant 官网看:

vue2案例--类似今日头条新闻浏览_第13张图片

14. 打包

下面介绍打包完成后能双击 dist/index.html 来打开项目,需要配置 vue.config.js:
vue2案例--类似今日头条新闻浏览_第14张图片

然后在终端运行:

npm run build

你可能感兴趣的:(vue2,案例,前端,vue.js,javascript)