> 大家好,我給大家分享一下豆瓣app的制作。當然了,我們不是用原生去實現,而是用前端框架vuejs來實現豆瓣app。
**為什么我們選擇豆瓣app 來做這樣一個教程?**
> 是因為我很早就接觸豆瓣這個網站,我比較喜歡看豆瓣里面電影和文章的點評。并且豆瓣提供了非常豐富的一個api接口供我們使用。也就是說我們可以不通過后端,直接通過前端ajax來獲取電影和圖書的數據,來組裝我們app。
我們可以看一下豆瓣app首頁是一個什么樣子

以上就是豆瓣app的一個截圖。
**我們先來分析一下**
> 首頁分為四個部分。第一個就是頂部的搜索框。搜索框下面就是一個banner圖切換。在下面就是一些熱點的文章列表。最底部就是一個tab切換。在這篇教程中,我們通過vue的組件來實現這樣一個首頁的布局。
* * * * *
**創建豆瓣項目**
我們可以通過官方vue-cli初始化項目,這里我們采用webpack示例
~~~
vue init webpack
~~~
初始化后,通過npm install安裝依賴
~~~
npm install
~~~
運行項目,可以看到基于官方vue-cli的模版就創建好了
~~~
npm run dev
~~~

將所需要用的資源,拷貝到項目中,這里我通過解壓豆瓣app獲得他的一些圖片素材,拷入到src/assets/images目錄里。
css這里我用到了normaliz.css
在src下,新建了一個pages目錄,存放每一個頁面組件,可以看一下我們的目錄

由于我們的首頁更改了位置,所以在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
}
]
})
~~~
**第一個組件 tabbar**
如何創建自定義組件tabbar,也就是豆瓣app底部的工具欄。這里的結構我們參考了[mint-ui](https://github.com/ElemeFE/mint-ui)
這是我們將要實現的效果圖。

我們先來分析一下這個組件的結構。
這個組件分為兩部分:第一個是組件的外層容器,第二個是組件的子容器item,子組件里面又分為圖片和文字組合。子組件有2個狀態,一個默認灰色的狀態,一個選中狀態,我們來實現一下這個組件的布局。在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">
首頁
</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>
~~~
布局大功告成~~~~
前面我們說的是,通過組件的方式來實現這個app。
如果像上面代碼這樣的話肯定是不行的!既然我們大體布局已經寫好了,現在就可以通過組件的方式來調用。當然我們還要改造一下代碼。
先在components文件夾下面,新建兩個組件,通過這兩個組件來組合實現我們底部的tab組件:
**一個是tabbar-item.vue,實現子組件的item項,**
**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>
~~~
**一個是tabbar.vue,實現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中組合這兩個組件,實現tab組件效果
~~~
<template>
<div>
<m-tabbar>
<m-tabbar-item id='tab1'>
<img src="../assets/images/ic_tab_home_normal.png" alt="" slot="icon-normal">
首頁
</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'>
<img src="../assets/images/ic_tab_group_normal.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">
我的
</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>
~~~
實現的效果。

* * * * *
**光有一個死的界面,沒有點擊切換的效果怎么能行?**
以下我們通過vue使用自定義事件的表單輸入組件來實現點擊切換的效果。
* * * * *
先給Index.vue里面的tab組件加上v-model 來進行數據雙向綁定,通過select來達到選擇item,在item里面再添加一個選中的active圖片
~~~
<template>
<div>
測試
<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">
首頁
</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-active">
小組
</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-active">
我的
</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里面通過props來傳遞數據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組件:根據父組件的value和當前組件的id判斷是否為選中狀態,通過 $parent.$emit('input',id) - 觸發父組件的自定義事件,添加選中的圖片,根據isActive來顯示隱藏
~~~
<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組件就完成了~~~~~

感謝餓了么團隊給我們帶來了這么好的ui組件!
源碼下載 鏈接:http://pan.baidu.com/s/1qYlR8g0 密碼:9yph
下載安裝
~~~
npm install
npm run dev
~~~