[vue+vuex+vue-router] 強擼一發暗黑風 markdown 日記應用

容我思考思考文章結構,可以更容易讓新手入門,思考的過程當中被小編拒了一次,囧。本文將會從項目開發角度出發,由外向內拆解,自頂而下設計javascript

項目地址css

效果圖html

圖片描述

暗黑風是否是很炫~Step by step,follow me~前端

知識儲備

vuex數據流

對於知識儲備這類事,無需多言,尤爲是node橫空出世以後,前端技能棧突飛猛進,學海無涯!一開始看不懂沒關係,書讀百遍,其義自現!做爲一名「碼農」, 更要增強閱讀能力+實操能力結合。

項目初始化

  1. 安裝nodejs,這個不贅述了

  2. 安裝vue-cli,這是vue.js官方推薦的大中型項目構建工具腳手架

    npm install -g vue-cli
  3. 初始化項目,選擇webpack做爲資源打包工具

    vue init webpack workbook(eslint,karma,e2e test等都選擇n) 
    cd workbook
    npm install
    npm run dev 
    // 打開 http://localhost:8080,應該能看到頁面
  4. 安裝相關依賴,我們把本次能用到的依賴安裝一下

    npm install -D vue-router vuex marked highlight.js
    // -D 和 --save-dev 等效,marked是markdown 語法轉換工具庫

項目結構

ok,項目初始化工做結束,我們來思考用vue+vuex+vue-router來構建頁面吧。

圖片描述
Oh Yeah! 組件化設計!

因爲我們後面幾乎全部的工做都在src文件夾下完成,因此咱們先來看看咱們將來的結構吧

├── App.vue //初始化工做,以及掛載路由的router-view組件
├── assets //靜態資源文件
│   └── darkness.css //暗黑風stylesheet
├── components  //組件放在這兒
│   ├── rawEditor.vue //markdown 文本編輯器組件
│   └── renderEditor.vue //渲染後的展現組件
├── main.js //入口程序
├── router.js //SPA 路由配置文件
├── views //頁面
│   ├── 404.vue // 除'/'之外的非法路由,一概指向404
│   └── index.vue // '/'路由指向頁面,內含 rawEditor.vue & renderEditor.vue
└── vuex
    ├── actions.js //vuex理念中 actions -> dispatch
    ├── getters.js //vuex 理念中 Getters Can Return Derived State,簡言之,組建裏面的狀態都經過getters來獲取
    └── store.js //vuex 理念中 initial state,mutations,相應dispatch-》mutations-》從而完成對state的更新

AhhA,Talk is cheap ,show me the code!

1. 在 src 根目錄下建立 router.js

//router.js
export default (router)=>router.map({
    '/':{
        name:'index',//應用首頁
        component:require('./views/index') //加載index頁面
    },
    '*':{//除'/'之外的全部路由,均跳轉到404頁面
        name:'404',
        component:require('./views/404')// 加載404頁面
    }
})

2. 修改 main.js 入口文件,咱們要加上 vue-router

//main.js
import Vue from 'vue'
import App from './App'
import VueRouter from 'vue-router'
import configRouter from './router'
require('./assets/darkness.css') 

Vue.use(VueRouter)
const router = new VueRouter()
configRouter(router)//注入路由規則

router.start(Vue.extend(App),'#app')//#app是what 鬼,哪裏來的?
/*
細心或者有經驗的同窗可能已經發現,在整個項目的根目錄有個index.html 文件,這個其實才是咱們整個應用的第一入口,SPA(Single Page App)完美的解釋,咱們來修改一下它吧。
*/

//index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>workbook</title>
    <style type="text/css">
        html,#app {
            height:100%;
        }
        body{
            width: 100%;
            height: 100%;
            margin:0;
            padding:0;
        }

    </style>
  </head>
  <body>
      <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

3. 修改 App.vue

//app.vue 瞧好了,vue 組件大法來了
<template>
    <div id="main">
        <router-view></router-view> //路由組件
    </div>   
</template>
<script>
import store from './vuex/store' //後面講vuex 配置會提到
export default {
    store
}
</script>
<style>
 #main {
    width:100%;
    height:100%;
 }
</style>

