老规矩放上大大的github开源地址:https://github.com/goodheart222/vuepro
我们再来看看项目的效果,初步根据效果做到心中有数
看到效果的话,我们会发现,肯定是有路由切换,懒加载,后端交换数据这些
一起分析代码
main.js入口文件,引用了vue-lazyload懒加载的方式加载图片
//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中的,还有切换中颜色的改变,很有意思啊
//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{
rem(730px);
height:rem(160px);
background: #444;
margin:0 auto;
padding-top:rem(10px);
img{
display: block;
rem(243px);
margin:0 auto;
}
div.input{
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{
100%;
height:rem(80px);
background: #8cba48;
position: fixed;
bottom: 0;
left:0;
ul{
100%;
height:rem(80px);
display: flex;
li{
font-size: rem(38px);
33.33%;
height:100%;
line-height: rem(80px);
text-align: center;
color:#fff;
}
.selected{
background: #009606;
}
}
}
</style>
//src
outerindex.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'
}
]
})
跟后端请求接口的文件也写的很高级,作者的功力很深厚
//srcgetdata opic.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}
接下来我们分析页面
//srccomponentsIndex.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{
rem(730px);
height:rem(70px);
background: #f6f6f6;
border-radius: rem(15px) rem(15px) 0 0;
margin:rem(40px) auto 0;
ul{
display:flex;
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>
//srccomponents opicsGood.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';
//2、引入公共的主题列表组件
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);
},
},
//3、加载组件(类似局部组件)
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插件主要是实现下拉数据加载更多的效果,实际数据的请求,以及点击回到顶部代码为
//srccomponents opicsTopiclist.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{
rem(730px);
margin:0 auto;
background:#fff;
.items{
100%;
.item{
display: flex;
height:rem(100px);
align-items: center;
border-bottom: 1px solid #ccc;
img{
display: block;
rem(60px);
height:rem(60px);
border-radius: rem(10px);
margin:0 rem(15px);
}
.tab{
.bj{
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{
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{
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>
//srccomponents opicsShare.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';
//2、引入公共的主题列表组件
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);
},
},
//3、加载组件(类似局部组件)
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>
//srccomponents opicsTopiclist.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{
rem(730px);
margin:0 auto;
background:#fff;
.items{
100%;
.item{
display: flex;
height:rem(100px);
align-items: center;
border-bottom: 1px solid #ccc;
img{
display: block;
rem(60px);
height:rem(60px);
border-radius: rem(10px);
margin:0 rem(15px);
}
.tab{
.bj{
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{
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{
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>
//srccomponents opicsAsk.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';
//2、引入公共的主题列表组件
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);
},
},
//3、加载组件(类似局部组件)
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>
//srccomponents opicsJob.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';
//2、引入公共的主题列表组件
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);
},
},
//3、加载组件(类似局部组件)
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>
//srccomponents opicsTest.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';
//2、引入公共的主题列表组件
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);
},
},
//3、加载组件(类似局部组件)
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>
//srccomponentsMe.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;
rem(730px);
height:rem(686px);
background: #fff;
border-radius: rem(10px);
.head{
border-radius: rem(10px) rem(10px) 0 0;
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>
//srccomponentsLogin.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;
rem(730px);
height:rem(686px);
background: #fff;
border-radius: rem(10px);
.head{
border-radius: rem(10px) rem(10px) 0 0;
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{
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>