在接觸vue
以後,就一直想用vue把原來老舊的博客(基於jquery
和php
)從新搭一遍,在摸了幾個月後,總算摸出來了😂.前端部分只涉及到vue
,關於koa2
和mongodb
請移步到後端部分.php
博客地址:
dawkey.topcss
推薦在PC端訪問,移動端作了相關兼容,不過在PC端上效果要更好.html
github地址:
github.com/Dawkey/dkyS…前端
後端部分:
github.com/wwk321/dkyS…vue
vue
,vuex
,vue-router
(vue
的全家桶走一下流程);axios
發送ajax請求(這個也不用多說);marked
把markdown
轉爲html
(比本身瞎寫的md-html
好用多了);highlight
代碼語法高亮;基本上就是搭建博客經常使用的一些庫.jquery
我要開始甩圖片了😂ios
後臺管理界面也是集成在前端部分的,後端部分只負責處理數據就好了.css3
想要經過瀏覽器看一下後臺界面的朋友,能夠經過
login
界面的visit
按鈕(不須要帳號密碼),直接進入後臺管理哦,不過沒有相關權限就是了😁(移動端沒有login
選項)git
發了這麼多演示圖,尚未些什麼實質性的東西.github
主要記錄一下博客搭建中的遇到的一些問題:
博客作的是單頁面的,因此咱們因此的數據獲取都是經過ajax
的.
個人思路是在頁面加載時,就請求一個main
的關鍵數據,它是一個數組,其中包含着每篇博客的標題,標籤,分類,時間,描述,以及關鍵的id
號(這裏id
號在請求博客文章數據時會用到).
對這一個數組數據用js
進行加工,咱們就能獲得了home(首頁)
,tag(標籤)
,classify(分類)
,archive(歸檔)
這四個頁面(也是通常博客最基礎的)所須要的數據,把這些數據存入到vuex
中.
這樣,單頁面較多頁面的優點就體現出來了,咱們只請求了一次數據,以後,咱們再訪問上面提到的四個頁面,就不再會請求任何數據,甚至斷網也能正常訪問(除非刷新頁面)
當咱們想要查看一篇博客文章的具體內容時,點擊以後,根據前面提到的對應的id
號,就會經過ajax
請求對應的文章數據,最終顯示瀏覽器上就完事了.
至於還有一個update(更新日誌)
,這個在訪問它時,單獨請求數據就好了.
原理上能夠說是很是簡單😆
由於作的是單頁面,頁面間的切換是不可避免的,在寫頁面切換時,我嘗試了不少種動畫切換(本人是極端的外觀黨😖),最終還選擇瞭如今這種比較傳統的方式.
具體的實現方式是,使用vue-router
中的導航守衛中的beforeEach
(具體查看vue-router的文檔),在每次切換路由時,都先顯示一段時間的加載動畫,以後才顯示出頁面,傳統,可是實在沒想出或者說實現出什麼炫酷的切換方式.
marked
和highlight
實現的文本編輯:這兩哥們應該是搭建博客系統時,文本編輯的標配:
關於這二者的使用網上也是有不少了,這裏我主要記錄一下我在使用這二者時,遇到的一些坑,我的的一些理解,方便一樣想要搭建本身博客系統的朋友使用.
marked
和highlight
組合達到語法高亮:這個問題應該是首要的,博客文章代碼不高亮,乾巴巴一片,就太醜了
其實就是要用到marked
的renderer
,直接看代碼:(終於要上代碼了😆)
import marked,{Renderer} from "marked";
import hljs from "highlight.js";
const renderer = new Renderer();
renderer.code = (code,language) => {
if(!language){
language = "code";
}
let lang_is_valid = (language !== "code" && hljs.getLanguage(language));
let highlighted = lang_is_valid ? hljs.highlight(language, code).value : code;
return `<pre><div class="language">${language}</div><code class="hljs ${language}">${highlighted}</code></pre>`;
};
marked.setOptions({renderer});
複製代碼
咱們先把工做分配明確,在實現語法高亮時,highlight
負責把代碼字符串轉換爲具備語法高亮結構的html
字符串,marked
只負責告訴highlight
這串代碼用的什麼編程語言.
好了,接着看上面的代碼,marked
的renderer
適用於咱們來DIY它最終生成的html
代碼,代碼中的renderer.code
天然指的是最終生成的代碼相關的html
.
它是一個函數,這裏咱們能夠理解爲要重寫這個函數,這個函數最終調用時,會傳入兩個參數,第一個code
是代碼字符串,第二個language
是代碼的編程語言.
代碼中的hljs.highlight(language, code).value
就是最終根據marked
提供的兩個參數值,所生成的具備代碼高亮結構的html
字符串.
再來看最終的return
值,咱們能夠注意到code
標籤裏面class
值是"hljs空格+編程語言"
,這個class
格式是必須的,以告訴highlight
最終怎麼高亮.
以上工做作完以後,咱們marked()
返回的就是具備高亮代碼格式的html
字符串,固然前提是咱們有引入highlight
提供的css
,最終咱們才能看到高亮的代碼.
marked
是怎麼知道咱們的代碼是什麼編程語言😐,好吧,是我當時孤陋寡聞了😂,使用柵欄代碼塊來寫代碼,讓咱們來告訴marked
咱們的語言.
marked
生成的連接能跳轉到新的標籤:默認狀況先,
marked
生成的a
標籤是在當前頁跳轉的,一樣用renderer
咱們能夠適當修改一下就行了:
renderer.link = (href,title,text) => {
return `<a href="${href}" target="_blank">${text}</a>`;
}
複製代碼
Mayuri指的就是博客左上角的那個動漫頭像,在最開始搭建博客時,我就已經想好要作這個了,當時還準備作幾個表情,截了相關的圖,不過由於暑假摸了過久,致使目前博客上線時,還只有這個初始的表情.
未來也許可能會新增幾個表情吧😶
若是你不仔細看,可能不會發如今出現消息文字時,Mayuri的嘴部是在動的.
其實就是三張圖片之間在互相切換,由於本人沒有一點動漫製做的相關知識,所寫這個css
的動畫徹底是憑感受(瞎)寫的,最終的效果還行吧,不過仍是有一點小瑕疵的😑.
由於只涉及到一點css3
的知識,這裏就不貼代碼了.
打字動畫的實現,網上講述的也很多了,可是,我仍是想結合個人項目寫一寫,對這個不感興趣的朋友能夠直接跳過.
打字動畫用js
實現效果肯是要比css
要好的,本質上就是,經過不斷的更換一個元素的innerHTML
來達到打字的效果.
這裏我用到了Promise
鏈,當時剛剛看了promise
,就用了,不知道有沒有把這個問題複雜化😕.
貼代碼:
export default function type(el,word){
let word_array = word.split("");
let promise = Promise.resolve();
word_array.reduce((meno,value,index)=>{
let str = meno + value;
if(index === 1){
promise = type_timer(el,meno);
}
promise = promise.then(()=>{
return type_timer(el,str);
});
return str;
});
return promise;
}
//生成新的promise,串成promise鏈
function type_timer(el,str){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
el.innerHTML = str;
resolve();
},115);
});
}
複製代碼
這裏咱們export
出了type
方法,type
方法,第一個參數是輸出文字元素對象,第二個參數是輸出的文字,執行type(el,word),就能實現打字效果了.
具體看代碼,type_timer
生成一個含有setTimeout
的Promise
,咱們對輸出的文字進行分割,獲得word_array
數組,再用數組的reduce
方法串出一條Promise
鏈;
使用Promise
鏈的好處就是,咱們能夠經過then
很好的知道何時打字動畫結束了.
對話之間的衝突😕
有時候,咱們一條消息對話尚未打完,下一條消息就產生了,這時,確定會產生兩條Promise
鏈做用於同一個元素,這就發生了衝突.
這時,咱們有兩種選擇:
Promise
鏈執行完,再執行下一條;reject
當前Promise
鏈,執行下一條.我選擇了第二種作法,於是須要在上面的代碼上稍做修改:
export default function type(el,word,$store){
let word_array = word.split("");
let promise = Promise.resolve();
word_array.reduce((meno,value,index)=>{
let str = meno + value;
if(index === 1){
promise = type_timer(el,meno,$store);
}
promise = promise.then(()=>{
return type_timer(el,str,$store);
});
return str;
});
return promise;
}
//生成新的promise,串成promise鏈
function type_timer(el,str,$store){
return new Promise((resolve,reject)=>{
//若是talk_flag === false,則reject,以防止生成多條promise鏈產生衝突.
if($store.getters["talk_flag"] === false){
reject("talk_is_break");
}
setTimeout(()=>{
el.innerHTML = str;
resolve();
},115);
});
}
複製代碼
用了vuex
😬,在vuex
中存儲一個變量talk_flag
,在執行type
方法時,傳入第三個參數,vuex
的$store
對象.
每次咱們建立新的消息對話時,先把vuex
中的talk_flag
設爲false
,保證,先前的Promise
鏈必定會斷掉,而在Promise
鏈斷後,調用的type
方法就會catch
到reject
,在catch
中,咱們再從新把talk_flag
設爲true
,保證新的Promise
鏈能順利執行.
好吧,寫到這裏我忽然意識到,根本不須要用到
vuex
,一個普通的對象就好了,當時編寫時,可能以爲vuex
對象更厲害吧😃.
固然,若是有的朋友有更好的實現手段能夠和我交流(應該沒人有耐心看完這段碎碎唸吧~)
不知不覺竟然寫了這麼多,算是這幾個月的成果的一個總結,無論怎樣,接着努力吧,固然更重要的是但願能對和我同樣,想要親手搭建一個屬於本身博客的朋友有所幫助吧.
若是你有耐心看到這裏,不防👉這裏點個star⭐吧,也算是對個人一點小小的鼓勵😂
不存在的😆