2019-08-09 Django+Vue.js實現前后端分離的單頁面博客系統(2)前端界面設計與組件、vue-router的初步編寫

前端界面設計

用了Bootstrap之后開發效率果然非常高,在頁面美化這部分沒有耗費太多精力,而且就算像我這樣沒學過UI設計的人寫出來的界面也比較好看??磥鞡ootstrap能成為使用最廣的前端框架,并不是沒有原因的。

直接上效果圖:

首頁
首頁
博文
歸檔
登錄
后臺管理
添加博文

用這么多的英文、只用黑白兩種顏色、簡單與扁平化的風格是想做跟上一個項目完全不同的感覺,畢竟這個項目跟上一個PHP寫的是走了兩個極端——一個是多頁面前后端不分離,一個是單頁面前后端分離。

當然這個風格也是Bootstrap本身的特點,反正比我自己純手寫的頁面是好看多了。

組件

目前的組件列表如下:

每個組件的詳細說明:

  • Add.vue:添加博文頁面
  • Archive.vue:歸檔頁面
  • ArchiveArticle.vue:歸檔頁面的文章列表
  • Article.vue:主頁使用的文章列表,預計一頁顯示15篇文章
  • ArticleDetail.vue:博文頁面(也就是文章的詳細內容)
  • Category.vue:主頁使用的目錄組件,預計顯示10條最新的文章的鏈接
  • Delete.vue:刪除文章的組件
  • Header.vue:頁面頭部的灰色部分
  • HelloWorld.vue:用vue-cli構建項目時默認生成的組件,現在留作測試用途,完成之后會刪掉
  • Login.vue:登錄頁面
  • Logout.vue:銷毀Session或者Cookie實現登出的組件
  • Main.vue:整個主頁
  • Manage.vue:后臺管理頁面
  • NavBar.vue:頁面頭部的導航欄
  • PageNavgation.vue:首頁的翻頁條,以后可能會加到別的頁面中

將整個網站拆解成這么多組件是為了解耦(降低耦合度)和提高每個組件的可重用性,也方便在開發的時候查錯改錯、為組件增加新功能。當然這是第一次用vue-cli開發,也有很多使用等方面的問題不大明白,而且目前我也弄不大清楚是盡可能拆解出更多的組件好還是一個頁面一個組件更好,這個問題以后慢慢考慮吧。

配置需要引用的庫

目前有Bootstrap、axios和VueAxios。

main.js(整個應用的入口js文件)

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import axios from 'axios'
import VueAxios from 'vue-axios'
import 'bootstrap/dist/css/bootstrap.min.css'

Vue.use(axios, VueAxios)

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

vue-router的配置

目前只想到文章和刪除需要動態id,以后如果有需要動態id的也會在里面改。

這個只是目前的配置,隨著開發進程的推進,會繼續更改。

index.js(vue-router的配置文件):

import Vue from 'vue'
import Router from 'vue-router'
import Manage from '@/components/Manage'
import Main from '@/components/Main'
import Login from '@/components/Login'
import Archive from '@/components/Archive'
import ArticleDetail from '@/components/ArticleDetail'
import Add from '@/components/Add'
import Delete from '@/components/Delete'
import Logout from '@/components/Logout'

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'Main',
      component: Main
    },
    {
      path: '/manage',
      name: 'Manage',
      component: Manage
    },
    {
      path: '/login',
      name: 'Login',
      component: Login
    },
    {
      path: '/archive',
      name: 'Archive',
      component: Archive
    },
    {
      path: '/article/:id',
      name: 'Article',
      component: ArticleDetail
    },
    {
      path: '/add',
      name: 'Add',
      component: Add
    },
    {
      path: '/delete/:id',
      name: 'Delete',
      component: Delete
    },
    {
      path: '/logout',
      name: 'Logout',
      component: Logout
    }
  ]
})

頁面跳轉的實現

點擊鏈接實現頁面跳轉

因為是用vue-cli做的單頁面應用,所以所有的頁面跳轉都由vue-router完成,也就是完全放棄了<a></a>標簽而用<router-link></router-link>標簽來代替(其實<router-link>渲染出來就是<a>,所以可以用<a>的樣式,在CSS的部分如果要控制<router-link>的樣式,選擇器也可以直接用元素選擇器a { })。以導航欄為例:

