老規矩放上大大的github開源地址:https://github.com/goodheart222/vuepro
咱們再來看看項目的效果,初步根據效果作到心中有數
看到效果的話,咱們會發現,確定是有路由切換,懶加載,後端交換數據這些
一塊兒分析代碼
main.js入口文件,引用了vue-lazyload懶加載的方式加載圖片css
//main.js import Vue from 'vue' import App from './App' import router from './router' //引入圖片懶加載模塊 import VueLazyload from 'vue-lazyload' //懶加載配置 Vue.use(VueLazyload, { preLoad: 1.3, error: require('../static/images/mo.jpg'), loading: require('../static/images/minloading.gif'), attempt: 1 }) Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, render: h => h(App) })
App.vue中的代碼寫的很高級啊,就是你會想象不到,竟然能夠這樣寫出來,做者大大功力很深啊
下面的tab切換是直接寫在router-link中的,還有切換中顏色的改變,頗有意思啊html
//app.vue <template> <div id="app"> <nav class="logo"> <img src="../static/images/cnodejs_light.svg"/> <div class="input"> <span class="iconfont icon-gouwuche"></span> <input type="text" /> </div> </nav> <!-- tab切換部分寫在了App.vue中,有意思 並且還添加了tag有意思--> <nav class="bottom"> <ul> <router-link to="/index" tag="li" :class="res=='index'?'selected':''">首頁</router-link> <router-link to="/me" tag="li" :class="res=='me'?'selected':''">關於咱們</router-link> <router-link to="/login" tag="li" :class="res=='login'?'selected':''">登陸</router-link> </ul> </nav> <router-view/> <!--{{res}}--> </div> </template> <script> export default { name: 'App', computed:{ res:function(){ var arr = this.$route.path.split('/'); return arr[1]; } }, mounted:function(){ var div1=document.getElementsByClassName('input')[0]; var input1=document.getElementsByTagName('input')[0]; input1.onfocus=function(){ this.style.background='#fff'; div1.style.background='#fff'; } input1.onblur=function(){ this.style.background='#888'; div1.style.background='#888'; } } } </script> <style lang="scss"> @import './assets/sass/base.scss'; nav.logo{ width:rem(730px); height:rem(160px); background: #444; margin:0 auto; padding-top:rem(10px); img{ display: block; width:rem(243px); margin:0 auto; } div.input{ width:rem(470px); height:rem(54px); border-radius: rem(30px); background: #888; margin:rem(20px) auto 0; display: flex; align-items: center; padding-left:rem(15px); span{ font-size: rem(40px); font-weight: bold; color:#5c5c5c; } input{ background: transparent; height:98%; border-radius: 0 rem(10px) rem(10px) 0; border:none; font-size: rem(34px); } } } nav.bottom{ width:100%; height:rem(80px); background: #8cba48; position: fixed; bottom: 0; left:0; ul{ width:100%; height:rem(80px); display: flex; li{ font-size: rem(38px); width:33.33%; height:100%; line-height: rem(80px); text-align: center; color:#fff; } .selected{ background: #009606; } } } </style>
//src\router\index.js import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' import Index from '@/components/Index' import Me from '@/components/Me' import Login from '@/components/Login' //主題組件 import All from '@/components/topics/All' import Ask from '@/components/topics/Ask' import Share from '@/components/topics/Share' import Job from '@/components/topics/Job' import Good from '@/components/topics/Good' import Test from '@/components/topics/Test' import Detail from '@/components/topics/Detail' Vue.use(Router) export default new Router({ routes: [ { path: '/index', name: 'Index', component: Index, children:[ { path:'/', component:All }, { path:'good', component:Good }, { path:'ask', component:Ask }, { path:'share', component:Share }, { path:'test', component:Test }, { path:'job', component:Job }, { path:'detail/:id', component:Detail }, ] }, { path: '/me', name: 'Me', component: Me }, { path: '/login', name: 'Login', component: Login }, { path:'/*', redirect:'/index' } ] })
跟後端請求接口的文件也寫的很高級,做者的功力很深厚vue
//src\getdata\topic.js //引入axios模塊 import axios from 'axios'; //基本配置,建立axios對象 var $http = axios.create({ baseURL: 'https://cnodejs.org/api/v1', //timeout: 1000, headers: {'X-Custom-Header': 'foobar'} }); //獲取欄目列表 function getItemList(options){ // console.log(options); //設置默認參數,Object.assign是對象屬性的合併,權重大的放在後面。例如options var newOptions=Object.assign({ page:1, limit:9 },options) return $http({ method: 'get', //具體的地址 url: '/topics', params:newOptions }) } //獲取文章 function getArticle(id){ return $http.get('/topic/'+id) } //向外暴露,主要是暴露axios對象 export {getItemList,getArticle}
接下來咱們分析頁面
node
//src\components\Index.vue <template> <div class="index"> <nav class="top"> <ul> <router-link to="/index/" tag="li" :class="(res==''||res==undefined)?'bj':''">所有</router-link> <router-link to="/index/good" tag="li" :class="res=='good'?'bj':''">精華</router-link> <router-link to="/index/share" tag="li" :class="res=='share'?'bj':''">分享</router-link> <router-link to="/index/ask" tag="li" :class="res=='ask'?'bj':''">問答</router-link> <router-link to="/index/job" tag="li" :class="res=='job'?'bj':''">招聘</router-link> <router-link to="/index/test" tag="li" :class="res=='test'?'bj':''">測試</router-link> </ul> </nav> <!--{{res}}--> <router-view/> </div> </template> <script> export default { name: 'Index', data () { return { msg: 'Welcome to Your Vue.js App' } }, //計算屬性 computed:{ res:function(){ var arr=this.$route.path.split('/'); console.log(arr[2]); return arr[2]; } }, // 這個時候用這個是什麼意思? mounted:function(){ var swiper = new Swiper('.swiper-container', { // 顯示 slide 的個數 slidesPerView: 5, spaceBetween: 15, }); } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> @import '../assets/sass/base.scss'; nav.top{ width:rem(730px); height:rem(70px); background: #f6f6f6; border-radius: rem(15px) rem(15px) 0 0; margin:rem(40px) auto 0; ul{ display:flex; width:100%; height: 100%; align-items: center; justify-content: space-around; li{ font-size: rem(34px); color:#90b910; } .bj{ background: #8dbd3e; color:#fff; padding:rem(5px) rem(10px); border-radius:rem(10px) } } } </style>
//src\components\topics\Good.vue <template> <div class="good quan"> <!--1--> <topic-list :items="items"></topic-list> <!--分頁--> <infinite-loading @infinite="infiniteHandler" v-if="isLoadingShow" class="box"></infinite-loading> </div> </template> <script> //引入axios模塊 //import axios from 'axios'; //引入取數據函數 import {getItemList} from '@/getdata/topic.js'; //二、引入公共的主題列表組件 import topicList from '@/components/topics/Topiclist'; //引入分頁組件 import InfiniteLoading from 'vue-infinite-loading'; export default { name: 'Good', data () { return { items:[], //控制圓圈是否顯示 isLoadingShow:true, page:1 } }, methods: { infiniteHandler($state) { setTimeout(() => { //更新數據 getItemList({tab:'good',page:++this.page}).then((data)=> { console.log('aaaa',data.data.data); this.items=this.items.concat(data.data.data); if(data.data.data.length==0){ this.isLoadingShow=false; }else{ $state.loaded(); } }) }, 1000); }, }, //三、加載組件(相似局部組件) components:{ InfiniteLoading, topicList }, //4.鉤子函數 mounted:function(){ //分類這裏之因此要傳對象,是由於axios的語法就是這樣params:{} getItemList({tab:'good'}).then((data)=> { //console.log(data.data.data); this.items=data.data.data; }) }, } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> @import '../../assets/sass/base.scss'; .box{ margin-bottom:rem(100px); } </style>
上面的vue-infinite-loading插件主要是實現下拉數據加載更多的效果,實際數據的請求,以及點擊回到頂部代碼爲ios
//src\components\topics\Topiclist.vue <template> <div class="all quan"> <!--<loading v-if="items.length==0"></loading>--> <ul class="items"> <li class="item" v-for="item in items"> <img v-lazy="item.author.avatar_url"/> <div class="tab"> <div class="bj" v-if="item.top==true">置頂</div> <div class="bj" v-else-if="item.good==true">精華</div> <div class="bj1" v-else>{{tab[item.tab]}}</div> </div> <router-link :to="'/index/detail/'+item.id" tag="div" class="title">{{item.title}}</router-link> </li> </ul> <div class="back">回<br>到<br>頂<br>部</div> </div> </template> <script> //引入axios模塊 //import axios from 'axios'; //引入取數據模塊 ,數據和組件分開,因此這裏不引入數據模塊 //import {getItemList} from '@/getdata/topic.js'; //引入loading組件 import Loading from '@/components/Loading'; export default { name: 'All', data () { return { tab:{ share:'分享', ask:'問答', dev:'測試', job:'招聘' }, } }, //加載loading組件、分頁組件 components:{ Loading }, //接收數據,這個items是在子組件中綁定的屬性名稱 props:['items'], //鉤子函數,這裏不取數據,因此不用鉤子函數 mounted:function(){ $(window).scroll(function(){ var top=$(window).scrollTop(); if(top>200){ $('.back').css('display','block'); }else if(top<200){ $('.back').css('display','none'); } }) $('.back').click(function(){ $('html').animate({scrollTop:0},500); }) } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> @import '../../assets/sass/base.scss'; .quan{ width:rem(730px); margin:0 auto; background:#fff; .items{ width:100%; .item{ display: flex; height:rem(100px); align-items: center; border-bottom: 1px solid #ccc; img{ display: block; width:rem(60px); height:rem(60px); border-radius: rem(10px); margin:0 rem(15px); } .tab{ .bj{ width:rem(65px); height:rem(40px); font-size: rem(26px); background: #9cba48; color:#fff; text-align: center; line-height: rem(40px); border-radius: rem(10px); margin-right:rem(15px); } .bj1{ width:rem(65px); height:rem(40px); font-size: rem(26px); background: #e5e5e5; color:#999; text-align: center; line-height: rem(40px); border-radius: rem(10px); margin-right:rem(15px); } } .title{ width:rem(500px); line-height: rem(100px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: rem(30px); } } } .back{ display: none; position: fixed; top:60%; right:0; padding:rem(15px); background: #f5f5f5; border:1px solid #ccc; border-right:none; color:grey; font-size:rem(28px); border-radius: rem(20px) 0 0 rem(20px); } } </style>
//src\components\topics\Share.vue <template> <div class="share quan"> <!--1--> <topic-list :items="items"></topic-list> <!--分頁--> <infinite-loading @infinite="infiniteHandler" v-if="isLoadingShow" class="box"></infinite-loading> </div> </template> <script> //引入axios模塊 //import axios from 'axios'; //引入取數據函數 import {getItemList} from '@/getdata/topic.js'; //二、引入公共的主題列表組件 import topicList from '@/components/topics/Topiclist'; //引入分頁組件 import InfiniteLoading from 'vue-infinite-loading'; export default { name: 'Share', data () { return { items:[], //控制圓圈是否顯示 isLoadingShow:true, page:1 } }, methods: { infiniteHandler($state) { setTimeout(() => { //更新數據 getItemList({tab:'share',page:++this.page}).then((data)=> { // console.log(data.data.data); this.items=this.items.concat(data.data.data); if(data.data.data.length==0){ this.isLoadingShow=false; }else{ $state.loaded(); } }) }, 1000); }, }, //三、加載組件(相似局部組件) components:{ InfiniteLoading, topicList }, //4.鉤子函數 mounted:function(){ //分類這裏之因此要傳對象,是由於axios的語法就是這樣params:{} getItemList({tab:'share'}).then((data)=> { //console.log(data.data.data); this.items=data.data.data; }) }, } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> @import '../../assets/sass/base.scss'; .box{ margin-bottom:rem(100px); } </style>
//src\components\topics\Topiclist.vue <template> <div class="all quan"> <!--<loading v-if="items.length==0"></loading>--> <ul class="items"> <li class="item" v-for="item in items"> <img v-lazy="item.author.avatar_url"/> <div class="tab"> <div class="bj" v-if="item.top==true">置頂</div> <div class="bj" v-else-if="item.good==true">精華</div> <div class="bj1" v-else>{{tab[item.tab]}}</div> </div> <router-link :to="'/index/detail/'+item.id" tag="div" class="title">{{item.title}}</router-link> </li> </ul> <div class="back">回<br>到<br>頂<br>部</div> </div> </template> <script> //引入axios模塊 //import axios from 'axios'; //引入取數據模塊 ,數據和組件分開,因此這裏不引入數據模塊 //import {getItemList} from '@/getdata/topic.js'; //引入loading組件 import Loading from '@/components/Loading'; export default { name: 'All', data () { return { tab:{ share:'分享', ask:'問答', dev:'測試', job:'招聘' }, } }, //加載loading組件、分頁組件 components:{ Loading }, //接收數據,這個items是在子組件中綁定的屬性名稱 props:['items'], //鉤子函數,這裏不取數據,因此不用鉤子函數 mounted:function(){ $(window).scroll(function(){ var top=$(window).scrollTop(); if(top>200){ $('.back').css('display','block'); }else if(top<200){ $('.back').css('display','none'); } }) $('.back').click(function(){ $('html').animate({scrollTop:0},500); }) } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> @import '../../assets/sass/base.scss'; .quan{ width:rem(730px); margin:0 auto; background:#fff; .items{ width:100%; .item{ display: flex; height:rem(100px); align-items: center; border-bottom: 1px solid #ccc; img{ display: block; width:rem(60px); height:rem(60px); border-radius: rem(10px); margin:0 rem(15px); } .tab{ .bj{ width:rem(65px); height:rem(40px); font-size: rem(26px); background: #9cba48; color:#fff; text-align: center; line-height: rem(40px); border-radius: rem(10px); margin-right:rem(15px); } .bj1{ width:rem(65px); height:rem(40px); font-size: rem(26px); background: #e5e5e5; color:#999; text-align: center; line-height: rem(40px); border-radius: rem(10px); margin-right:rem(15px); } } .title{ width:rem(500px); line-height: rem(100px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: rem(30px); } } } .back{ display: none; position: fixed; top:60%; right:0; padding:rem(15px); background: #f5f5f5; border:1px solid #ccc; border-right:none; color:grey; font-size:rem(28px); border-radius: rem(20px) 0 0 rem(20px); } } </style>
//src\components\topics\Ask.vue <template> <div class="ask quan"> <!--1--> <topic-list :items="items"></topic-list> <!--分頁--> <infinite-loading @infinite="infiniteHandler" v-if="isLoadingShow" class="box"></infinite-loading> </div> </template> <script> //引入axios模塊 //import axios from 'axios'; //引入取數據函數 import {getItemList} from '@/getdata/topic.js'; //二、引入公共的主題列表組件 import topicList from '@/components/topics/Topiclist'; //引入分頁組件 import InfiniteLoading from 'vue-infinite-loading'; export default { name: 'Ask', data () { return { items:[], page:1, //控制圓圈是否顯示 isLoadingShow:true, } }, methods: { infiniteHandler($state) { setTimeout(() => { //更新數據 getItemList({tab:'ask',page:++this.page}).then((data)=> { // console.log(data.data.data); this.items=this.items.concat(data.data.data); if(data.data.data.length==0){ this.isLoadingShow=false; }else{ $state.loaded(); } }) }, 1000); }, }, //三、加載組件(相似局部組件) components:{ InfiniteLoading, topicList }, //4.鉤子函數 mounted:function(){ //分類這裏之因此要傳對象,是由於axios的語法就是這樣params:{} getItemList({tab:'ask'}).then((data)=> { //console.log(data.data.data); this.items=data.data.data; }) }, } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> @import '../../assets/sass/base.scss'; .box{ margin-bottom:rem(100px); } </style>
//src\components\topics\Job.vue <template> <div class="job quan"> <!--1--> <topic-list :items="items"></topic-list> <!--分頁--> <infinite-loading @infinite="infiniteHandler" v-if="isLoadingShow" class="box"></infinite-loading> </div> </template> <script> //引入axios模塊 //import axios from 'axios'; //引入取數據函數 import {getItemList} from '@/getdata/topic.js'; //二、引入公共的主題列表組件 import topicList from '@/components/topics/Topiclist'; //引入分頁組件 import InfiniteLoading from 'vue-infinite-loading'; export default { name: 'Job', data () { return { items:[], //控制圓圈是否顯示 isLoadingShow:true, page:1 } }, methods: { infiniteHandler($state) { setTimeout(() => { //更新數據 getItemList({tab:'job',page:++this.page}).then((data)=> { // console.log(data.data.data); this.items=this.items.concat(data.data.data); if(data.data.data.length==0){ this.isLoadingShow=false; }else{ $state.loaded(); } }) }, 1000); }, }, //三、加載組件(相似局部組件) components:{ InfiniteLoading, topicList }, //4.鉤子函數 mounted:function(){ //分類這裏之因此要傳對象,是由於axios的語法就是這樣params:{} getItemList({tab:'job'}).then((data)=> { //console.log(data.data.data); this.items=data.data.data; }) }, } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> @import '../../assets/sass/base.scss'; .box{ margin-bottom:rem(100px); } </style>
//src\components\topics\Test.vue <template> <div class="dev quan"> <!--1--> <topic-list :items="items"></topic-list> <!--分頁--> <infinite-loading @infinite="infiniteHandler" v-if="isLoadingShow" class="box"></infinite-loading> </div> </template> <script> //引入axios模塊 //import axios from 'axios'; //引入取數據函數 import {getItemList} from '@/getdata/topic.js'; //二、引入公共的主題列表組件 import topicList from '@/components/topics/Topiclist'; //引入分頁組件 import InfiniteLoading from 'vue-infinite-loading'; export default { name: 'Dev', data () { return { items:[], //控制圓圈是否顯示 isLoadingShow:true, page:1 } }, methods: { infiniteHandler($state) { setTimeout(() => { //更新數據 getItemList({tab:'dev',page:++this.page}).then((data)=> { // console.log(data.data.data); this.items=this.items.concat(data.data.data); if(data.data.data.length==0){ this.isLoadingShow=false; }else{ $state.loaded(); } }) }, 1000); }, }, //三、加載組件(相似局部組件) components:{ InfiniteLoading, topicList }, //4.鉤子函數 mounted:function(){ //分類這裏之因此要傳對象,是由於axios的語法就是這樣params:{} getItemList({tab:'dev'}).then((data)=> { //console.log(data.data.data); this.items=data.data.data; }) }, } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> @import '../../assets/sass/base.scss'; .box{ margin-bottom:rem(100px); } </style>
//src\components\Me.vue <template> <div class="me"> <div class="head"> <ul> <li><a href="/index">主頁</a> / </li> <li class="active">關於</li> </ul> </div> <div class="shuru"> <h2>關於</h2> <div class="con"> <p>CNode 社區爲國內最大最具影響力的 Node.js 開源技術社區,致力於 Node.js 的技術研究。</p> <p>CNode 社區由一批熱愛 Node.js 技術的工程師發起,目前已經吸引了互聯網各個公司的專業技術人員加入,咱們很是歡迎更多對 Node.js 感興趣的朋友。</p> <p>CNode 的 SLA 保證是,一個9,即 90.000000%。</p> </div> </div> </div> </template> <script> export default { name: 'Login', data () { return { msg: 'Welcome to Your Vue.js App' } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> @import '../assets/sass/base.scss'; .me{ margin:rem(40px) auto 0; width:rem(730px); height:rem(686px); background: #fff; border-radius: rem(10px); .head{ border-radius: rem(10px) rem(10px) 0 0; width:100%; height:rem(80px); background:#f6f6f6; ul{ display: flex; padding-left:rem(20px); li{ font-size:rem(28px); line-height: rem(80px); color:#999; a{ color:#80bd01; } } } } .shuru{ padding:rem(20px) rem(20px) 0; h2{ font-size: rem(40px); line-height:rem(80px); border-bottom:1px solid #ccc; } .con{ padding-top:rem(30px); p{ font-size: rem(30px); line-height: rem(50px); margin-bottom:rem(30px); } } } } </style>
//src\components\Login.vue <template> <div class="login"> <div class="head"> <ul> <li><a href="/index">主頁</a> / </li> <li class="active">登錄</li> </ul> </div> <div class="shuru"> <p>用戶名</p> <input type="text" /> <p>密碼</p> <input type="password" /><br /> <a href="#" class="btn">登陸</a> <a href="#" class="btn1">經過GitHub登陸</a> </div> </div> </template> <script> export default { name: 'Login', data () { return { msg: 'Welcome to Your Vue.js App' } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> @import '../assets/sass/base.scss'; .login{ margin:rem(40px) auto 0; width:rem(730px); height:rem(686px); background: #fff; border-radius: rem(10px); .head{ border-radius: rem(10px) rem(10px) 0 0; width:100%; height:rem(80px); background:#f6f6f6; ul{ display: flex; padding-left:rem(20px); li{ font-size:rem(28px); line-height: rem(80px); color:#999; a{ color:#80bd01; } } } } .shuru{ height:rem(526px); padding-top:rem(80px); padding-left:rem(20px); p{ font-size: rem(30px); color:#333; margin-bottom: rem(15px); } input{ width:rem(568px); height:rem(60px); border:rem(2px) solid #ccc; border-radius: rem(10px); margin-bottom: rem(40px); font-size: rem(30px); } a{ display: inline-block; padding:rem(15px); color:#fff; border-radius: rem(10px); font-size: rem(28px); margin:rem(30px) rem(5px); } .btn{ background:#0088cc; margin-left:rem(20px); } .btn1{ background: #5bc0de; } } } </style>