写在文章前:最近把官网的vue文档过了一遍,准备写个项目来巩固下本身对vue的学习。由于cnode网站有开放的api,因此我决定用vue+webpack+es6+sass的技术栈去实现这个网站(单页面的形式)。这篇系列的文章我主要是分享下本身怎么开发还有怎么实现一个个vue组件去构建整个网站。关于webpack配合vue的使用能够关注个人另一篇博文webpack+vue配置,感谢Cnode网站提供的开放API。javascript
单页面应用css
路由vue-router文档html
├── 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 配置文件
在上面的gif动画中咱们总共看到了几个页面java
loading.vue(首页过渡加载)node
artlist.vue(列表展现页)
几个组件webpack
header.vue(头部)css3
meun.vue(菜单栏)git
returnTop.vue(返回顶部)es6
在正式内容开始前先简单的说下,咱们看到的一个页面是由各个组件组成的,而咱们能够把页面拆分红一个各个组件,每一个组件单独一个文件,组件的结构是这样的,避免内容过多下面讲到的组件我都不写style,具体代码开源在了 github上,有兴趣的能够去看下。
<template> <!--html结构--> </template> <script> //js </script> <style> //style </style>
咱们要实现的是一个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>
咱们的列表页的结构是这样的:
<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