NavBar.vue(未完成)

<!--
      導航欄組件,顯示前往首頁的按鈕、后臺管理按鈕、登出按鈕等
      TODO: 開發根據登錄情況顯示不同按鈕的功能
-->
<template>
  <nav class="navbar navbar-expand-sm bg-dark navbar-dark topnavbar">
    <router-link to="/" class="navbar-brand">NullP0</router-link>
    <ul class="navbar-nav ml-auto">
      <li class="nav-item">
        <router-link to="/archive" class="nav-link">Archive</router-link>
      </li>
      <li class="nav-item">
        <router-link to="/add" class="nav-link">Add</router-link>
      </li>
      <li class="nav-item">
        <router-link to="/manage" class="nav-link">Manage</router-link>
      </li>
      <li class="nav-item">
        <router-link to="/logout" class="nav-link">Logout</router-link>
      </li>
    </ul>
  </nav>
</template>

<script>
  export default {
    name: 'NavBar',
  }
</script>

<style scoped>
  .navbar {
    position: fixed;
    width: 100%;
    z-index: 100;
  }
</style>

在這里,導航欄上所有的鏈接的本質都是路由跳轉。

至于頁面中獨立的按鈕(比如首頁中的閱讀全文按鈕),將<router-link>加上按鈕的class就可以把鏈接渲染成按鈕。

完成某操作后頁面強制跳轉

以登出組件為例,如果登出之后沒有任何操作,頁面將會停留在空白(因為預計登出組件不會顯示任何東西,僅僅是銷毀Cookie或者Session之后彈出一個框),所以需要一個強制跳轉??梢允褂?code>this.$router.push()函數完成:

Logout.vue(未完成)

<!--
  登出組件
  TODO: 開發登出功能
-->
<template>
    
</template>

<script>
  export default {
    name: 'Logout',
    mounted () {
      alert('登出成功!')
      this.$router.push('/')
    }
  }
</script>

<style scoped>

</style>

獲取動態id并根據動態id返回不同內容

如果要根據動態id顯示不同的內容(比如根據文章編號的不同顯示相應內容),除了要在vue-router的配置文件里配置上動態id,還需要在相應的組件里添加獲取動態id的方法。以文章頁面為例:

ArticleDetail.vue(未完成)

<!--
  閱讀文章的頁面
  TODO: 根據動態id顯示不同文章
-->
<template>
  <div>
    <v-header></v-header>
    <div class="container">
      <div class="col-12 border bg-light main-body">
        <div class="article">
          <h1 class="display-4">{{ detail.title }}</h1>
          <small>yyyy.mm.dd - hh:mm:ss</small>
          <hr class="my-3">
          <pre>{{ detail.content }}</pre>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  import Header from './Header'

  export default {
    name: 'ArticleDetail',
    components: {
      'v-header': Header,
    },
    data () {
      return {
        detail: {}
      }
    },
    mounted () {
      this.detail = this.getid(this.$route.params.id)
    },
    beforeRouteUpdate (to, from, next) {
      this.detail = this.getid(to.params.id)
      next()
    },
    methods: {
      // TODO: 從后端接收數據并顯示
      getid (id) {
        switch (id) {
          case '0' :
            return {
              id: 0,
              title: 'This is a title.',
              content: 'This is content.\n' + '    中文測試。'
            }
          default :
            return {
              id: -1,
              title: 'No data',
              content: 'No data'
            }
        }
      }
    }
  }
</script>

<style scoped>
  .main-body {
    padding: 40px;
    margin: 30px;
  }

  pre {
    font-family: 'DengXian', 'DengXian Light', sans-serif;
    font-size: 1.1em;
  }

  h1 {
    display: inline;
  }

  small {
    margin-left: 20px;
  }
</style>

實際效果:

編號為0的文章
編號為1的文章

當然,雖然現在文章內容是寫死的,但是后臺開發完成后文章內容就可以動態地使用Ajax從服務器端獲取了。

將文章內容放在<pre></pre>而不是<p></p>中是為了保留空格與換行,不讓文章本身的結構混亂。

這部分代碼太多沒法全都放上來,開發完成之后我會把整個項目傳到GitHub,詳細的代碼可以到時候在GitHub上查看。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容