6

写在文章前:最近把官网的vue文档过了一遍,准备写个项目来巩固下自己对vue的学习。因为cnode网站有开放的api,所以我决定用vue+webpack+es6+sass的技术栈去实现这个网站(单页面的形式)。这篇系列的文章我主要是分享下自己怎么开发还有怎么实现一个个vue组件去构建整个网站。关于webpack配合vue的使用可以关注我的另外一篇博文webpack+vue配置,感谢Cnode网站提供的开放API。

建议阅读前准备内容

1. 构建我们的项目目录

├── README.md          
├── index.html         // 项目入口文件
├── package.json       // 项目配置文件
├── src                // 生产目录
│   ├── vue            // 组件
│   |    ├──about.vue
│   |    ├──artlist.vue
│   |    ├──article.vue
│   |    ├──login.vue
│   |    ├──loading.vue
│   |    ├──search.vue
│   ├── components     // 各种子组件
│   |    ├──header.vue
│   |    ├──returnTop.vue
│   |    ├──menu.vue
│   ├── js             // 外部引入的js文件
│   ├── scss           //scss文件
│   ├── img           //图片文件
│   ├── filters.js     //过滤器
│   └── main.js        // Webpack 预编译入口    
└── webpack.js          // Webpack 配置文件

2.今天要实现的一个效果

图片描述

在上面的gif动画中我们总共看到了几个页面

  • loading.vue(首页过渡加载)

  • artlist.vue(列表展示页)
    几个组件

  • header.vue(头部)

  • meun.vue(菜单栏)

  • returnTop.vue(返回顶部)

在正式内容开始前先简单的说下,我们看到的一个页面是由各个组件组成的,而我们可以把页面拆分成一个各个组件,每个组件单独一个文件,组件的结构是这样的,避免内容过多下面讲到的组件我都不写style,具体代码开源在了 github上,有兴趣的可以去看下。

<template>
    <!--html结构-->
</template>
<script>
    //js
</script>
<style>
    //style
</style>

3.具体页面开发

3.1首页过度也难loading.vue

我们要实现的是一个loading图等待2秒进入artlist列表页

<template>
     <div>
          <img class="loading" src="../img/loading.gif" alt="">
     </div>
</template>
<script>
     export default {
          ready : function() {
               setTimeout(() => {
                    this.$route.router.go({name : 'artlist'});
               }, 2000);
          }
     }
</script>

3.1主题列表页artlist.vue

我们的列表页的结构是这样的:

<template>
     <nv-header></nv-header>
     <div class="artlist">
          <ul class="artlistTab clearfix">
               <li v-for="item in itemTab" :class="{'on':initIndex === $index}" v-on:click="changeTab($index)">{{item.title}}</li>
          </ul>
          <div class="artlistCon">
               <div v-for="art in artlist" class="artitem clearfix" v-link="{name:'article',params:{id:art.id}}">
                    <a class="avatar" href="javascript:void(0);">
                         <img :src="art.author.avatar_url" :alt="art.author.loginname">
                    </a>
                    <div class="art-inf">
                         <p class="title">{{art.title}}</p>
                         <span>{{art.reply_count}}/{{art.visit_count}}</span>
                         <span>{{art.create_at | getDateTime }}</span>
                    </div>
               </div>
          </div>
     </div>
     <nv-top></nv-top>
</template>

tab主题导航的渲染
我们把列表的导航加载进来,官方API的有主体分类ask,share,job,good
所以得出我们的数据itemTab。

itemTab : [
      {'title' : '全部', 'type' : 'all'},
      {'title' : '精华', 'type' : 'good'},
      {'title' : '分享', 'type' : 'share'},
      {'title' : '问答', 'type' : 'ask'},
      {'title' : '招聘', 'type' : 'job'}
]

然后在定义一个输出请求接口的对象:

searchKey : {
     page : 1,
     limit : 20, //每页加载20条
     tab : 'all' //主题 有all ask share job good
}

顺便再定义哥artilist[]空数组来存放等下取出来的数据。

我们要先定义拉取数据的方法函数,我们把拉取到的数据列表放在我们先前定义的artlist[]数组里面,利用vue的双向绑定的特性配合v-for我们就可以把我们的列表页的主题内容渲染出来了。

