一.前言
文章主要以巨集觀的形式來聊一個全棧開發專案,非常適合初級階段學習前端的小白,適當的全棧開發是前端學習在初級階段所必須要有的技能。大多數人都知道的是,一個全棧開發專案是大多是由:電商系統+社交系統+部落格系統 構成。但我們不知道的是其中的種種原理和方法。而我今天要講解的專案就是以部落格的形式為例子,幫助大家解開疑惑。
說在前面
還未安裝vue?這裡有vue的安裝教程,很詳細噢!當然如果你vue基礎不是很好的話,這裡也有幫助你提升vue專案的視訊。技術胖vue視訊教程
這是一篇基於vue & mongodb 為主的專案,如果還未安裝mongodb,可以參考mongodb安裝教程,操作簡單,容易上手,想要弄懂全棧專案用vue如何構建全棧專案?就快快花幾分鐘時間瀏覽這篇文章吧!
二. 問題提出:部落格(blog)
- 思路
- 在整棧專案中,我們需要建立前端(web)和後端(server)分離的框架。除此之外,還需要有在後臺(admin)開發的思想。或許很多人被我這麼一說繞暈了,那麼我就和你說說它們之間的區別。
前端後端後臺的區別 後臺:提供給系統管理者能夠看到的頁面,而遊客、使用者看不到的頁面;前端:程式設計師在進行程式設計的時候的程式碼;後端:對應前端而言的,編寫程式碼基本上是提供給前端呼叫,是不需要處理UI的內容.比如:邏輯層。
- 前端我們需要進行的頁面操作,後端資料庫的連線,後臺的管理到底如何去執行?
前端(web)我們需要使用vue建立一個新的前端專案,相對來說:vue使用者體驗好,並且相對react來說更容易上手,且vue為單頁應用。而後端(server)主要用於對部落格文章的增刪改查,提供api。後臺(admin)則是幫助管理員處理事物,本文章暫不涉及後臺的內容。因此我們全棧開發的大致思路就搭建好啦!
三.具體講解
- 專案的建立過程:在vue目錄下新建blog資料夾,在blog資料夾下新建server資料夾和admin資料夾。
後端server
1.首先我們要將server檔案進行初始化 npm init -y
.之後,我們需要在server資料夾上新建資料夾db,在db資料夾中新建檔案db.js,建立該檔案的目的是連線本地的資料庫。localhost:27017是mongodb預設的地址
,這是一個常考點。連線本地資料庫之後,在mongodb中可以使用use myblog
切換進blog系統。程式碼如下:
// 資料庫層的分離 向外提供
module.exports = app => {
// mongodb 的驅動
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/myblog', {
useNewUrlParser: true // 屬性設定為true來避免"不建議使用當前URL字串解析器"警告,相容moogoose的新的URL連線的機制。
})
}
複製程式碼
2. 接下來,我們要做的事情就是建立資料庫的連線。我們在server資料夾下新建index.js檔案。程式碼裡有引入express腳手架,我們可以通過yarn add express
來新增express腳手架。如果對express有疑問的大佬們,這裡也有關於express腳手架的講解。程式碼如下:
const express = require('express');
const app = express();
// 將db.js 引入
// import es6 模組化 es5 require
// require('./db/db')(app); //資料庫的連線
複製程式碼
使用
node index.js
執行專案,沒有報錯則代表資料庫連線成功。
3. 現在我們就要開始建表,將表設計都分成獨立的模組來建立。可以去想想要做blog,我們需要建哪幾張表呢?首先我們必須要建的表是文章表:Article.js。在mongodb中,我們建的表都叫做collection(集合)。程式碼如下:
// 建表 collection
// 1. Schema 表設計
// 2. 模型物件 返回
const mongoose = require('mongoose')
const schema = new mongoose.Schema({
uid: {
type: mongoose.SchemaTypes.ObjectId,
ref: 'User'
},
title: { type: String },
isTop: { type: Boolean}, //是否置頂
summary: { type: String }, // 列表裡的介紹
body: { type: String },
categories:[{ type: mongoose.SchemaTypes.ObjectId, ref:'Category'}]
}) // ref:category 外來鍵關係,一個文章可以有多個類別。
//類 表 articles
module.exports = mongoose.model('Article', schema, 'articles');
複製程式碼
在文章表中值得一提的是裡面有一個新增
mongoose
,Mongoose是MongoDB的一個物件模型工具,是基於node-mongodb-native開發的MongoDB nodejs驅動,可以在非同步的環境下執行。同時它也是針對MongoDB操作的一個物件模型庫,封裝了MongoDB對文件的的一些增刪改查等常用方法,讓NodeJS操作Mongodb資料庫變得更加靈活簡單。我們依舊可以通過yarn add mongoose
來新增mongoose。
4. 使用者表User.js程式碼如下:
// blog 分類的Schema
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const schema = mongoose.Schema({
username: {
type: String
},
password: {
type: String,
// 獲取使用者資料的時候, 不要把密碼取出去
select: false, // select 查詢
set(val) {
return bcrypt.hashSync(val, 10) // 不會存明文密碼
}
},
// 使用者和文章的關係 ?
})
// model -> mongodb 儲存到底做了什麼事情? mongoose
module.exports = mongoose.model('User', schema, 'users')
複製程式碼
在這裡有一個
bcrypt
加密解密演算法,需要通過yarn add bcrypt
新增方法,代表對使用者輸入的密碼進行加密解密。
5. 文章分類表Category.js。
// blog 分類的Schema
const mongoose = require('mongoose');
const schema = mongoose.Schema({
title: { type: String }
})
// model -> mongodb 儲存到底做了什麼事情? mongoose
module.exports = mongoose.model('Category', schema, 'categories')
複製程式碼
接下來就是前端部分的講解。
- 首先我們要掌握vue-router的兩種模式的區別: 眾所周知,vue-router有兩種模式,hash模式和history模式,這裡來談談兩者的區別。
- hash模式: hash模式背後的原理是onhashchange事件,可以在window物件上監聽這個事件: 上面的程式碼可以通過改變hash來改變頁面字型顏色,雖然沒什麼用,但是一定程度上說明了原理。更關鍵的一點是,因為hash發生變化的url都會被瀏覽器記錄下來,從而你會發現瀏覽器的前進後退都可以用了,同時點選後退時,頁面字型顏色也會發生變化。這樣一來,儘管瀏覽器沒有請求伺服器,但是頁面狀態和url一一關聯起來,後來人們給它起了一個霸氣的名字叫前端路由,成為了單頁應用標配。
- history路由: 隨著history api的到來,前端路由開始進化了,前面的hashchange,你只能改變#後面的url片段,而history、api則給了前端完全的自由,history,api可以分為兩大部分,切換和修改切換歷史狀態包括back,forward,go三個方法,對應瀏覽器的前進,後退,跳轉操作,有同學說了,(谷歌)瀏覽器只有前進和後退,沒有跳轉,嗯,在前進後退上長按滑鼠,會出來所有當前視窗的歷史記錄,從而可以跳轉(也許叫跳更合適):
history.go(-2);//後退兩次
history.go(2);//前進兩次
history.back(); //後退
hsitory.forward(); //前進
複製程式碼
修改歷史狀態 包括了pushState,replaceState兩個方法,這兩個方法接收三個引數:stateObj,title,url
history.pushState({color:'red'}, 'red', 'red'})
window.onpopstate = function(event){
console.log(event.state)
if(event.state && event.state.color === 'red'){
document.body.style.color = 'red';
}
}
history.back();
history.forward();
複製程式碼
通過pushstate把頁面的狀態儲存在state物件中,當頁面的url再變回這個url時,可以通過event.state取到這個state物件,從而可以對頁面狀態進行還原,這裡的頁面狀態就是頁面字型顏色,其實滾動條的位置,閱讀進度,元件的開關的這些頁面狀態都可以儲存到state的裡面。
history模式怕啥: 通過history api,我們丟掉了醜陋的#,但是它也有個毛病: 不怕前進,不怕後退,就怕重新整理,f5,(如果後端沒有準備的話),因為重新整理是實實在在地去請求伺服器的,不玩虛的。
- 在Vue中,我們需要在router資料夾下的index.js新增路由,目的就是為了引入建立的vue專案。程式碼如下:
// 引入vue專案 新增專案的路徑
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Main from '../views/Main.vue'
import Article from '../views/Article.vue'
import Tag from '../views/Tag.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
//列表頁
{
path: '/main',
name: 'main',
component: Main
},
// 文章
{
path: '/article/:id',
name: 'article',
component: Article
},
//每個分類下有多少文章
{
path: '/tag',
name: 'tag',
component: Tag
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
複製程式碼
建立文章頁面的時候,它的路徑是這樣的:path: '/article/:id',裡面的id代表動態路由,根據id的不同檢視不同的文章。
- 既然我們引入了vue頁面,就必須去建立相應的檔案。因此,我views目錄下新建main.vue,article.vue,tag.vue檔案。
- 檔案的專案目錄
- 最後,我們在components目錄下新建元件檔案:如頭部元件,腳部元件,載入元件,評論元件以及文章專案元件,而這些都是blog會複用的元件。
執行結果
- localhost:8081埠
- localhost:3001埠
文章看到現在,相信讀者朋友們是知道了
router + views + components
功能分別是什麼啦!
打包上線
- 使用
npm run build
命令,將web檔案打包成dist
,打包後將檔案放至server目錄下,之後將檔名改成web。進行專案上線,在後端進行上線。 - 回到後端server目錄下,新增程式碼:
app.use('/', express.static(__dirname + '/web'))
app.listen('3001', async(req, res) => {
console.log('http://localhost:3001');
})
複製程式碼
在此處,express,static是express提供的靜態資源,之後在將打包中的內容展示出來,後端就等著你把vue打包好的靜態資源給你一個包,後端把包放進伺服器中,啟動根路由,交給web目錄,之後網路端訪問即可。
總結專案執行順序
- vue 寫完後,npm run build 生成一包靜態檔案。
- 靜態檔案包放到伺服器目錄下。
- 在把vue釋出出去。
- 最後在3001埠驅動(上線)
結束
文章看到現在也結束啦,第一次寫文章,如果有錯誤的話就麻煩大家給我指出來吧!如果覺得不錯的話別忘了點個贊?再走噢!
最後附上Github地址
- 原始碼地址:blog