4. 開始寫咱們的兩個頁面吧

在src目錄下,新建views文件夾,存放咱們的頁面,index.vue & 404.vue

//index.vue
<template>//對照頁面佈局草稿圖,分別把兩個組件加載進來
    <raw-editor></raw-editor> 
    <render-editor></render-editor>
</template>

<script>
    import rawEditor from '../components/rawEditor'
    import renderEditor from '../components/renderEditor'

    export default {
        components:{
            rawEditor,
            renderEditor
        }
    }
</script>


//404.vue  簡單到使人髮指,不過我只是爲了實現router功能,請開恩。

<template>
    <h1>404</h1>
</template>

<script>
    export default {
        
    }
</script>

5. 開始寫具體組件

在寫組件以前,咱們先靜靜地思考一下

  • 代碼都寫了快一大半了,怎麼還不見飽守吹捧的vuex登場。OK!如你所願,不過在vuex登場以前,我們能否拿出紙和筆 或者 頭腦風暴一下,想一想我們的應用的state應該是什麼!!!

    • BingGo! rawHtmlrenderHtml,簡簡單單的兩個state,就可以知足咱們的應用需求。

  • rawHtmlrenderHtml之間又有什麼關係呢?

    • rawHtml通過轉換以後給renderHtml賦值

Jack:我以爲是時候引入 Vuex 了

在src 文件夾下 新建vuex文件夾,建立store.js ,getters.js,actions.js

//store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const state = {
    rawHtml:'',
    renderHtml:''
}

//這塊是重點,可以改變state的只可以在 mutations完成!!!
const mutations = {
    MARKDOWN_SUCCESS(state,_rawHtml,content){
        console.log(_rawHtml,content)
        state.rawHtml = _rawHtml
        state.renderHtml = content
    }
}

//最後別忘了,這塊要export 出去,還記得咱們在編寫app.vue 的時候 引入的store,就是這個,SPA只須要在最頂層的app.vue 引用一次便可。
export default new Vuex.Store({
    state,
    mutations
})

//getters.js 簡單到不像,getters存在的意義就是 純粹!!
export const getRawHtml = (state)=>state.rawHtml;
export const getRenderHtml = (state)=>state.renderHtml;

//actions.js 還記得vuex核心思想的那張數據流圖,還有上面我描述src的完成狀態的關於 vuex裏面各文件的意義所在,actions.js 說白了,就是處理玩rawHtml以後,dispatch 結果到 mutations,剩下更新state的工做交給mutations

import Vue from 'vue'
import marked from 'marked';
//marked配置文件
marked.setOptions({
  renderer: new marked.Renderer(),
  gfm: true,
  tables: true,
  breaks: false,
  pedantic: false,
  sanitize: true,
  smartLists: true,
  smartypants: false,
  highlight: function (code) {
    return require('highlight.js').highlightAuto(code).value;
  }
});


export const renderHtml = ({dispatch},e)=>{
    var _renderHtml = marked(e.target.value) 
    return dispatch('MARKDOWN_SUCCESS',e.target.value,_renderHtml)
}

繼續咱們的組件工做

這個項目很簡單,兩個組件,一個是rawEditor 還有一個是 renderEditor,至於爲何要起這個名字,who knows!在components 文件夾下建立rawEditor.vue 和renderEditor.vue文件。

往下走,可能有點複雜,千萬別退縮,多是我表述不夠清楚,可是move on,你就能收穫整片天空。

//rawEditor.vue
<template>
    <div id="raw-editor">
        <textarea
              :value="rawHtml"
              @input="renderHtml"
              class="form-control">
        </textarea>
    </div>
</template>

<script>
    //設計思想就是rawHtml內容已改變,就會觸發renderHtml方法
    import {renderHtml} from '../vuex/actions' 
    import {getRawHtml} from '../vuex/getters'
    export default {
        vuex:{//看到沒,裏面有個 vuex 對象,actions和getters二者相得益彰
            actions:{
                renderHtml //內容改變觸發
            },
            getters:{
                rawHtml:getRawHtml//得到rawHtml 
            }
        },
    }
</script>

<style>
    #raw-editor {
        float:left;
        width:45%;
        height:100%;
    }

    textarea{
        width: 100%;
        height:100%;
        border: 0;
        border-radius: 0;
    }
