大家好聚谁,我給大家分享一下仿豆瓣app的教程垦巴。當(dāng)然了骤宣,我們不是用原生去實(shí)現(xiàn),而是用前端框架vuejs來(lái)實(shí)現(xiàn)豆瓣app等限⊥牛————第一次寫文章,寫得不好請(qǐng)見(jiàn)諒桐早。
為什么我們選擇豆瓣app 來(lái)做這樣一個(gè)教程哄酝?
是因?yàn)槲液茉缇徒佑|豆瓣這個(gè)網(wǎng)站陶衅,我比較喜歡看豆瓣里面電影和文章的點(diǎn)評(píng)直晨。并且豆瓣提供了非常豐富的一個(gè)api接口供我們使用勇皇。也就是說(shuō)我們可以不通過(guò)后端儒士,直接通過(guò)前端ajax來(lái)獲取電影和圖書的數(shù)據(jù),來(lái)組裝我們app诅福。
我們可以看一下豆瓣app首頁(yè)是一個(gè)什么樣子 gif
以上就是豆瓣app的一個(gè)截圖氓润。
我們先來(lái)分析一下
首頁(yè)分為四個(gè)部分咖气。第一個(gè)就是頂部的搜索框崩溪。搜索框下面就是一個(gè)banner圖切換斩松。在下面就是一些熱點(diǎn)的文章列表惧盹。最底部就是一個(gè)tab切換。在這篇教程中粹断,我們通過(guò)vue的組件來(lái)實(shí)現(xiàn)這樣一個(gè)首頁(yè)的布局瓶埋。
創(chuàng)建豆瓣項(xiàng)目
如果沒(méi)有安裝node养筒,請(qǐng)到官網(wǎng)下載安裝闽颇,或者通過(guò)淘寶npm鏡像安裝
http://npm.taobao.org/
我們通過(guò)官方vue-cli初始化項(xiàng)目,這里我們采用webpack示例
vue init webpack douban
填寫項(xiàng)目描述兵多,作者橄仆,安裝vue-router
? Project name douban
? Project description douban
? Author afei
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? No
? Setup unit tests with Karma + Mocha? No
? Setup e2e tests with Nightwatch? No
vue-cli · Generated "douban".
To get started:
cd douban
npm install
npm run dev
Documentation can be found at https://vuejs-templates.github.io/webpack
初始化后盆顾,通過(guò)npm install安裝依賴
cd douban
npm install
由于我們是做的移動(dòng)端您宪,所以在index.html里面加上meta宪巨,
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
運(yùn)行項(xiàng)目,可以看到基于官方vue-cli的模版就創(chuàng)建好了
npm run dev
將所需要用的資源捏卓,拷貝到項(xiàng)目中怠晴,這里我通過(guò)解壓豆瓣app獲得他的一些圖片素材,拷入到src/assets/images目錄里稿械。
css這里我用到了normaliz.css
在src下溜哮,新建了一個(gè)pages目錄茂嗓,存放每一個(gè)頁(yè)面組件,可以看一下我們的目錄
由于我們的首頁(yè)更改了位置,所以在router里面的index.js需要更改為
import Vue from 'vue'
import Router from 'vue-router'
import Index from '../pages/Index'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Index',
component: Index
}
]
})
每一個(gè)組件的css我們通過(guò)less來(lái)編寫道批,所有需要通過(guò)npm安裝less插件
npm install less less-loader --save
使用less預(yù)處理器需要在頁(yè)面添加 lang='less'
<style scoped lang="less">
</style>
第一個(gè)組件 tabbar
如何創(chuàng)建自定義組件tabbar隆豹,也就是豆瓣app底部的工具欄茅逮。這里的結(jié)構(gòu)我們參考了mint-ui
這是我們將要實(shí)現(xiàn)的效果圖献雅。
我們先來(lái)分析一下這個(gè)組件的結(jié)構(gòu)挺身。
這個(gè)組件分為兩部分:第一個(gè)是組件的外層容器章钾,第二個(gè)是組件的子容器item贱傀,子組件里面又分為圖片和文字組合。子組件有2個(gè)狀態(tài)串纺,一個(gè)默認(rèn)灰色的狀態(tài)纺棺,一個(gè)選中狀態(tài)祷蝌,我們來(lái)實(shí)現(xiàn)一下這個(gè)組件的布局帆卓。在index.vue里面
template
<div class="m-tabbar">
<a class="m-tabbar-item is-active">
<span class="m-tabbar-item-icon">
< img src="../assets/images/ic_tab_home_normal.png" alt="">
</span>
<span class="m-tabbar-item-text">
首頁(yè)
</span>
</a>
<a class="m-tabbar-item">
<span class="m-tabbar-item-icon">
< img src="../assets/images/ic_tab_subject_normal.png" alt="">
</span>
<span class="m-tabbar-item-text">
書影音
</span>
</a>
<a class="m-tabbar-item">
<span class="m-tabbar-item-icon">
< img src="../assets/images/ic_tab_status_normal.png" alt="">
</span>
<span class="m-tabbar-item-text">
廣播
</span>
</a>
<a class="m-tabbar-item">
<span class="m-tabbar-item-icon">
< img src="../assets/images/ic_tab_group_normal.png" alt="">
</span>
<span class="m-tabbar-item-text">
小組
</span>
</a>
<a class="m-tabbar-item">
<span class="m-tabbar-item-icon">
< img src="../assets/images/ic_tab_profile_normal.png" alt="">
</span>
<span class="m-tabbar-item-text">
我的
</span>
</a>
</div>
style
<style lang="less">
.m-tabbar{
display: flex;
flex-direction: row;
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: 100%;
overflow: hidden;
height: 50px;
background: #fff;
border-top: 1px solid #e4e4e4;
.m-tabbar-item{
flex: 1;
text-align: center;
.m-tabbar-item-icon{
display: block;
padding-top: 2px;
img{
width: 28px;
height: 28px;
}
}
.m-tabbar-item-text{
display: block;
font-size: 10px;
color:#949494;
}
&.is-active{
.m-tabbar-item-text{
color: #42bd56;
}
}
}
}
</style>
布局大功告成~~~~
前面我們說(shuō)的是糊啡,通過(guò)組件的方式來(lái)實(shí)現(xiàn)這個(gè)app棚蓄。
如果像上面代碼這樣的話肯定是不行的!既然我們大體布局已經(jīng)寫好了稍算,現(xiàn)在就可以通過(guò)組件的方式來(lái)調(diào)用糊探。當(dāng)然我們還要改造一下代碼侧到。
先在components文件夾下面,新建兩個(gè)組件故源,通過(guò)這兩個(gè)組件來(lái)組合實(shí)現(xiàn)我們底部的tab組件:
一個(gè)是tabbar-item.vue绳军,實(shí)現(xiàn)子組件的item項(xiàng)门驾,
tabbar-item.vue
<template>
<a class="m-tabbar-item" >
<span class="m-tabbar-item-icon"><slot name="icon-normal"></slot></span>
<span class="m-tabbar-item-text"><slot></slot></span>
</a>
</template>
<style lang="less">
.m-tabbar-item{
flex: 1;
text-align: center;
.m-tabbar-item-icon{
display: block;
padding-top: 2px;
img{
width: 28px;
height: 28px;
}
}
.m-tabbar-item-text{
display: block;
font-size: 10px;
color:#949494;
}
&.is-active{
.m-tabbar-item-text{
color: #42bd56;
}
}
}
</style>
一個(gè)是tabbar.vue奶是,實(shí)現(xiàn)tab的外層容器聂沙,
tabbar.vue
<template>
<div class="m-tabbar">
<slot></slot>
</div>
</template>
<style lang="less">
.m-tabbar{
display: flex;
flex-direction: row;
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: 100%;
overflow: hidden;
height: 50px;
background: #fff;
border-top: 1px solid #e4e4e4;
}
</style>
在Index.vue中組合這兩個(gè)組件及汉,實(shí)現(xiàn)tab組件效果
<template>
<div>
<m-tabbar>
<m-tabbar-item id='tab1'>
< img src="../assets/images/ic_tab_home_normal.png" alt="" slot="icon-normal">
首頁(yè)
</m-tabbar-item>
<m-tabbar-item id='tab2'>
< img src="../assets/images/ic_tab_subject_normal.png" alt="" slot="icon-normal">
書影音
</m-tabbar-item>
<m-tabbar-item id='tab3'>
< img src="../assets/images/ic_tab_status_normal.png" alt="" slot="icon-normal">
廣播
</m-tabbar-item>
<m-tabbar-item id='tab4'>
![](../assets/images/ic_tab_group_normal.png)
小組
</m-tabbar-item>
<m-tabbar-item id='tab5'>
< img src="../assets/images/ic_tab_profile_normal.png" alt="" slot="icon-normal">
我的
</m-tabbar-item>
</m-tabbar>
</div>
</template>
<script>
import mTabbar from '../components/tabbar'
import mTabbarItem from '../components/tabbar-item'
export default {
name: 'index',
components: {
mTabbar,
mTabbarItem
}
}
</script>
完成的效果房铭。
光有一個(gè)死的界面缸匪,沒(méi)有點(diǎn)擊切換的效果怎么能行豪嗽?
以下我們通過(guò)vue使用自定義事件的表單輸入組件來(lái)實(shí)現(xiàn)點(diǎn)擊切換的效果。
先給Index.vue里面的tab組件加上v-model 來(lái)進(jìn)行數(shù)據(jù)雙向綁定隐锭,通過(guò)select來(lái)達(dá)到選擇item钦睡,在item里面再添加一個(gè)選中的active圖片
<template>
<div>
測(cè)試
<m-tabbar v-model="select">
<m-tabbar-item id='tab1'>
< img src="../assets/images/ic_tab_home_normal.png" alt="" slot="icon-normal">
< img src="../assets/images/ic_tab_home_active.png" alt="" slot="icon-active">
首頁(yè)
</m-tabbar-item>
<m-tabbar-item id='tab2'>
< img src="../assets/images/ic_tab_subject_normal.png" alt="" slot="icon-normal">
< img src="../assets/images/ic_tab_subject_active.png" alt="" slot="icon-active">
書影音
</m-tabbar-item>
<m-tabbar-item id='tab3'>
< img src="../assets/images/ic_tab_status_normal.png" alt="" slot="icon-normal">
< img src="../assets/images/ic_tab_status_active.png" alt="" slot="icon-active">
廣播
</m-tabbar-item>
<m-tabbar-item id='tab4'>
< img src="../assets/images/ic_tab_group_normal.png" alt="" slot="icon-normal">
< img src="../assets/images/ic_tab_group_active.png" alt="" slot="icon-normal">
小組
</m-tabbar-item>
<m-tabbar-item id='tab5'>
< img src="../assets/images/ic_tab_profile_normal.png" alt="" slot="icon-normal">
< img src="../assets/images/ic_tab_profile_active.png" alt="" slot="icon-normal">
我的
</m-tabbar-item>
</m-tabbar>
</div>
</template>
<script>
import mTabbar from '../components/tabbar'
import mTabbarItem from '../components/tabbar-item'
export default {
name: 'index',
components: {
mTabbar,
mTabbarItem
},
data() {
return {
select:"tab1"
}
}
}
</script>
tabbar.vue里面通過(guò)props來(lái)傳遞數(shù)據(jù)vaule
<template>
<div class="m-tabbar">
<slot></slot>
</div>
</template>
<script>
import mTabbarItem from './tabbar-item';
export default {
props: ['value']
}
</script>
<style lang="less">
.m-tabbar{
display: flex;
flex-direction: row;
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: 100%;
overflow: hidden;
height: 50px;
background: #fff;
border-top: 1px solid #e4e4e4;
}
</style>
tabbar-item.vue組件:根據(jù)父組件的value和當(dāng)前組件的id判斷是否為選中狀態(tài),通過(guò) $parent.$emit('input',id) - 觸發(fā)父組件的自定義事件,添加選中的圖片躁倒,根據(jù)isActive來(lái)顯示隱藏
<template>
<a class="m-tabbar-item" :class="{'is-active':isActive}" @click="$parent.$emit('input',id)">
<span class="m-tabbar-item-icon" v-show="!isActive"><slot name="icon-normal"></slot></span>
<span class="m-tabbar-item-icon" v-show="isActive"><slot name="icon-active"></slot></span>
<span class="m-tabbar-item-text"><slot></slot></span>
</a>
</template>
<script>
export default{
props: ['id'],
computed: {
isActive(){
if(this.$parent.value===this.id){
return true;
}
}
}
}
</script>
<style lang="less">
.m-tabbar-item{
flex: 1;
text-align: center;
.m-tabbar-item-icon{
display: block;
padding-top: 2px;
img{
width: 28px;
height: 28px;
}
}
.m-tabbar-item-text{
display: block;
font-size: 10px;
color:#949494;
}
&.is-active{
.m-tabbar-item-text{
color: #42bd56;
}
}
}
</style>
大功告成荞怒,tabbar組件就完成了~~~~~
感謝餓了么團(tuán)隊(duì)給我們帶來(lái)了這么好的ui組件!
git地址:
https://github.com/MrMoveon/doubanApp
第一章
源碼下載 鏈接:http://pan.baidu.com/s/1qYlR8g0 密碼:9yph
下載安裝
npm install
npm run dev