寫在文章前:最近把官網的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