//获取数据方法
gerArtlist : function() {
    let rqdata = $.param(this.searchKey);
    $.get('https://cnodejs.org/api/v1/topics?' + rqdata, (data) => {
         if(data.success){
              this.artlist = data['data'];
              this.scroll = true;
         }
    })

}
页面刚打开的时候我们要去取第一次的数据

ready : function() {
   this.gerArtlist(this.initIndex);
 });

切换主题的时候我们要给每个item绑定一个事件changeTab($index),利用$index这个索引,改变我们this.searchKey.tab在去请求数据

// 标签tab切换方法
changeTab : function(index) {
    this.initIndex = index;
    this.searchKey.tab = this.itemTab[index].type;
    this.artlist = [];
    this.searchKey.limit = 20;
    this.gerArtlist(this.initIndex);
}

我们设置的是当前页面打开的时候加载了20条数据,现在我们要实现下拉,超过了一定的区域在去请求下一个20条的内容,就是改变searchKey.limit,每次触发下拉条件就叠加20.

// 超过滚动获取数据方法
scrollArtlist : function() {
    if(this.scroll){
         let totalheight = parseFloat($(window).height()) + parseFloat($(window).scrollTop());
         if ($(document).height() <= totalheight + 200) {
             this.scroll = false;
             this.searchKey.limit += 20;
             this.gerArtlist();
         }
    }
}

在ready里面绑定下scroll

ready : function() {
       $(window).on('scroll',() => {
        this.scrollArtlist();
 });

3.2返回顶部组件
在我们的列表页引入返回顶部组件和头部组件作为子组件

components : {
    'nv-header' : require('../components/header.vue'),
    'nv-top' : require('../components/returnTop.vue')
}

返回顶部组件returnTop.vue

<template>
    <div class="return-top" v-show="showTop" v-on:click="returnTop"></div>
</template>
<script>
    export default {
        data : function() {
            return {
                showTop : false
            }
        },
        ready : function() {
            $(window).on('scroll', () => {
                if($(window).scrollTop() > 150){
                    this.showTop = true;
                }else{
                    this.showTop = false;
                }    
            })
        },
        methods : {
            returnTop : function() {
                $(window).scrollTop(0);
                this.showTop = false;
            }
        }
    }
</script>

3.3头部组件

<template>
    <!-- 遮罩层 -->
    <div class="page-cover"  v-show="coverShow" v-on:click="hideMenu"></div>
    <!-- 头部 -->
    <div class="header">
        <span class="left-menu" v-on:click="showMenu"></span>cnode.js
    </div>
    <nv-menu :showm="menuShow"></nv-menu>
</template>
<script>
    export default {
        data : function() {
            return {
                coverShow : false,
                menuShow : false
            }
        },
        methods : {
            showMenu : function() {
                this.coverShow = true;
                this.menuShow = true;
            },
            hideMenu : function() {
                this.coverShow = false;
                this.menuShow = false;
            }
        },
        components : {
            'nv-menu' : require('./menu.vue')
        }
    }
</script>

在我们的header组件中我们引入了一个menu组件,props : ['showm']利用父子组件间的通信,给meun绑定了个:class="{'showMeun':showm}"利用css3来实现过渡

<template>
    <div class="meun" :class="{'showMeun':showm}">
        <ul>
            <li v-link="{name:'home'}">首页</li>
            <li v-link="{name : 'search'}">搜索</li>
            <li v-link="{name : 'login'}">登录</li>
            <li v-link="{name : 'login'}">注册</li>
            <li v-link="{name : 'about'}">关于</li>
        </ul>
    </div>
</template>
<script>
    export default {
        props : ['showm']
    }
</script>
<style lang="sass">
    .meun {
        position: fixed;
        top: 0px;
        left:-200px;
        width: 200px;
        height: 100%;
        background: #444444;
        transition: all .3s ease;
        z-index: 99;
        ul {
            padding-top: 3rem;
            li {
                color: #fff;
                padding: 16px 0;
                text-align: left;
                text-indent: 10px;
                line-height: 20px;
                font-size: 20px;
                margin: 0 25px;
            }
        }
    }
    .showMeun {
        transform: translateX(200px);
    }
</style>

结束语

由于是空闲的时间做的,所以只实现了部分功能,后面会继续完善,源码已经放在github


cwsjoker
433 声望45 粉丝

摸爬滚打,我是程序的搬运工。