基於Vue,Vue-router,Vuex的簡書網站模仿

在這個教程裏面,我會經過一系列的代碼和圖片來學習怎麼使用vue-router,以及vuex。本文假設讀者手裏有關於vue-router和Vuex的文檔,而且對Vue-router和Vuex有必定的瞭解。
沒有文檔也不要緊,我這裏有關於 Vue-router文檔以及Vuex介紹,能夠配合本文進行學習。因爲纔開始學習Vue,若有不當
之處,還請你們幫我斧正!!html

首先看下這個網站的截圖
圖片描述vue

這裏是網站的源碼下載地址 Github Repo
部分代碼已經更新爲2.0 JianshuVue2
代碼已經具備React版本 JianshuByReact
這裏是Demo地址,在線感覺vue的魅力node

搭建項目

項目結構

本項目才用Vue-cli腳手架自動生成,這是一個Vue生態系統中一個偉大創舉。這意味着咱們不須要手動構建咱們的項目,而它就能夠很快地爲咱們生成。如圖所示:
圖片描述webpack

  • components:包含全部的頁面組件
  • vuex:包含vuex相關文件(action.js, store.js)
  • static:靜態文件存放(圖片和圖標庫等)
  • index.html:渲染的頁面
  • main.js:應用入口點,包含根實例
  • App.vue:主頁面組件

項目流程:

  • 安裝Vue-cli(要有node與npm)
npm i -g vue-cli
  • 建立一個webpack項目,而且下載依賴
vue init webpack vue-demo-jianshu
cd vue-demo-jianshu
npm i
  • 安裝Vue-router和Vuex
npm install vue-router vuex --save
  • 熱加載打開頁面(生產的時候運行npm run build)
npm run dev

項目的框架已經搭建好了,接下來就是爲項目添磚加瓦。git

添磚加瓦第一步(初始化main.js與App.vue)

首先分析頁面結構(專題頁面結構和首頁同樣,就不在單獨贅述了,寫到哪兒分析到哪兒)
圖片描述github

  • App.vue: 綠色框內的和黃色框內的就是每一個頁面都存在的,故寫在App.vue裏
  • home.vue: 紫色區域部分,因爲文章區內文章會進行變化,故把文章區域單獨寫成組件
  • Article.vue: 棕色框部分

main.js部分

