blog前后端分離項目02:Vue前端頁面開發(fā)

1、前言

技術(shù)棧:

  • vue
  • element-ui
  • axios http請求庫
  • markdown編輯器
    • mavon-editor
    • markdown-it
    • github-markdown-css

2、項目演示

3狞膘、環(huán)境準(zhǔn)備

安裝Vue的環(huán)境拦宣,Vue官方文檔

1戈盈、Nodejs安裝

  • Node.js:http://nodejs.cn/download/
    安裝就是無腦的下一步就好,安裝在自己的環(huán)境目錄下

  • 檢查時候安裝成功

    • cmd下輸入node -v,查看是否能夠正確打印出版本號即可宁赤!
    • cmd下輸入npm -v,查看是否能夠正確打印出版本號即可栓票!
    • 這個npm决左,就是一個軟件包管理工具,就和linux下的apt軟件安裝差不多逗载!
  • 修改全局依賴包下載路徑

    可以通過npm root -g 查看當(dāng)前存放的位置

    我們不想讓全局包放在這里哆窿,我們可以自定義存放目錄,在CMD窗口執(zhí)行以下兩條命令修改默認(rèn)路徑:

    npm config set prefix "D:\Program Files (x86)\nodejs\node_global"
    
    npm config set cache "D:\Program Files (x86)\nodejs\node_globalnode_cache"
    
  • 設(shè)置淘寶源,讓我們下載速度快的飛起

    # 安裝淘寶npm
    npm config set registry http://registry.npm.taobao.org/
    
  • 安裝 vue-cli

    # vue-cli 安裝依賴包
    npm install -g vue-cli
    

4厉斟、新建項目

參考官方文檔:https://cli.vuejs.org/zh/guide/creating-a-project.html

可以通過vue create或者vue ui創(chuàng)建項目挚躯,這里我使用vue ui,是@vue/cli3.0增加一個可視化項目管理工具擦秽,可以運行項目码荔、打包項目,檢查等操作感挥。

# 打開vue的可視化管理工具界面
vue ui

運行vue ui之后缩搅,會為我們打開一個http://localhost:8080的頁面:

然后點擊創(chuàng)建,填寫項目名稱

注意:創(chuàng)建的目錄最好是和你運行vue ui同一級触幼。這樣方便管理和切換硼瓣。

下一步,選擇【手動】置谦,再點擊下一步堂鲤,如圖點擊按鈕,勾選上路由Router媒峡、狀態(tài)管理Vuex瘟栖,去掉js的校驗。

下一步谅阿,也選上【Use history mode for router】半哟,點擊創(chuàng)建項目,然后彈窗中選擇按鈕【創(chuàng)建項目签餐,不保存預(yù)設(shè)】寓涨,就進入項目創(chuàng)建啦。

上述步驟氯檐,幫助我們創(chuàng)建了一個vue項目缅茉,并且安裝了Router、Vuex男摧。這樣我們后面就可以直接使用蔬墩。

我們可以看一下vueblog-vue的項目結(jié)構(gòu)

將項目導(dǎo)入idea

安裝element ui

