由於專案中用到了豆瓣api,涉及到跨域訪問,就需要在config的index.js新增代理,例如
proxyTable: { // 設定代理,解決跨域問題
'/api': {
target: 'https://api.douban.com/v2',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
},
安裝axios
npm install --save axios vue-axios
在main.js引入axios
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
在各個元件裡獲取資料,就是這麼簡單
this.axios.get(api).then((response) => {
console.log(response.data)
})
由於豆瓣app首頁的資料,我們不能直接通過api獲取資料,只能先將資料儲存下來進行訪問,大家做專案的時候,訪問靜態資料json會遇到路徑404,這裡我們可以通過在dev-server.js裡新增靜態資料的路由,例如:我們先將豆瓣的首頁資料先儲存到/src/data/homeData.json,
dev-server.js 新增
/**************** 靜態資料 start ****************/
var app = express()
var homeData = require('../src/data/homeData.json')
var apiRoutes = express.Router()
apiRoutes.get('/homeData',function(req,res){
res.json({
errno: 0,
data: homeData
})
})
app.use('/api',apiRoutes)
/**************** 靜態資料 end *****************/
在元件裡面訪問
this.axios.get('/api/homeData').then((response) => {
console.log(response.data)
})
接下來我們將靜態資料顯示到首頁中:靜態資料分為熱門和推薦,我麼先fetchData獲取資料,通過判斷card.name,賦值給recommendData、hotData
export default {
name: 'index',
components: {
mHeader,
mSwipe,
mCell,
mCellMedia
},
data() {
return {
recommendData: [],
hotData: []
}
},
created() {
this.fetchData();
},
methods: {
fetchData() {
this.axios.get('/api/homeData').then((response) => {
let data = response.data.data.recommend_feeds;
let recommend = [];
let hot = [];
for (var i in data) {
if (data[i].card && data[i].card.name == '為你推薦') {
recommend.push(data[i]);
} else {
hot.push(data[i]);
}
}
this.recommendData = recommend;
this.hotData = hot;
})
}
}
}
在Index.vue迴圈media-cell元件
<m-cell-media :author="item.target.author.name" :column="item.source_cn" :img="item.target.cover_url" v-for="(item,index) in hotData"
:key="item.id">
<span slot="title">{{item.title}}</span>
<span slot="describe">{{item.target.desc}}</span>
</m-cell-media>
Index.vue
<template>
<div>
<!-- 頭部 -->
<header class="m-header is-fixed is-bg top-search">
<div class="search-wrap">
<img src="../../assets/images/ic_search_gray.png" alt="">
<span class="placeholder">影視 圖書 唱片 小組 舞臺劇等</span>
<img src="../../assets/images/ic_scan_gray.png" alt="">
</div>
<!-- <div class="m-header-button is-right" style="text-align: center;width: 50px;">
<a href="javascript:;"><img class="m-icon-img" src="../../assets/images/ic_chat_white.png" /></a>
</div> -->
</header>
<!-- 主體 -->
<div class="page-content">
<!-- 輪播圖 -->
<m-swipe swipeid="swipe01" :autoplay="1000" paginationDirection="right">
<div class="swiper-slide " slot="swiper-con"><img src="../../assets/images/banner/01.jpg" alt=""></div>
<div class="swiper-slide " slot="swiper-con"><img src="../../assets/images/banner/02.jpg" alt=""></div>
<div class="swiper-slide " slot="swiper-con"><img src="../../assets/images/banner/03.jpg" alt=""></div>
</m-swipe>
<!-- cell -->
<m-cell title="提醒" icon>
<img src="../../assets/images/ic_mine_notification.png" slot="icon">
<a href="javascript:;" slot="cell-right"><img src="../../assets/images/ic_arrow_gray_small.png" alt=""></a>
</m-cell>
<m-cell title="設定">
<a href="javascript:;" slot="cell-right"><img src="../../assets/images/ic_arrow_gray_small.png" alt=""></a>
</m-cell>
<!--熱門-->
<div class="hot-wrap">
<m-cell title="熱門" label="hot">
<!--<a href="javascript:;" slot="cell-right">更多<img src="../../assets/images/ic_arrow_gray_small.png" alt=""></a>-->
</m-cell>
<m-cell-media :author="item.target.author.name" :column="item.source_cn" :img="item.target.cover_url" v-for="(item,index) in hotData"
:key="item.id">
<span slot="title">{{item.title}}</span>
<span slot="describe">{{item.target.desc}}</span>
</m-cell-media>
</div>
<!--推薦-->
<!-- <div class="recommend-wrap">
<m-cell title="推薦" label="recommend"></m-cell>
<m-cell-media :author="item.target.author.name" :column="item.source_cn" :bg="item.target.cover_url" v-for="(item,index) in recommendData" :key="item.id">
<span slot="title">{{item.title}}</span>
<span slot="describe">{{item.target.desc}}</span>
</m-cell-media>
</div> -->
</div>
</div>
</template>
<script>
import mHeader from '../../components/header'
import mSwipe from '../../components/swipe'
import mCell from '../../components/cell'
import mCellMedia from '../../components/cell-media'
export default {
name: 'index',
components: {
mHeader,
mSwipe,
mCell,
mCellMedia
},
data() {
return {
recommendData: [],
hotData: []
}
},
created() {
this.fetchData();
},
methods: {
fetchData() {
this.axios.get('/api/homeData').then((response) => {
let data = response.data.data.recommend_feeds;
let recommend = [];
let hot = [];
for (var i in data) {
if (data[i].card && data[i].card.name == '為你推薦') {
recommend.push(data[i]);
} else {
hot.push(data[i]);
}
}
this.recommendData = recommend;
this.hotData = hot;
})
}
}
}
</script>
<style lang="less">
// 頭部
header.m-header {
padding: 0 0 0 10px;
}
.is-fixed~.page-content {
padding-top: 44px;
padding-bottom: 50px;
}
.top-search {
.search-wrap {
// width: 100%;
height: 30px;
background: #fff;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
color: #c0c0c0;
padding: 0 12px;
.placeholder {
flex: 1;
text-align: left;
padding-left: 12px;
}
img {
width: 20px;
height: 20px;
}
}
}
// 熱門
.hot-wrap,
.recommend-wrap {
padding-top: 12px;
}
</style>
header.vue
<template>
<header class="m-header" :class="{'is-bg':bg,'is-fixed':fixed}">
<div class="m-header-button is-left" v-show="leftShow">
<slot name="left"></slot>
</div>
<h1 class="m-header-title" v-text="title"></h1>
<div class="m-header-button is-right">
<slot name="right"></slot>
</div>
</header>
</template>
<script>
/**
* @param title - header顯示的標題
* @param bg - header是否顯示的標題背景
* @param {slot} [left] - 左側的圖片內容和文字
* @param {slot} [right] - 右側的圖片內容和文字
* @exmaple
* <m-header title="豆瓣app" :bg="true">
* <a href="javascript:;" slot="left"><img class="m-icon-img" src="../../assets/images/ic_bar_back_white.png"/>返回</a>
* <a href="javascript:;" slot="right">分享</a>
* </m-header>
*/
export default {
props: {
title: {
type: String,
default: ''
},
bg: {
type: Boolean,
default: false
},
fixed: {
type: Boolean,
default: false
},
leftShow: {
type: Boolean,
default: true
}
}
}
</script>
<style lang="less">
/*匯入顏色變數*/
@import "../assets/less/var.less";
.m-header {
display: flex;
align-items: center;
height: 44px;
padding: 0 10px;
background: #fff;
color: @headerDefaultColor;
position: relative;
&:after {
content: '';
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 1px;
background: @headerBorderColor;
transform: scaleY(0.5);
}
a {
color: @headerDefaultColor;
}
.m-header-button {
width: 70px;
align-items: stretch;
&.is-left {
text-align: left;
}
&.is-right {
text-align: right;
}
.m-icon-img {
width: 20px;
height: 20px;
}
.margin-right-10 {
margin-right: 10px;
}
}
.m-header-title {
flex: 1;
text-align: center;
font-size: 16px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
&.is-bg {
background: @headerBg;
color: #fff;
a {
color: #fff;
}
.m-header-title {
color: #fff;
}
&:after {
content: '';
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 0px;
background: @headerBorderColor;
transform: scaleY(0.5);
}
}
&.is-fixed {
position: fixed;
left: 0;
right: 0;
top: 0;
z-index: 9;
}
}
</style>
swipe.vue
<template>
<div class="swiper-container" :class="swipeid">
<div class="swiper-wrapper">
<slot name="swiper-con"></slot>
</div>
<!-- 分頁器 -->
<div :class="{'swiper-pagination':pagination}" :style="{'text-align':paginationDirection}"></div>
</div>
</template>
<script>
import '../assets/lib/swiper/js/swiper.js'
export default {
props: {
swipeid: {
type: String,
default: ''
},
effect: {
type: String,
default: 'slide'
},
loop: {
type: Boolean,
default: true
},
direction: {
type: String,
default: 'horizontal'
},
autoplay: {
type: Number,
default: 5000,
},
paginationType: {
type: String,
default: 'bullets'
},
pagination: {
type: Boolean,
default: true
},
paginationDirection:{
type:String,
default:'center'
}
},
mounted() {
var That = this;
new Swiper('.'+That.swipeid, {
//迴圈
loop: That.loop,
//分頁器
pagination: '.swiper-pagination',
//分頁型別
paginationType: That.paginationType, //fraction,progress,bullets
//自動播放
autoplay: That.autoplay,
//方向
direction: That.direction,
//特效
effect: That.effect, //slide,fade,coverflow,cube
//使用者操作swiper之後,是否禁止autoplay
autoplayDisableOnInteraction : false,
})
}
}
</script>
<style>
@import '../assets/lib/swiper/css/swiper.css';
.swiper-container img{
width: 100%
}
.swiper-pagination-bullet-active {
background: #fff;
}
</style>
cell.vue
<template>
<div class="m-cell normal" :class="label">
<div class="m-cell-title">
<slot name="icon"></slot> {{title}}
</div>
<div class="m-cell-right">
<slot name="cell-right"></slot>
</div>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: ''
},
hot: {
type: Boolean,
default: false
},
recommend: {
type: Boolean,
default: false
},
icon: {
type: Boolean,
default: false
},
label: {
type: String,
default: 'normal'
}
}
}
</script>
<style lang="less">
.m-cell {
position: relative;
padding: 10px 5px 10px 15px;
display: flex;
justify-content: space-between;
align-items: center;
&:before {
content: '';
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 1px;
background: #eee;
transform: scaleY(0.5);
}
.m-cell-title {
font-size: 15px;
img {
width: 20px;
height: 20px;
}
}
.m-cell-right {
font-size: 12px;
a {
color: #666;
}
img {
width: 20px;
height: 20px;
}
}
&.normal {}
&.hot {
padding: 0px 5px 0px 15px;
height: 22px;
&:after {
content: '';
position: absolute;
width: 5px;
left: 0;
top: 0px;
bottom: 0px;
background: #ff8447;
}
&:before {
height: 0
}
}
&.recommend {
padding: 0px 5px 0px 15px;
height: 22px;
&:after {
content: '';
position: absolute;
width: 5px;
left: 0;
top: 0px;
bottom: 0px;
background: #42bd56;
}
&:before {
height: 0
}
}
}
</style>
cell-media.vue
<template>
<div class="m-cell-media-wrap">
<a href="javascript:;">
<div class="m-cell-media-top">
<div class="m-cell-media">
<div class="m-cell-title m-ellipsis-2">
<slot name="title"></slot>
</div>
<div class="m-cell-detail m-ellipsis-2">
<slot name='describe'></slot>
</div>
</div>
<div class="m-pull-right right-img" :style="{'background-image':'url('+img+')'}">
</div>
</div>
<div class="m-cell-media-bottom">
<p v-if="author">作者:{{author}}</p>
<p v-if="column">{{column}}</p>
</div>
</a>
</div>
</template>
<script>
export default {
props: ['author', 'column', 'img']
}
</script>
<style lang="less">
.m-cell-media-wrap {
display: flex;
flex-direction: column;
padding: 18px 20px;
position: relative;
&:after {
content: '';
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 1px;
background: #eee;
transform: scaleY(0.5);
}
.m-cell-media-top {
display: flex;
flex-direction: row;
.m-cell-media {
flex: 1;
padding-right: 45px;
}
.m-cell-title {
font-size: 17px;
line-height: 22px;
color: #333;
font-weight: bold;
}
.m-cell-detail {
font-size: 12px;
padding-top: 12px;
color: #939393;
}
.m-pull-right {
width: 94px;
height: 94px;
overflow: hidden;
background-position: center center;
background-size: cover;
img {
width: 100%;
}
}
}
.m-cell-media-bottom {
display: flex;
justify-content: space-between;
padding-top: 20px;
margin-top: 12px;
color: #bfbfbf;
position: relative;
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 1px;
background: #eee;
}
}
}
</style>
var.less
//APP預設顏色
@defaultColor:#42bd56;
//header
@headerBg:@defaultColor;
@headerDefaultColor:rgb(73,73,73);
@headerBorderColor:#e4e4e4;
//tabbar
@tabbarBorderColor:#e4e4e4;
@tabbarActiveColor: @defaultColor;
新增 reset.css
效果圖