簡單作個博客。
功能點:
註冊、登陸、cookie、權限控制、文章列表、文章詳情、文章目錄、點贊、評論、分頁加載css
npm install -g @vue/cli vue create hello-world
爲了避開煩人的 eslint,選擇了手動選擇特性:
同時沒有選擇 Linter/Formatter,使用 vscode 中的插件 prettier 和 vetur 配合格式化代碼。html
參考了vue中Axios的封裝和API接口的管理,對網絡請求進行了發封裝。
網絡請求統一放在/src/request
中,config.js
中是基本配置信息:http.js
中封裝請求攔截、響應攔截、錯誤統一處理。api.js
中是網站全部接口,將其導出後,掛載到 vue.prototype.$api
上,這樣全局可使用 this.$api.xxx
使用接口:
而後在main.js
引入並掛載:前端
博客採用cookie/session的方式來記錄會話狀態,在app.vue
的created
生命週期函數中經過checkLogin()
接口查詢用戶登陸狀態,具體的邏輯爲:vue
let documentEle = document.documentElement let needLoadMore = documentEle.scrollTop + documentEle.clientHeight + 50 > documentEle.scrollHeight; if (needLoadMore && !this.nomore) { this.loadingMore = true; //暫時不能再滾動加載數據 this.nomore = true; this.loadMoreArticle(); }
document.documentElement.scrollTop
:文檔滾動的距離document.documentElement.clientHeight
:文檔在可視範圍內的高度document.documentElement.scrollHeight
:文檔總高度java
判斷思路是:視口的高度 + 文檔的滾動距離 >= 文檔總高度,能夠預留50的距離作預加載。前端每一次判斷觸底後,會向後端請求下一頁數據,並返回 nomore
字段,表示是否還有未加載文章。這裏有個細節是:每一次觸底後手動將 nomore
設爲 true
,後端返回 nomore
後再修改其值,這樣作的目的是防止在請求返回前再次發送請求。
參考:搞清clientHeight、offsetHeight、scrollHeight、offsetTop、scrollTopmysql
沒有實際作博客以前,覺得每一篇博文都是經過單獨寫html標籤的方式排版的...而後經過別人的項目,發現了正確的作法是:
使用markdown/富文本編輯器編輯文章,生成html
片斷,在vue中使用v-html
語法插入該html
片斷,文章便以html
標籤的形式渲染出來可。博客中使用的markdown編輯器是mavonEditor,另外使用highlightjs
高亮代碼。linux
<div v-html="articleInfo.contentHtml" class="article-container" ref="content"></div>
extractCatalog() { let contentElementRef = Array.from( this.$refs.content.querySelectorAll("h1,h2,h3,h4,h5,h6") ); contentElementRef.forEach((item, index) => { item.id = item.localName + "-" + index; this.catalogList.push({ tagName: item.localName, href: `#${item.localName}-${index}`, text: item.innerText }); }); }
上一小節中,將文章的html
片斷渲染到了div
容器元素中,接下來可使用querySelectorAll("h1,h2,h3,h4,h5,h6")
函數來找出文中全部的標題Dom節點,querySelectorAll()
的好處在於它會按照傳入參數的順序進行查找,因此不用擔憂亂序。獲取到目錄後對各級目錄編號,以便生成錨點進行跳轉。ios
watchPageScrollFunc() { let contentElementRef = Array.from( this.$refs.content.querySelectorAll("h1,h2,h3,h4,h5,h6") ); for (let index = 0; index < contentElementRef.length; index++) { const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; const elementHeight = contentElementRef[index].clientHeight; const el = contentElementRef[index]; const top = el.getBoundingClientRect() && el.getBoundingClientRect().top + elementHeight; if (top <= viewPortHeight && top > 0) { this.firstVisibleElemetHref = this.catalogList[index].href; break; } } } window.addEventListener("scroll", this.watchPageScrollFunc);
判斷方法:元素上邊到視口上邊的距離 + 元素自身高度 <= 視口高度 && 元素上邊到視口上邊的距離 + 元素自身高度 > 0
其中,獲取元素到視口上邊的距離用到:getBoundingClientRect()
,某個元素相對於視窗的位置集合。集合中有top, right, bottom, left等屬性:nginx
rectObject = object.getBoundingClientRect(); rectObject.top // 元素上邊到視窗上邊的距離; rectObject.right // 元素右邊到視窗左邊的距離; rectObject.bottom // 元素下邊到視窗上邊的距離; rectObject.left // 元素左邊到視窗左邊的距離;
在整個文章的Dom結構中,使用querySelectorAll("h1,h2,h3,h4,h5,h6")
去搜索全部標題類的Dom節點,每一次滾動都去依次動態檢查這些標題元素距離視口上方的距離,找到第一個出如今視口中的Dom元素就返回。另外加上節流函數可優化性能。git
評論數據採用的數據結構以下,這裏只作到了二級評論,數據結構定下來,具體的實現仍是比較簡單的。
let comments = [ { author: "admin", content: "留言1", articleId: "9", time: "2020-04-12 10:59", id: "0", replyList: [ { author: "ghm", content: "回覆留言1", articleId: "9", replyTo: "admin", time: "2020-04-12 10:59", id: "0-0" } ] }, { author: "admin", content: "留言2", articleId: "9", time: "2020-04-12 10:59", id: "1", replyList: [ { author: "ghm", content: "回覆留言2", articleId: "9", replyTo: "admin", time: "2020-04-12 11:00", id: "1-0" } ] } ];
初版的實現方式:在<input>
中直接插入emoji
的unicode
,展現效果以下所示:
這樣作的問題在於:展現效果沒有圖片好,而且在不一樣的瀏覽器中會展示出不一樣的效果。果斷換用圖片形式展現表情,可是<input>
是不能插入<img>
標籤的,因而參考了掘金的實現方式,使用contenteditable
這個css屬性將普通Dom元素變爲可編輯的Dom元素,這樣就可使用appendChild()
的方式將<img>
插入,最終的顯示效果也是明顯優於直接使用emoji
的。
<div class="textarea" ref="inputContent" contenteditable="true" autocomplete="off" :placeholder="placeholder" draggable="false" spellcheck="false" ></div>
1.一臺linux服務器
做者買的阿里雲最便宜的ECS雲服務器,配置爲1核2G,1M帶寬,做爲學習使用徹底夠了,操做系統選擇的CentOS。而後參照阿里雲給出的教程在服務器上部署NodeJs環境,部署mysql。
2.購買域名
在阿里雲上購買域名後,按照新手引導設置域名解析,同時設置 www 和 @,網站即可經過 www.xxx.com 和 xxx.com 訪問。同時,想要使用域名訪問網站,還須要對域名進行備案。
3.本地數據庫遷移到雲服務器
做者使用的數據庫可視化工具是navicat,在navicat中對選中的數據庫作轉儲SQL文件處理,再在雲服務器的mysql中新建數據庫,運行此SQL文件,便完成了數據庫的遷移。
1.下載文件傳輸工具 Xftp
2.部署前端代碼
npm run build
打包好後,使用 Xftp 將 dist
文件夾上傳到服務器中
3.部署後端代碼
將後端代碼 git clone
到服務器中
npm i npm start
1.安裝nginx
yum install nginx
安裝好的 nginx 會在 /etc/nginx
中
2.使用 Xftp 修改 nginx 配置
找到/etc/nginx
目錄下的 nginx.conf
文件,使用記事本打開編輯:
user root; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name localhost; root /root/project/dt_blog/frontend/dist/; index index.html; add_header Access-Control-Allow-Origin *; location /api { proxy_pass http://127.0.0.1:7001; proxy_set_header HOST $host; } location / { try_files $uri $uri/ @router; index index.html; } location @router { rewrite ^.*$ /index.html last; } } }
其中這兩個配置很重要:
location / { try_files $uri $uri/ @router; index index.html; } location @router { rewrite ^.*$ /index.html last; }
網站部署好後,能夠正常訪問,可是打開二級頁面後再刷新,就會404,緣由是:v-router設置的路徑並非真實存在的路由,工程中的路由跳轉都是經過 js 實現的,而將前端打包好的 dist
目錄部署在服務器後,在瀏覽器中訪問根路徑會默認打到 index.html 中,可是直接訪問其餘路徑,就沒有一個真實的路徑與其對應。(參考:https://www.cnblogs.com/kevingrace/p/6126762.html)
作好以上配置後,就能夠經過 服務器ip:80
來訪問部署好的網站了,可是一直經過 ip 地址訪問網站不太合理,那麼就須要給網站配置域名。