基于 “vue、UI组件库” 打造网易新闻应用

一、项目创建与启动

  • 安装vue-cli : vue init webpack vue-example

二、功能需求分析

  • 头部
  • 顶部Tab导航
  • 幻灯片呢
  • 新闻列表
    1. 下拉刷新
    2. 上拉加载更多
  • 底部导航

三、Vux(UI组件库)

注:[可参考此文章](https://www.cnblogs.com/zy-review/p/7151938.html

基于webpack+vue-loader+vux可以快速开发移动端页面,配合vux-loader方便你在WeUI的基础上定制需要的样式。
vux-loader保证了组件按需使用,因此不用担心最终打包了整个vux的组件库代码。

  • 安装

    • npm i -S vux
      npm i -D less less-loader(需要配置后缀,base.conf.js)
extensions: ['.js', '.vue', '.json','.less']
  • 报错(基础差劲的我解决了一天呵呵呵)

屏幕快照 2018-02-21 下午9.12.10.png

解决

  1. 安装vux-loader : npm install vux-loader --save-dev
  2. 配置build/webpack.base.conf.js,如下:
  • API:
const vuxLoader = require('vux-loader')
const webpackConfig = originalConfig // 原来的 module.exports 代码赋值给变量 webpackConfig

module.exports = vuxLoader.merge(webpackConfig, {
  plugins: ['vux-ui']
})
屏幕快照 2018-02-21 下午11.46.41.png
  • Vue组件库

    • 组件分类
      • 功能型
      • UI型
      • 混合型
  • 组件基本使用

    • 四大要素
      • Props(属性)
    <x-header
          title="网易"
          :left-options="{showBack:true,backText:'back'}"
    ></x-header>
    
    • Slots(插槽)
    <x-header
         :left-options="{showBack:true,backText:'back'}"
     >
         //插槽:比title便于管理、编写
         <div>网易</div>
       </x-header>
    
    • Events
    • Methods
  • 组件内导入方法

//烤串
 <view-box></view-box>
//导入组件(驼峰)
 import { ViewBox,XHeader } from 'vux';
 export default {
  name: 'App',
  components: {
  //注册组件
    ViewBox,
    XHeader
  }
}

实现步骤

1. 制作整体布局:布局组件-ViewBox(该组件为100%高布局)

  - 介绍
    - 该组件为vux的基本布局容器,建议其他组件包含在该组件内部使用。
  - 导入
    - import {ViewBox } from 'vux';
    - @import '~vux/src/styles/reset.less'  (样式重置,可直接在style标签导入)
  - 注意:此处导入的是less,所以style标签必须加lang属性,值为less
<view-box></view-box>
<style lang="less">
  @import '~vux/src/styles/reset.less';
</style>

2. 制作顶部:布局组件-XHeader

- 介绍
    - 顶部组件
- 导入
    - import {XHeader} from 'vux'

(现在程序终于跑起来了,在此之前我调了好久原因就是配置错了,详细的的解决已在上面备注了~)
- 在index.html中设置meta标签

//将这个顶部部导航作为view-box的插槽
  <x-header
    slot="header"
    :left-options="{showBack:false,backText:'back'}"
  >
    <div slot="left">直播</div>
    <div>网易</div>
    <div slot="right">搜索</div>
</x-header>

3.制作底部导航:底部导航组件-Tabbar,TabbarItem

    - 介绍
        - 底部切换导航组件
    - 导入
        - import {Tabbar,TabbarItem} from 'vux'
//将这个底部导航作为view-box的插槽
 <tabbar slot="bottom">
  <tabbar-item>
    <img src="./assets/icon_nav_button.png" slot="icon" alt="">
      <span slot="label">首页</span>        
  </tabbar-item>
  <tabbar-item>
    <img src="./assets/icon_nav_article.png" slot="icon" alt="">
    <span slot="label">推荐</span>        
  </tabbar-item>
  <tabbar-item>
    <img src="./assets/icon_nav_msg.png" slot="icon" alt="">
    <span slot="label">我的</span>        
  </tabbar-item>
</tabbar>
屏幕快照 2018-02-22 上午1.22.28.png

4.制作tab切换:组件-Tab、TabItem

  - 介绍
    - tab组件
  - 导入
    - import {Tab,TabItem} from 'vux'
      - 设置容器div.my-tab
      - TabItem的selected属性
<tab class="tab">
        //selected : 默认选中
        <tab-item selected>推荐</tab-item>
        <tab-item>要闻</tab-item>
        <tab-item>游戏</tab-item>
        <tab-item>科技</tab-item>
        <tab-item>娱乐</tab-item>
        <tab-item>体育</tab-item>
</tab>
//设置宽度之后,会自动计算,为每个元素自动分配
.tab{
    width:600px;
}

5.为tab选项卡添加自动回弹效果:组件-Scroller

    - 介绍
        - 自定义滚动组件
    - 导入
        - import {Scroller} from 'vux'
            - :lock-y/x='true' (锁定X/Y轴是否可以拖拽)
  //soroller组件外面必须包div
     <scroller :lock-y="true" >
        <div class="tab">
          <tab>
            <tab-item selected>推荐</tab-item>
            <tab-item>要闻</tab-item>
            <tab-item>游戏</tab-item>
            <tab-item>科技</tab-item>
            <tab-item>娱乐</tab-item>
          <tab-item>体育</tab-item>
          </tab>
        </div>
      </scroller>

6.添加轮播图:组件-Swiper

    - 介绍
        - 轮播图组件
    - 导入
        - import {Swiper} from 'vux'
            - 设置数据: :list='slideData'
            - 设置当前显示项 :v-model='slideIndex'
  <swiper 
        :list='swiperList'  //绑定数据(图片,图片信息等)
        v-model="swiperIndex"
        :loop='true'  //设置无缝滚动
      >
  </swiper>
  data() {
    return {
      swiperList: [
        {
          url: "javascript:",
          img: "https://static.vux.li/demo/1.jpg",
          title: "送你一朵fua"
        },
        {
          url: "javascript:",
          img: "https://static.vux.li/demo/2.jpg",
          title: "送你一辆车"
        },
        {
          url: "javascript:",
          img: "https://static.vux.li/demo/5.jpg",
          title: "送你一次旅行",
          fallbackImg: "https://static.vux.li/demo/3.jpg"
        }
      ],
      //设置默认显示第几个
      swiperIndex:1
    };
  }

6.制作跑马灯新闻效果:组件-Marquee,MarqueeItem

    - 介绍
        - 滚动(跑马灯)组件
    - 导入
        - import {Marquee,MarqueeItem} from 'vux'
        - 通过v-for指令设置item
<marquee class="my-marquee">
        <marquee-item>111</marquee-item>
        <marquee-item>222</marquee-item>
        <marquee-item>333</marquee-item>
</marquee>

7.制作图文列表 : 组件-Panel

    - 介绍
        - 图文列表组件
    - 导入
        - import {Panel} from 'vux'
            - 设置数据: :list='list'
            - 设置样式: class='panel-list'
  <panel
    :list='dataList'
  >
  </panel>
屏幕快照 2018-02-22 下午10.32.35.png

8.获取远程数据

  接口
    - 首屏推荐新闻数据
      http://3g.163.com/touch/jsonp/sy/recommend/0-9.html
     (点击network => preview,这样就格式化显示数据,foucs(焦点图)和list(首屏新闻)
    - 推荐下拉刷新
      http://3g.163.com/touch/jsonp/sy/recommend/0-9.html
        - miss : '00'
        - refresh : ['A','B01','B02','B03','B04','B05','B06','B07','B08','B09','B10']
                  每次切换这个数组项,确保每次拿到不同的数据
    - 推荐新闻更多数据
        - http://3g.163.com/touch.jsonp/sy/recommend/'+start结束(开始)+'-'+end()+'.html'

数据交互 - vue-jsonp

    - 插件介绍
        - https://www.npmjs.com/package/vue-jsonp
        - 安装:npm i -S vue-jsonp
    - 导入(在main.js入口文件中)
        - import VueJsonp from 'vue-jsonp'
        - Vue.use(VueJsonp)
    - 使用
        - 组件中 : this.$jsonp(请求地址,请求对象,返回promise对象)
1.首屏加载

过程分析 : 在我们的应用当中,首先第一次加载的时候,组件创建的时候(creat钩子),就会发送第一个请求,请求到首屏幻灯片数据和新闻列表数据。
注: 当组件创建的时候,creat就会执行。
此处学到一个新的知识点运用:当拿到数据后,可以先用filter过滤出自己想要的数据,然后再用map方法映射出一个自己需要的数据格式。

  created () {
        //首屏轮播图数据,请求成功之后填充swiperList对象,过滤,只要null
        /* 
        {
           url: "javascript:",
           img: "https://static.vux.li/demo/1.jpg",
           title: "送你一朵fua"
        }
        */
//先过滤需要的数据,然后map映射出需要的数据格式
        this.$jsonp('http://3g.163.com/touch/jsonp/sy/recommend/0-9.html').then(data=>{
          this.swiperList = data.focus.filter( item => {
            return item.addata === null
          }).map(item=>{
            return {
              url : item.link,
              img : item.picInfo[0].url,
              title : item.title
            }
          })
        })
  }
 //首屏新闻列表的数据,拿list的数据
        this.$jsonp('http://3g.163.com/touch/jsonp/sy/recommend/0-9.html').then(data=>{
          this.dataList = data.list.map( item=> {
            return {
              src:item.picInfo[0].url,
              title:item.title,
              desc:item.digest,
              url: item.link
            }
          })
         })
//滚动新闻
        this.$jsonp('http://3g.163.com/touch/jsonp/sy/recommend/0-9.html').then(data=>{
          this.marquee = data.live.map( item=> {
            return {
              title:item.title,
              url: item.link
            }
          })
        })
可以看到,新闻列表的样式需要调整
2.下拉刷新

第三方组件 : vue-scroller

   - 介绍
      - 自定义滚动条刷新加载组件
        - https://www.npmjs.com/package/vue-scroller
   - 安装
      - npm i vue-scroller -S
  <!-- 内容区域,用vue-scroller组件包起来 -->
      <scroller 
        class="my-scroller" 
        :on-refresh="refresh"
        :on-infinite="infinite">
        <!-- 轮播图 -->
        <swiper 
          :list='swiperList'
          v-model="swiperIndex"
          :loop='true'
          ref="myRef"
        >
        </swiper>
        <!-- 滚动新闻 -->
        <marquee class="my-marquee">
          <marquee-item v-for="item in marquee">
            <a :href="item.url"> {{item.title}}</a>
          </marquee-item>
        </marquee>
        <!-- 新闻列表 -->
        <panel
          :list='dataList'>
        </panel>
      </scroller>
     methods: {
    //下拉数据加载 : 新闻列表
    refresh(){
      this.$jsonp('http://3g.163.com/touch/jsonp/sy/recommend/0-9.html',{
        miss : '00',
        refresh : getRefreshKey()
      }).then(data=>{
       this.dataList = data.list.map( item=> {
            return {
              src:item.picInfo[0].url,
              title:item.title,
              desc:item.digest,
              url: item.link
            }
        })
        //**停止下拉刷新**
        this.$refs.myRef.finishPullToRefresh()
      })
    },
    //上拉数据加载
    infinite(){
    
    }
  }
2.上拉加载更多

这里注意:不是副高之前的新闻列表,而是需要和之前的拼接起来。比如新建一个数组,然后新建一个新闻列表标签,将新获取的数据添加进去。

methods: {
    //下拉数据加载 : 新闻列表
    refresh(){
      getRefreshKey();//对key自增
      this.$jsonp('http://3g.163.com/touch/jsonp/sy/recommend/0-9.html',{
        miss : '00',
        refresh : keyValue
      }).then(data=>{
        
       this.dataList = data.list.filter(item => {
         return item.addata === null && item.picInfo[0]
       }).map( item=> {
            return {
              src:item.picInfo[0].url,
              title:item.title,
              desc:item.digest,
              url: item.link
            }
        })
        //停止下拉刷新
        this.$refs.myRef.finishPullToRefresh()
        //this.$vux.toast.text('hello', 'center')
        this.$vux.toast.show({
          text: '加载成功'
        })

      })
    },
    //加载更多
    infinite(){
      if(!initLoaded){
        this.$refs.myRef.finishInfinite()
        return
      }
  
      this.$jsonp(`http://3g.163.com/touch/jsonp/sy/recommend/${start}-${end}.html`,{
        miss : '00',
        refresh : keyValue
      }).then(data=>{
       
        var dataList = data.list.filter(item => {
         return item.addata === null && item.picInfo[0]
       }).map( item=> {
            return {
              src:item.picInfo[0].url,
              title:item.title,
              desc:item.digest,
              url: item.link
            }
        })
        this.moreDataList = this.moreDataList.concat(dataList)
        //第二批数据加载
        start += 10;
        end = start + 9;
        this.$refs.myRef.finishInfinite()
      })
    }
  }

总结

  • 1.上拉下拉加载更多,主要用到是第三方组件(自定义滚动条刷新加载组件) : vue-scroller
<scroller 
  //下拉 : refresh里请求一次接口
  :on-refresh="refresh"
 //上拉 : infinite方法里请求一次接口
  :on-infinite="infinite">
  <!-- content goes here -->
</scroller>

遇到类似需求,首先需要明白上拉下拉的时候请求数据,然后在下拉的时候是不是覆盖之前的数据,而是拼接。

  • 2.新学到的知识点。
    如果拿到一串数据,用这个数据生成自己想要的格式 : 首先用filter过滤数据,然后用map方法映射一个新的数据。
  • 3.遇到的技术难点
    3-1 :上拉下拉刷新的时候,数据出来了,但是loading图片没有消失,原因是:需要调用this.$refs.myRef.finishInfinite(),表示已经结束请求。

推荐阅读更多精彩内容