安裝element-ui組件(https://element.eleme.cn/#/zh-CN/component/installation), 幫助我們開發(fā)出好看的博客頁面

在我們的項目根目錄用命令

# 安裝element-ui
npm i element-ui -S

在main.js中引入elementui依賴

//引入elementui
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

以上代碼便完成了 Element 的引入。需要注意的是耗拓,樣式文件需要單獨引入拇颅。

安裝Axios

接下來,安裝Axios(http://www.axios-js.com/zh-cn/docs/

使用 npm:

npm install --save axios vue-axios

將下面代碼加入main.js:

import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.use(VueAxios, axios)

我們可以利用Axios完成乔询,從瀏覽器中創(chuàng)建樟插、轉(zhuǎn)換請求數(shù)據(jù)和響應(yīng)數(shù)據(jù)、攔截請求和響應(yīng)

組件中竿刁,我們就可以通過this.$axios.get()來發(fā)起我們的請求了黄锤。

配置頁面路由

開始前我們先定義好頁面、配置好路由食拜,由于項目簡單鸵熟,頁面較少,所有提前鏈接好负甸,后續(xù)慢慢開發(fā)流强,等用到鏈接的時候就可以直接使用:

我們在views文件夾下定義幾個頁面:

  • BlogDetail.vue(博客詳情頁)
  • BlogEdit.vue(編輯博客)
  • Blogs.vue(博客列表)
  • Login.vue(登錄頁面)

然后再路由中心配置

  • router\index.js

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import Login from "../views/Login";
    import BlogDetail from "../views/BlogDetail";
    import Blogs from "../views/Blogs";
    import BlogEdit from "../views/BlogEdit";
    
    Vue.use(VueRouter)
    
    //路由是按照順序訪問的,所以/blog/:blogId 要放在/blog/:blogId/edit前面
    const routes = [
      {
        //博客列表
        path: '/',
        name: 'Index',
        //也可以這樣寫    redirect: {name: "Blogs"}
        component: Blogs,
      },
      {
        //博客列表
        path: '/blogs',
        name: 'Blogs',
        component: Blogs
      },
      {
        //登錄頁面
        path: '/login',
        name: 'Login',
        component: Login
      },
      {
        //編輯博客,增加blog
        path: '/blog/add',
        name: 'BlogEdit',
        component: BlogEdit
      },
      {
        //博客詳情頁
        path: '/blog/:blogId',
        name: 'BlogDetail',
        component: BlogDetail
      },
      {
        //編輯博客
        //接受前端傳遞來的參數(shù) blogId
        path: '/blog/:blogId/edit',
        name: 'BlogEdit',
        component: BlogEdit
      },
    
    ]
    
    const router = new VueRouter({
      mode: 'history',
      base: process.env.BASE_URL,
      routes
    })
    
    export default router
    
    

    清空APP.vue的style

    測試

5呻待、頁面開發(fā)

登錄頁面

1打月、頁面原型設(shè)計

由于頁面設(shè)計簡單 ,這里就略過了

2蚕捉、代碼

  • views.Login.vue
<template>
    <div>
        <el-container>
            <el-header>
                <img class="mlogo" src="../static/images/logo.png">
            </el-header>
            <el-main>
                <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
                    <span class="login-title">歡迎登錄</span>
                    <el-form-item label="用戶名" prop="username">
                        <el-input v-model="ruleForm.username"></el-input>
                    </el-form-item>
                    <el-form-item label="密碼" prop="password">
                        <el-input type="password" v-model="ruleForm.password"></el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" @click="submitForm('ruleForm')">立即登錄</el-button>
                        <el-button @click="resetForm('ruleForm')">重置</el-button>
                    </el-form-item>
                </el-form>
            </el-main>
        </el-container>
    </div>
</template>

<script>
    export default {
        name: "Login",
        data() {
            return {
                ruleForm: {
                    username: 'markerhub',
                    password: '111111'
                },
                rules: {
                    username: [
                        { required: true, message: '請輸入用戶名', trigger: 'blur' },
                        { min: 3, max: 15, message: '長度在 3 到 5 個字符', trigger: 'blur' }
                    ],
                    password: [
                        { required: true, message: '請輸入密碼', trigger: 'change' }
                    ],
                }
            };
        },
        methods: {
            submitForm(formName) {
                this.$refs[formName].validate((valid) => {
                    if (valid) {
                        //表單提交是post
                        const _this = this;
                        this.axios.post('http://localhost:8081/login',this.ruleForm).then(res => {

                            const jwt = res.headers['authorization']
                            //將jwt放入 jwt
                            const  userInfo = res.data.data;
                            console.log(jwt);
                            console.log(userInfo);

                            //這里this指向的是axios奏篙,所以需要在外面另存this,為_this
                            //把數(shù)據(jù)共享出去
                            _this.$store.commit("SET_TOKEN",jwt);
                            _this.$store.commit("SET_USERINFO",userInfo);

                            console.log(_this.$store.getters.GETUSER)
                            //頁面跳轉(zhuǎn)
                            _this.$router.push("/blogs")
                        })
                    } else {
                        console.log('error submit!!');
                        return false;
                    }
                });
            },
            resetForm(formName) {
                this.$refs[formName].resetFields();
            }
        }
    }
</script>

<style scoped>
    .el-header, .el-footer {
        background-color: #B3C0D1;
        color: #333;
        text-align: center;
        line-height: 60px;
    }

    .el-aside {
        background-color: #D3DCE6;
        color: #333;
        text-align: center;
        line-height: 200px;
    }

    .el-main {
        /*background-color: #E9EEF3;*/
        color: #333;
        text-align: center;
        line-height: 80px;
    }

    body > .el-container {
        margin-bottom: 40px;
    }

    .el-container:nth-child(5) .el-aside,
    .el-container:nth-child(6) .el-aside {
        line-height: 260px;
    }

    .el-container:nth-child(7) .el-aside {
        line-height: 320px;
    }

    .mlogo {
        height: 80%;
        margin-top: 5px;
    }
    .demo-ruleForm{
        border:1px solid #DCDFE6;
        width: 350px;
        margin:0px auto;
        padding: 35px 35px 15px 35px;
        border-radius: 5px;
        -webkit-border-radius: 5px;
        -moz-border-radius: 5px;
        box-shadow: 0 0 25px #909399;
    }
    .login-title{
        width: 350px;
        height: 40px;
        text-align:center;
        margin: 0 auto 40px auto;
        color: #303133;
    }
</style>

上述代碼主要做了兩件事:

1迫淹、表單校驗

2秘通、登錄按鈕的點擊登錄事件

表單校驗規(guī)則,固定寫法千绪,element-ui組件的demo有

發(fā)起登錄事件之后的代碼:

//這里this指向的是axios充易,所以需要在外面另存this,為_this
//把數(shù)據(jù)共享出去
_this.$store.commit("SET_TOKEN",jwt);
_this.$store.commit("SET_USERINFO",userInfo);

console.log(_this.$store.getters.GETUSER)
//頁面跳轉(zhuǎn)
_this.$router.push("/blogs")

從返回的結(jié)果請求頭中獲取到token的信息荸型,然后使用store提交token和用戶信息的狀態(tài)盹靴。完成操作之后,我們調(diào)整到了/blogs路由瑞妇,即博客列表頁面稿静。

token的狀態(tài)同步

所以在store/index.js中,代碼是這樣的:

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    token: '',
    userInfo: JSON.parse(sessionStorage.getItem("userInfo"))
  },
  mutations: {
    //state的值不能直接修改 mutations相當(dāng)于set方法
    SET_TOKEN: (state,token) => {
      state.token = token;
      localStorage.setItem("token",token);
    },
    SET_USERINFO: (state,userInfo) => {
      state.userInfo = userInfo;
      //session里面不能傳遞字符串辕狰,這里用JSON轉(zhuǎn)化一下,序列化
      sessionStorage.setItem("userInfo",JSON.stringify(userInfo));
    },
    REMOVE_INFO: (state) => {
      state.token = '';
      state.userInfo = {};
      localStorage.setItem("token", '');
      sessionStorage.setItem("userInfo",JSON.stringify(""));
    }
  },
  getters: {
    //get
    GETUSER: state => {
      return state.token;
    }
  },
  actions: {
  },
  modules: {
  }
})