</style>

//renderEditor.vue
<template>
    <div id="render-editor">
        {{{renderHtml}}}
    </div>
</template>

<script>
    import {getRenderHtml} from '../vuex/getters'
    export default {
        vuex:{ //看到沒,裏面有個 vuex 對象
            getters:{
                renderHtml:getRenderHtml
            }
        }
    }
</script>
<style>
    #render-editor {
        float:right;
        width:50%;
        height:100%;
        overflow: scroll;
    }
</style>

代碼寫到這裏,離成功不遠了,是否是有點小期待呢

//打開命令行or terminal 工具,運行一下吧
npm run dev

等待一會編譯完成後,打開 http://localhost:8080,查看效果,怎麼樣,是否是很酷!

好吧!你們發現了,咱們的樣式不夠酷炫,也不是 暗黑風。退貨、老闆給差評!在src/assets文件夾中新建 darkness.css

pre,
code {
  font-family: Menlo, Monaco, "Courier New", monospace;
}

pre {
  padding: .5rem;
  line-height: 1.25;
  overflow-x: scroll;
}

@media print {
  *,
  *:before,
  *:after {
    background: transparent !important;
    color: #000 !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }

  a,
  a:visited {
    text-decoration: underline;
  }

  a[href]:after {
    content: " (" attr(href) ")";
  }

  abbr[title]:after {
    content: " (" attr(title) ")";
  }

  a[href^="#"]:after,
  a[href^="javascript:"]:after {
    content: "";
  }

  pre,
  blockquote {
    border: 1px solid #999;
    page-break-inside: avoid;
  }

  thead {
    display: table-header-group;
  }

  tr,
  img {
    page-break-inside: avoid;
  }

  img {
    max-width: 100% !important;
  }

  p,
  h2,
  h3 {
    orphans: 3;
    widows: 3;
  }

  h2,
  h3 {
    page-break-after: avoid;
  }
}

a,
a:visited {
  color: #01ff70;
}

a:hover,
a:focus,
a:active {
  color: #2ecc40;
}

.retro-no-decoration {
  text-decoration: none;
}

html {
  font-size: 12px;
}

@media screen and (min-width: 32rem) and (max-width: 48rem) {
  html {
    font-size: 15px;
  }
}

@media screen and (min-width: 48rem) {
  html {
    font-size: 16px;
  }
}

body {
  line-height: 1.85;
}

p,
.retro-p {
  font-size: 1rem;
  margin-bottom: 1.3rem;
}

h1,
.retro-h1,
h2,
.retro-h2,
h3,
.retro-h3,
h4,
.retro-h4 {
  margin: 1.414rem 0 .5rem;
  font-weight: inherit;
  line-height: 1.42;
}

h1,
.retro-h1 {
  margin-top: 0;
  font-size: 3.998rem;
}

h2,
.retro-h2 {
  font-size: 2.827rem;
}

h3,
.retro-h3 {
  font-size: 1.999rem;
}

h4,
.retro-h4 {
  font-size: 1.414rem;
}

h5,
.retro-h5 {
  font-size: 1.121rem;
}

h6,
.retro-h6 {
  font-size: .88rem;
}

small,
.retro-small {
  font-size: .707em;
}

/* https://github.com/mrmrs/fluidity */

img,
canvas,
iframe,
video,
svg,
select,
textarea {
  max-width: 100%;
}

html,
body {
  background-color: #222;
  min-height: 100%;
}

html {
  font-size: 18px;
}

body {
  width: 100%;
  color: #fafafa;
  font-family: "Courier New";
  line-height: 1.45;
  padding: .25rem;
}

pre {
  background-color: #333;
}

blockquote {
  border-left: 3px solid #01ff70;
  padding-left: 1rem;
}

不行,代碼部分然而並無高亮,老闆,我要退貨!

//在 index.html的head 裏面加上
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/styles/default.min.css">

這樣我們的暗黑風的在線markdown日記應用就暫告一段落了,文中表述若是有不清不楚的,歡迎留言。同時我也是一命 new vuer,但願老鳥們可以指點!

相關文章
相關標籤/搜索