在main.js中咱們引入Vue,App,Vue-router,而且建立了一個Vue的實例(由於在router這行引入了App組件router.start(App, '#app'),上main.js代碼:web

import Vue from 'vue'
import App from './App'
import VueRouter from 'vue-router'

import home from './components/Home.vue'
import topic from './components/Topic.vue'
import article from './components/Article.vue'
import bonus from './components/Bonus.vue'
import login from './components/Login.vue'
import topic_article from './components/Topic_article.vue'

//註冊VueRouter這個插件
Vue.use(VueRouter)

const router = new VueRouter()

//路由map
router.map({
    '/home': {
        component: home,
        subRoutes: {
            '/article': {
                component: article
            }
        }
    },
    '/topic': {
        component: topic,
        subRoutes: {
            'topic_article': {
                component: topic_article
            }
        }
    },
    '/bonus': {
        component: bonus
    },
    '/login': {
        component: login
    }
})
//路由重定向(訪問不存在的頁面時,重定向到這個頁面)
router.redirect({
    '*':'/home/article'
})

router.start(App,'app')//啓動一個啓用了路由的應用。建立一個 App 的實例而且掛載到元素 'app'
router.go('/home/article')//爲了讓頁面打開的時候能看見文章,我把它導航到新路由

App.vue部分

App.vue裏面咱們把兩個側邊欄(綠色框和黃色框)寫在這裏邊,由於這兩個老是一直存在的vue-router

<template>
<div class="container">
  <div class="sidebar">
    <ul class="dropdown">
      <li :class="{active: show === 'home'}">
        <a @click="show = 'home'" v-link="'/home/article'"><i class="fa fa-home"></i><span>&nbsp;&nbsp;首頁</span></a>
      </li>
      <li :class="{active: show === 'topic'}">
        <a @click="show = 'topic'" v-link="'/topic/topic_article'"><i class="fa fa-th"></i><span>&nbsp;&nbsp;專題</span></a>
      </li>
      <li><a href="#"><i class="fa fa-mobile"></i><span>&nbsp;&nbsp;下載手機應用</span></a></li>
    </ul>
    <ul class="nav-user">
      <li><a href=""><i class="fa fa-font"></i><span>&nbsp;&nbsp;顯示模式</span></a></li>
      <li><a v-link="'/login'"><i class="fa fa-sign-in"></i><span>&nbsp;&nbsp;登陸</span></a></li>
    </ul>
  </div>
  <div class="home">
    <router-view transition = 'display' transition-mode = 'out-in'></router-view>
  </div>
  <div class="rightbar">
    <nav>
      <a v-link="'/login'"><i class="fa fa-sign-in"></i>登陸</a>
      <a href="#"><i class="fa fa-user"></i>註冊</a>
    </nav>
  </div>
</div>
</template>

添磚加瓦第二步(home.vue和article.vue)

home.vue部分

先講home.vue,home.vue裏面要放紫色框內(除了棕色框)的內容,分析這個界面紫色框內的左側邊欄是不變的,故能夠寫死,頂部導航也是不變的,也寫死。關鍵就是在中部導航欄(熱門,新上榜那塊),棕色框內的內容會根據中部導航欄選中不一樣內容進行改變。那麼該怎麼實現這個呢?vuex

首先寫好須要寫死的地方,以下圖代碼所示:vue-cli

<template>
<div>
    <div class="showbar">
        <div class="cover-image"></div>
        <div class="text" style="text-shadow:1px 1px 1px #000000">
            <h1>簡書</h1>
            <h3>交流故事,溝通想法</h3>
            <p>一個基於內容分享的社區</p>
            <a href="#"><i class="fa fa-home"></i>提筆寫篇文章</a>
        </div>
    </div>
    <div class="article-page">
        <nav>
            <span class="nav-text fir"><a href="#">發現</a></span>
            <span class="nav-text"><a v-link="'../bonus'">2015精選</a></span>
            <span class="search clearfloat">
                <span class="input">
                    <input type="search" placeholder="搜索">
                </span>
                <span class="search-icon"><i class="fa fa-search"></i></span>
            </span>                    
        </nav>
        <div class="article-list">
            <ul class="btn-group">
                <li :class="{active: show === 'hot'}">
                    <a @click="displayArticle('hot')"
                       v-link="'/home/article'" 
                    >熱門</a></li>
                <li :class="{active: show === 'new'}">
                    <a @click="displayArticle('new')"
                       v-link="'/home/article'" 
                    >新上榜</a></li>
                <li :class="{active: show === 'daily'}">
                    <a @click="displayArticle('daily')"
                       v-link="'/home/article'" 
                    >日報</a></li>
                <li :class="{active: show === 'weekhot'}">
                    <a @click="show = 'weekhot'"
                       v-link="'/home/article'" 
                    >七日熱門</a></li>
                <li :class="{active: show === 'monthhot'}">
                    <a @click="show = 'monthhot'"
                       v-link="'/home/article'" 
                    >三十日熱門</a></li>
                <li :class="{active: show === 'reward'}">
                    <a @click="show = 'reward'"
                       v-link="'/home/article'" 
                    >有獎活動</a></li>
                <li :class="{active: show === 'publish'}">
                    <a @click="show = 'publish'"
                       v-link="'/home/article'" 
                    >簡書出版</a></li>
                <li :class="{active: show === 'video'}">
                    <a @click="show = 'vedio'"
                       v-link="'/home/article'" 
                    >簡書播客</a></li>
                <li :class="{active: show === 'hotnews'}">
                    <a @click="show = 'hotnews'"
                       v-link="'/home/article'" 
                    >時事熱聞</a></li>
                <li :class="{active: show === 'choice'}">
                    <a @click="show = 'choice'"
                       v-link="'/home/article'" 
                    >專題精選</a></li>

            </ul>
            <router-view></router-view>
        </div>
    </div>
</div>
</template>

不知道你看懂代碼了沒,沒看懂沒關係,我來給你講解,重點分析導航欄部分,爲了讓導航欄標籤被選中時改變背景色,這裏我使用了:class="{active: show === 'hot'}" ,這是vue裏v-bind:class的簡寫,若是你問我show從哪裏來,我會告訴你show從天上來,哈哈,不開玩笑,show的來源也就是今天的另外一個重點Vuex。看代碼:
首先是store.js(個人理解是管理數據和操做數據的地方)

store.js部分

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = {
    articles:{
        fir: {
            author:'徐丹妮',
            title:'我不是學霸,只是比你努力一點而已',
            time:'大約6小時以前',
            read:'8498',
            comment:'248',
            like:'2342',
            pay:'2',
            src:'url(../../static/vue-demo-hot.jpg)'
        },
        sec: {
            author:'共央君',
            title:'愛漂亮的女生們,六款超高性價比的變美神器你都有了嗎?',
            time:'大約8小時以前',
            read:'2623',
            comment:'34',
            like:'191',
            pay:'2',
            src:'url(../../static/vue-demo-hot_1.jpg)'
        },
        thi: {
            author:'姜肥東',
            title:'畢業9年,我才學懂的道理',
            time:'大約6天以前',
            read:'6498',
            comment:'38',
            like:'242',
            pay:'2',
            src:'url(../../static/vue-demo-hot_2.jpg)'
        }
    },
    show:'hot'
}
const mutations = {
    DISPLAY_ARTICLE (state, show) {
        const article = {
            hot: {
                fir: {
                    author:'徐丹妮',
                    title:'我不是學霸,只是比你努力一點而已',
                    time:'大約6小時以前',
                    read:'8498',
                    comment:'248',
                    like:'2342',
                    pay:'2',
                    src:'url(../../static/vue-demo-hot.jpg)'
                },
                sec: {
                    author:'共央君',
                    title:'愛漂亮的女生們,六款超高性價比的變美神器你都有了嗎?',
                    time:'大約8小時以前',
                    read:'2623',
                    comment:'34',
                    like:'191',
                    pay:'2',
                    src:'url(../../static/vue-demo-hot_1.jpg)'
                },
                thi: {
                    author:'姜肥東',
                    title:'畢業9年,我才學懂的道理',
                    time:'大約6天以前',
                    read:'6498',
                    comment:'38',
                    like:'242',
                    pay:'2',
                    src:'url(../../static/vue-demo-hot_2.jpg)'
                }
            },
            new: {
                fir: {
                    author:'阿俊',
                    title:'Learn by doing',
                    time:'大約6小時以前',
                    read:'3398',
                    comment:'258',
                    like:'232',
                    pay:'88',
                    src:'url(../../static/vue-demo-new.jpg)'    
                },
                sec: {
                    author:'阿貓',
                    title:'Learn by doing',
                    time:'大約6小時以前',
                    read:'3398',
                    comment:'258',
                    like:'232',
                    pay:'88',
                    src:'url(../../static/vue-demo-new.jpg)'    
                },
                thi: {
                    author:'阿狗',
                    title:'Learn by doing',
                    time:'大約6小時以前',
                    read:'3398',
                    comment:'258',
                    like:'232',
                    pay:'88',
                    src:'url(../../static/vue-demo-new.jpg)'    
                }
            },
            daily:{
                fir: {
                    author:'屍叔',
                    title:'如何讓你的自拍,驚爆朋友圈?看我是怎麼設計的',
                    time:'大約2小時以前',
                    read:'3750',
                    comment:'70',
                    like:'190',
                    pay:'0',
                    src:'../../static/vue-demo-daily.jpg'                    
                },
                sec: {
                    author:'屍爸',
                    title:'如何讓你的自拍,驚爆朋友圈?看我是怎麼設計的',
                    time:'大約2小時以前',
                    read:'3750',
                    comment:'70',
                    like:'190',
                    pay:'0',
                    src:'../../static/vue-demo-daily.jpg'
                },
                thi: {
                    author:'屍姐',
                    title:'如何讓你的自拍,驚爆朋友圈?看我是怎麼設計的',
                    time:'大約2小時以前',
                    read:'3750',
                    comment:'70',
                    like:'190',
                    pay:'0',
                    src:'../../static/vue-demo-daily.jpg'
                }
            }
        }
        state.show = show
        state.articles = article[show]
    }
}
export default new Vuex.Store({
    state,
    mutations
})

getters獲取數據

這裏面我採用的是模擬數據的方式(一我的沒有後臺 QAQ),能夠看到show來自於state,咱們在home.vue頁面經過vuex的getters來獲取數據show,代碼以下:

import { displayArticle} from '../vuex/actions'
export default{
    vuex: {
        getters: {
            show: state => state.show
        },
        actions: {
            displayArticle
        }
    }
}

actions.js部分

在這裏還引入一個action,它是作什麼的呢?你答對了,這個displayArticle是用來分發事件的函數,它將更換文章區域內容的事件dispatch出去,而後在store.js裏面完成內容的更換,下面是actions.js代碼:

export const displayArticle = ({ dispatch },show) => {
    dispatch('DISPLAY_ARTICLE',show)
}

是否是感受vuex很簡單。中部導航欄我只給前三個弄了正確的點擊事件,如需體驗更多效果,本身動手,豐衣足食!!233
接下來是文章區域(棕色框部分)的代碼:

Article.vue

<template>
    <ul>
        <li class='list' v-for="article in articles">
            <p class="list-top"><a href="#" class="author"><span>{{ article.author }}</span></a><span class="time"> - {{ article.time}}</span></p>
            <h2 class="title"><a href="#">{{ article.title }}</a></h2>
            <span class="small-text">閱讀 {{article.read}} -</span>
            <span class="small-text">評論 {{article.comment}} -</span>
            <span class="small-text">喜歡 {{article.like}} -</span>
            <span class="small-text">打賞 {{article.pay}}</span>
            <span class="image" 
                :style="{background:article.src,backgroundSize:'100%',backgroundRepeat:'no-repat'}">
            </span>
        </li>
    </ul>
</template>
<script>
    export default {
        vuex: {
            getters: {
                articles: state => state.articles
            }
        }
    }
</script>

Article.vue和home.vue裏獲取數據的方式同樣,因爲未知文章數量,這裏採用vue的列表渲染(是否是感受很方便,有了vue,媽媽不再用擔憂個人學習啦)。簡書的首頁到這裏就寫完成了,因爲電腦越寫越卡,這篇就先發了,接下來開第二篇文章,簡書的專題頁面和推薦頁面,若是你發現本文章的錯誤之除,還請您斧正。
參考文章:用 Vuex 構建一個筆記應用 Vue構建單頁應用最佳實戰

相關文章
相關標籤/搜索