存儲token改备,我們用的是localStorage,存儲用戶信息蔓倍,我們用的是sessionStorage悬钳。畢竟用戶信息我們不需要長久保存盐捷,保存了token信息,我們隨時都可以初始化用戶信息默勾。當(dāng)然了因為本項目是個比較簡單的項目碉渡,考慮到初學(xué)者,所以很多相對復(fù)雜的封裝和功能我沒有做母剥,當(dāng)然了滞诺,學(xué)了這個項目之后,自己想再繼續(xù)深入环疼,完成可以自行學(xué)習(xí)和改造哈

定義全局axios攔截器

點擊登錄按鈕發(fā)起登錄請求习霹,成功時候返回了數(shù)據(jù),如果是密碼錯誤炫隶,我們是不是也應(yīng)該彈窗消息提示淋叶。為了讓這個錯誤彈窗能運用到所有的地方,所以我對axios做了個后置攔截器等限,就是返回數(shù)據(jù)時候爸吮,如果結(jié)果的code或者status不正常,那么我對應(yīng)彈窗提示望门。

在src目錄下創(chuàng)建一個文件axios.js(與main.js同級)形娇,定義axios的攔截:

import axios from "axios";
import ElementUI from 'element-ui';
import store from './store'
import router from './router'

//方便管理請求,方便修改請求鏈接的域名
axios.defaults.baseURL="http://localhost:8081";

//前置攔截
axios.interceptors.request.use(config =>{

    return config
})

//后置攔截
axios.interceptors.response.use(response => {
    let res = response.data;

    console.log("==============")
    console.log(res)
    console.log("==============")

    if (res.code == 200) {
        return response
    } else {
        ElementUI.Message.error('錯了哦桐早,這是一條錯誤消息', {duration : 3*1000});

        //不讓進入Login.vue
        return Promise.reject(response.data.msg)
    }
},
    error => {
    console.log(error)
        if (error.response.data){
            error.message = error.response.data.msg
        }
        if (error.response.status === 401){
            store.commit("REMOVE_INFO")
            router.push("/login")
        }
        ElementUI.Message.error(error.message, {duration : 3*1000});

        return Promise.reject(error)
}
)

前置攔截厨剪,其實可以統(tǒng)一為所有需要權(quán)限的請求裝配上header的token信息哄酝,這樣不需要在使用是再配置祷膳,我的小項目比較小,所以直晨,還是免了吧~

然后再main.js中導(dǎo)入axios.js

//引入axios攔截器
import "./axios"

后端因為返回的實體是Result搀军,succ時候code為200勇皇,fail時候返回的是400,所以可以根據(jù)這里判斷結(jié)果是否是正常的门烂。另外權(quán)限不足時候可以通過請求結(jié)果的狀態(tài)碼來判斷結(jié)果是否正常屯远。這里都做了簡單的處理。

登錄異常時候的效果如下:

博客頁面

登錄完成之后直接進入博客列表頁面赂乐,然后加載博客列表的數(shù)據(jù)渲染出來。同時頁面頭部我們需要把用戶信息展示處理崩溪。因為很多地方都用到這個模塊斩松,所以我們把頁面頭部的用戶信息單獨抽取處理作為一個組件惧盹。

頭部用戶信息

頭部用戶信息包括三部分信息:id钧椰,頭像,用戶名瓶埋,而這些信息我們是在登錄之后就存在sessionStorage诊沪。因此端姚,我們可以通過store的getters獲取用戶信息渐裸。

  • components\Header.vue
<template>
    <div class="m-content">
        <h3>歡迎來到Ergou博客</h3>
        <div class="block"><el-avatar :size="50" :src="user.avatar"></el-avatar></div>
        <div>{{user.username}}</div>

        <div class="m-action">
            <span>  <el-link href="/blogs" >主頁</el-link></span>
            <el-divider direction="vertical"></el-divider>
            <span><el-link type="success" href="/blog/add">發(fā)表博客</el-link></span>
            <el-divider direction="vertical"></el-divider>
            <span v-if="!hasLogin"><el-link type="primary" @click="login">登錄</el-link></span>
            <span v-if="hasLogin"> <el-link type="danger" @click="logout">退出</el-link></span>
        </div>
    </div>
</template>

<script>
    export default {
        name: "Header",
        data() {
            return {
                user: {
                    username: '請先登錄',
                    avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
                },
                hasLogin: false
            }
        },
        methods: {
            logout() {
                const _this = this;
                _this.axios.get("/logout", {
                    headers: {
                        "Authorization" : localStorage.getItem("token")
                    }
                }).then(res =>{
                    _this.$store.commit("REMOVE_INFO")
                    _this.$router.push("/login")
                })
            },

        },
        created() {
            if (this.$store.getters.GETUSER.username){
                this.user.username = this.$store.getters.GETUSER.username
                this.user.avatar = this.$store.getters.GETUSER.avatar

                this.hasLogin = true
            }
        }
    }
</script>

<style scoped>
.m-content{
    max-width: 960px;
    margin: 0 auto;
    text-align: center;
}
    .m-action{
       margin: 10px 0;
    }
</style>

上面代碼created()中初始化用戶的信息橄仆,通過hasLogin的狀態(tài)來控制登錄和退出按鈕的切換盆顾,以及發(fā)表文章鏈接的disabled您宪,這樣用戶的信息就能展示出來了奠涌。 然后這里有個退出按鈕溜畅,在methods中有個logout()方法慈格,邏輯比較簡單遥金,直接訪問/logout稿械,因為之前axios.js中我們已經(jīng)設(shè)置axios請求的baseURL,所以這里我們不再需要鏈接的前綴了哈页眯。因為是登錄之后才能訪問的受限資源窝撵,所以在header中帶上了Authorization述吸。返回結(jié)果清楚store中的用戶信息和token信息蝌矛,跳轉(zhuǎn)到登錄頁面入撒。

然后需要頭部用戶信息的頁面只需要幾個步驟:

import Header from "@/components/Header";
data() {
  components: {Header}
}
# 然后模板中調(diào)用組件
<Header></Header>

博客分頁

接下來就是列表頁面茅逮,需要做分頁,列表我們在element-ui中直接使用時間線組件來作為我們的列表樣式碉考,還是挺好看的侯谁。還有我們的分頁組件。

需要幾部分信息:

  • 分頁信息
  • 博客列表內(nèi)容热芹,包括id伊脓、標(biāo)題报腔、摘要剖淀、創(chuàng)建時間
  • views\Blogs.vue
<template>
    <div>
        <Header> </Header>

        <div class="block">
            <el-timeline>
                <el-timeline-item :timestamp="blog.created" placement="top" v-for="blog in blogs">
                    <el-card>
                        <h4>
                            <router-link :to="{name: 'BlogDetail',params:{blogId: blog.id}}">
                                {{blog.title}}
                            </router-link>
                        </h4>
                        <p>{{blog.description}}</p>
                    </el-card>
                </el-timeline-item>

            </el-timeline>

            <el-pagination class="mpage"
                    background
                    layout="prev, pager, next"
                    :current-page=currentPage
                    :page-size=pageSize
                    :total=total
                    @current-change=page>
            </el-pagination>
        </div>
    </div>
</template>

<script>
    import Header from "../components/Header"
    export default {
        name: "Blogs",
        components: {
            Header
        },
        data() {
            return {
                blogs: {},
                currentPage: 1,
                total: 0,
                pageSize: 5
            }
        },
        methods: {
            page(currentPage) {
               const _this = this
                _this.axios.get("/blogs?currentPage=" + currentPage).then(res => {
                    console.log(res)
                    _this.blogs = res.data.data.records
                    _this.currentPage = res.data.data.currentPage
                    _this.total = res.data.data.total
                    _this.pageSize = res.data.data.size
                })
            }
        },
        created() {
            //調(diào)用分頁程序
            this.page(1)
        }

    }
</script>

<style scoped>
    .mpage{
        margin: 0 auto;
        text-align: center;
    }
</style>

data()中定義博客列表blogs、已經(jīng)一些分頁信息巨朦。method()中定義分頁的調(diào)用接口page(currentPage)糊啡,參數(shù)是需要調(diào)整的頁碼currentPage,得到結(jié)果之后直接賦值即可吁津。然后初始化時候碍脏,直接在mounted()方法中調(diào)用第一頁this.page(1),

博客編輯

我們點擊發(fā)表博客鏈接調(diào)整到/blog/add頁面,這里我們需要用到一個markdown編輯器役拴,在vue組件中河闰,比較好用的是mavon-editor姜性,那么我們直接使用哈髓考。先來安裝mavon-editor相關(guān)組件:

安裝mavon-editor

基于Vue的markdown編輯器mavon-editor

npm install mavon-editor --save

然后在main.js中全局注冊:

// 全局注冊
import Vue from 'vue'
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
// use
Vue.use(mavonEditor)

ok,那么我們?nèi)ザx我們的博客表單:

<template>
    <div>
        <Header></Header>

        <div class="m-content">
            <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
                <el-form-item label="標(biāo)題" prop="title">
                    <el-input v-model="ruleForm.title"></el-input>
                </el-form-item>
                <el-form-item label="摘要" prop="description">
                    <el-input type="textarea" v-model="ruleForm.description"></el-input>
                </el-form-item>
                <el-form-item label="內(nèi)容" prop="content">
                    <mavon-editor v-model="ruleForm.content"></mavon-editor>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" @click="submitForm('ruleForm')">立即創(chuàng)建</el-button>
                    <el-button @click="resetForm('ruleForm')">重置</el-button>
                </el-form-item>
            </el-form>
        </div>
    </div>
</template>

<script>
    import Header from "../components/Header";
    export default {
        name: "BlogEdit",
        components: {
            Header
        },    data() {
            return {
                ruleForm: {
                    id: '',
                    title: '',
                    description: '',
                    content: '',
                },
                rules: {
                    title: [
                        { required: true, message: '請輸入標(biāo)題', trigger: 'blur' },
                        { min: 3, max: 25, message: '長度在 3 到 25 個字符', trigger: 'blur' }
                    ],
                    description: [
                        { required: true, message: '請輸入摘要', trigger: 'blur' }
                    ],
                    content: [
                        {  required: true,message: '請輸入內(nèi)容', trigger: 'blur' }
                    ],
                }
            };
        },
        methods: {
            submitForm(formName) {
                this.$refs[formName].validate((valid) => {
                    if (valid) {
                        const _this = this;
                        this.axios.post("/blog/edit",this.ruleForm ,{
                            headers: {
                                "Authorization" : localStorage.getItem("token")
                            }
                        }).then(res =>{
                            console.log(res)
                            this.$alert('操作成功', '提示', {
                                confirmButtonText: '確定',
                                callback: action => {
                                   _this.$router.push("/blogs")
                                }
                            });
                        })
                    } else {
                        console.log('error submit!!');
                        return false;
                    }
                });
            },
            resetForm(formName) {
                this.$refs[formName].resetFields();
            }
        },
        created() {
            const  blogId = this.$route.params.blogId;
            const _this = this;
            //內(nèi)容回顯
            if (blogId){
                this.axios.get("/blog/" + blogId).then(res =>{
                    const blog = res.data.data;
                    _this.ruleForm.id = blog.id
                    _this.ruleForm.title = blog.title
                    _this.ruleForm.description = blog.description
                    _this.ruleForm.content = blog.content
                })
            }
        }
    }

</script>

<style scoped>
    .m-content{
        text-align: center;
    }

</style>

邏輯依然簡單射赛,校驗表單楣责,然后點擊按鈕提交表單秆麸,注意頭部加上Authorization信息,返回結(jié)果彈窗提示操作成功屯烦,然后跳轉(zhuǎn)到博客列表頁面房铭。emm,和寫ajax沒啥區(qū)別翁狐。熟悉一下vue的一些指令使用即可露懒。 然后因為編輯和添加是同一個頁面砂心,所以有了create()方法辩诞,比如從編輯連接/blog/7/edit中獲取blogId為7的這個id。然后回顯博客信息荞怒。獲取方式是const blogId = this.$route.params.blogId褐桌。

對了荧嵌,mavon-editor因為已經(jīng)全局注冊,所以我們直接使用組件即可:

<mavon-editor v-model="editForm.content"/>

效果如下:

博客詳情頁

博客詳情中需要回顯博客信息,然后有個問題就是赃春,后端傳過來的是博客內(nèi)容是markdown格式的內(nèi)容织中,我們需要進行渲染然后顯示出來狭吼,這里我們使用一個插件markdown-it,用于解析md文檔破花,然后導(dǎo)入github-markdown-c旧乞,所謂md的樣式。

方法如下:

# 用于解析md文檔
npm install markdown-it --save
# md樣式
npm install github-markdown-css
  • views\BlogDetail.vue

    <template>
        <div>
            <Header> </Header>
    
            <div class="mblog">
                <h2>{{blog.title}}</h2>
                <el-link icon="el-icon-edit" v-if="ownBlog">
                    <router-link :to="{name: 'BlogEdit',params: {blogId: blog.id} }">
                        編輯
                    </router-link>
                    </el-link>
                <el-divider></el-divider>
                <div class="markdown-body" v-html="blog.content"></div>
            </div>
    
        </div>
    </template>
    
    <script>
        import Header from "../components/Header";
        import "github-markdown-css/github-markdown.css"
        export default {
            name: "BlogDetail",
            components: {Header},
            data() {
                return {
                    blog: {
                        id: "",
                        title: "默認(rèn)",
                        content: "內(nèi)容"
                    },
                    ownBlog: false
                }
            },
            created() {
                const  blogId = this.$route.params.blogId;
                const _this = this;
                //內(nèi)容回顯
                if (blogId){
                    this.axios.get("/blog/" + blogId).then(res =>{
                        const blog = res.data.data;
                        _this.blog.id = blog.id
                        _this.blog.title = blog.title
                        var markdownIt = require("markdown-it")
                        var md =new markdownIt();
                        var result = md.render(blog.content)
                        _this.blog.content = result
    
                        _this.ownBlog=(blog.userId === _this.$store.getters.GETUSER.id)
                    })
                }
            }
        }
    
    </script>
    
    <style scoped>
    .mblog{
        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
        width: 100%;
        min-height: 700px;
        padding: 20px 15px;
    }
    </style>
    

具體邏輯還是挺簡單,初始化create()方法中調(diào)用getBlog()方法叉橱,請求博客詳情接口者蠕,返回的博客詳情content通過markdown-it工具進行渲染踱侣。

再導(dǎo)入樣式:

import 'github-markdown.css'

然后在content的div中添加class為markdown-body即可哈抡句。 效果如下:

另外標(biāo)題下添加了個小小的編輯按鈕待榔,通過ownBlog (判斷博文作者與登錄用戶是否同一人)來判斷按鈕是否顯示出來流济。

6绳瘟、路由權(quán)限攔截

頁面已經(jīng)開發(fā)完畢之后糖声,我們來控制一下哪些頁面是需要登錄之后才能跳轉(zhuǎn)的工腋,如果未登錄訪問就直接重定向到登錄頁面擅腰,因此我們在src目錄下定義一個js文件:

  • src\permission.js
import router from "./router";
// 路由判斷登錄 根據(jù)路由配置文件的參數(shù)
router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requireAuth)) { // 判斷該路由是否需要登錄權(quán)限
    const token = localStorage.getItem("token")
    console.log("------------" + token)
    if (token) { // 判斷當(dāng)前的token是否存在 趁冈; 登錄存入的token
      if (to.path === '/login') {
      } else {
        next()
      }
    } else {
      next({
        path: '/login'
      })
    }
  } else {
    next()
  }
})

通過之前我們再定義頁面路由時候的的meta信息渗勘,指定requireAuth: true,需要登錄才能訪問乔遮,因此這里我們在每次路由之前(router.beforeEach)判斷token的狀態(tài)蹋肮,覺得是否需要跳轉(zhuǎn)到登錄頁面坯辩。

{
  path: '/blog/add', // 注意放在 path: '/blog/:blogId'之前
  name: 'BlogAdd',
  meta: {
    requireAuth: true
  },
  component: BlogEdit
}

然后我們再main.js中import我們的permission.js

import './permission.js' // 路由攔截

7崩侠、小結(jié)

前端到這就算到一段落却音,對于組件的使用系瓢,vue的聲明周期還是理解的太淺,后面多接觸 肯定沒問題

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末涯塔,一起剝皮案震驚了整個濱河市清蚀,隨后出現(xiàn)的幾起案子枷邪,更是在濱河造成了極大的恐慌东揣,老刑警劉巖嘶卧,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芥吟,死亡現(xiàn)場離奇詭異,居然都是意外死亡钉稍,警方通過查閱死者的電腦和手機贡未,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門俊卤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人矫限,你說我怎么就攤上這事佩抹」髌唬” “怎么了枢里?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長豆胸。 經(jīng)常有香客問我巷疼,道長嚼沿,這世上最難降的妖魔是什么骡尽? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任爆阶,我火速辦了婚禮辨图,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吱韭。我一直安慰自己理盆,他們只是感情好猿规,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著环葵,像睡著了一般宝冕。 火紅的嫁衣襯著肌膚如雪地梨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天褐耳,我揣著相機與錄音铃芦,去河邊找鬼刃滓。 笑死咧虎,一個胖子當(dāng)著我的面吹牛计呈,可吹牛的內(nèi)容都是我干的捌显。 我是一名探鬼主播扶歪,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼善镰,長吁一口氣:“原來是場噩夢啊……” “哼炫欺!你這毒婦竟也來了品洛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤典格,失蹤者是張志新(化名)和其女友劉穎耍缴,沒想到半個月后挽霉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侠坎,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡实胸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了门躯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酷师。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡懂讯,死狀恐怖域醇,靈堂內(nèi)的尸體忽然破棺而出蓉媳,到底是詐尸還是另有隱情,我是刑警寧澤酪呻,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布减宣,位于F島的核電站,受9級特大地震影響玩荠,放射性物質(zhì)發(fā)生泄漏漆腌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一阶冈、第九天 我趴在偏房一處隱蔽的房頂上張望闷尿。 院中可真熱鬧女坑,春花似錦填具、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽誉简。三九已至,卻和暖如春盟广,著一層夾襖步出監(jiān)牢的瞬間闷串,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工筋量, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留烹吵,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓桨武,卻偏偏與公主長得像年叮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子玻募,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容