摘要:項目來源以前曾用過搭建自己的博客網站,但感覺很是臃腫。所以一直想自己寫一個博客內容管理器。正好近日看完了各個插件的文檔,就用著嘗試寫了這個簡約的博客內容管理器。關于后端后端是用作為服務器的,使用了框架。
項目來源
以前曾用過WordPress搭建自己的博客網站,但感覺WordPress很是臃腫。所以一直想自己寫一個博客內容管理器。
正好近日看完了Vue各個插件的文檔,就用著Vue嘗試寫了這個簡約的博客內容管理器(CMS)。
嗯,我想完成的功能:一個基本的博客內容管理器功能,如后臺登陸,發布并管理文章等
支持markdown語法實時編輯
支持代碼高亮
管理博客頁面的鏈接
博客頁面對移動端適配優化
賬戶管理(修改密碼)
Demo登陸后臺按鈕在頁面最下方“站長登陸”,可以以游客身份登入后臺系統。
源碼 用到的技術和實現思路: 前端:Vue全家桶Vue.js
Vue-Cli
Vue-Resource
Vue-Router
Vuex
后端:NodeNode.js
mongoDB (mongoose)
Express
工具和語言Webpack
ES6
SASS
整體思路:Node服務端不做路由切換,這部分交給Vue-Router完成
Node服務端只用來接收請求,查詢數據庫并用來返回值
所以這樣做前后端幾乎完全解耦,只要約定好restful數據接口,和數據存取格式就OK啦。
后端我用了mongoDB做數據庫,并在Express中通過mongoose操作mongoDB,省去了復雜的命令行,通過Javascript操作無疑方便了很多。
Vue的各個插件:vue-cli:官方的腳手架,用來初始化項目
vue-resource:可以看作一個Ajax庫,通過在跟組件引入,可以方便的注入子組件。子組件以this.$http調用
vue-router:官方的路由工具,用來切換子組件,是用來做SPA應用的關鍵
vuex:規范組件中數據流動,主要用于異步的http請求后數據的刷新。通過官方的vue-devtools可以無縫對接
文件目錄│ .babelrc babel配置 │ .editorconfig │ .eslintignore │ .eslintrc.js eslintrc配置 │ .gitignore │ index.html 入口頁面 │ package.json │ README.md │ setup.html 初始化賬戶頁面 │ webpack.config.js webpack配置 │ ├─dist 打包生成 │ ├─server 服務端 │ api.js Restful接口 │ db.js 數據庫 │ index.js │ init.json 初始數據 │ └─src │ main.js 項目入口 │ setup.js 初始化賬戶 │ ├─assets 外部引用文件 │ ├─css │ ├─fonts │ ├─img │ └─js │ ├─components vue組件 │ ├─back 博客控制臺組件 │ ├─front 博客頁面組件 │ └─share 公共組件 │ ├─router 路由 │ ├─store vuex文件 │ └─style 全局樣式
前端的文件統一放到了src目錄下,有兩個入口文件,分別是main.js和setup.js,有過WordPress經驗應該知道,第一次進入博客是需要設置用戶名密碼和數據庫的,這里的setup.js就是第一次登入時的頁面腳本,而main.js則是剩余所有文件的入口
main.jsimport Vue from "vue" import VueResource from "vue-resource" import {mapState} from "vuex" //三個頂級組件,博客主頁和控制臺共享 import Spinner from "./components/share/Spinner.vue" import Toast from "./components/share/Toast.vue" import MyCanvas from "./components/share/MyCanvas.vue" import store from "./store" import router from "./router" import "./style/index.scss" Vue.use(VueResource) new Vue({ router, store, components: {Spinner, Toast, MyCanvas}, computed: mapState(["isLoading", "isToasting"]) }).$mount("#CMS2")
而后所有頁面分割成一個單一的vue組件,放在components中,通過入口文件main.js,由webpack打包生成,生成的文件放在dist文件夾下。
后端文件放在server文件夾內,這就是基于Express的node服務器,在server文件夾內執行
node index
就可以啟動Node服務器,默認偵聽3000端口。
?關于 WebpackWebpack的配置文件主體是有vue-cli生成的,但為了配合后端自動刷新、支持Sass和生成獨立的css文件,稍微修改了一下:
webpack.config.jsconst path = require("path") const webpack = require("webpack") const ExtractTextPlugin = require("extract-text-webpack-plugin") const CopyWebpackPlugin = require("copy-webpack-plugin") //萃取css文件,在此命名 const extractCSSFromVue = new ExtractTextPlugin("styles.css") const extractCSSFromSASS = new ExtractTextPlugin("index.css") module.exports = { entry: { main: "./src/main.js", setup: "./src/setup.js" }, output: { path: path.resolve(__dirname, "./dist"), publicPath: "/dist/", filename: "[name].js" }, resolveLoader: { moduleExtensions: ["-loader"] }, module: { rules: [ { test: /.vue$/, loader: "vue", //使用postcss處理加工后的scss文件 options: { preserveWhitespace: false, postcss: [ require("autoprefixer")({ browsers: ["last 3 versions"] }) ], loaders: { sass: extractCSSFromVue.extract({ loader: "css!sass!", fallbackLoader: "vue-style-loader" }) } } }, { test: /.scss$/, loader: extractCSSFromSASS.extract(["css", "sass"]) }, { test: /.js$/, loader: "babel", exclude: /node_modules/ }, { test: /.(png|jpg|gif|svg)$/, loader: "file", options: { name: "[name].[ext]?[hash]" } }, //字體文件 { test: /.woff(2)?(?v=[0-9].[0-9].[0-9])?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" }, { test: /.(ttf|eot|svg)(?v=[0-9].[0-9].[0-9])?$/, loader: "file-loader" } ] }, plugins: [ //取出css生成獨立文件 extractCSSFromVue, extractCSSFromSASS, new CopyWebpackPlugin([ {from: "./src/assets/img", to: "./"} ]) ], resolve: { alias: { "vue$": "vue/dist/vue" } }, //服務器代理,便于開發時所有http請求轉到node的3000端口,而不是前端的8080端口 devServer: { historyApiFallback: true, noInfo: true, proxy: { "/": { target: "http://localhost:3000/" } } }, devtool: "#eval-source-map" } if (process.env.NODE_ENV === "production") { module.exports.devtool = "#source-map" module.exports.plugins = (module.exports.plugins || []).concat([ new webpack.DefinePlugin({ "process.env": { NODE_ENV: ""production"" } }), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), new webpack.LoaderOptionsPlugin({ minimize: true }) ]) }
運行
npm start
后,node端開啟了3000端口,接著運行
npm run dev
打開webpack在8080端口服務器,具有動態加載的功能,并且所有的http請求會代理到3000端口
關于Vue-Router因為寫的是但也應用(SPA),服務器不負責路由,所以路由方面交給Vue-Router來控制。
router.jsimport Vue from "vue" import Router from "vue-router" //博客頁面 import Archive from "../components/front/Archive.vue" import Article from "../components/front/Article.vue" //控制臺頁面 import Console from "../components/back/Console.vue" import Login from "../components/back/Login.vue" import Articles from "../components/back/Articles.vue" import Editor from "../components/back/Editor.vue" import Links from "../components/back/Links.vue" import Account from "../components/back/Account.vue" Vue.use(Router) export default new Router({ mode: "history", routes: [ {path: "/archive", name: "archive", component: Archive}, {path: "/article", name: "article", component: Article}, {path: "/", component: Login}, { path: "/console", component: Console, children: [ {path: "", component: Articles}, {path: "articles", name: "articles", component: Articles}, {path: "editor", name: "editor", component: Editor}, {path: "links", name: "links", component: Links}, {path: "account", name: "account", component: Account} ] } ] })文檔首頁 ? index.html ?
cms2simple
可以看到路由控制在body元素下的router-view中。前面的spinner,toast元素分別是等待效果(轉圈圈)的彈出層和信息的彈出層,和背景樣式的切換。
關于后端后端是用node.js作為服務器的,使用了express框架。
其中代碼非常簡單:
index.jsconst fs = require("fs") const path = require("path") const express = require("express") const favicon = require("serve-favicon") const bodyParser = require("body-parser") const cookieParser = require("cookie-parser") const db = require("./db") const resolve = file => path.resolve(__dirname, file) const api = require("./api") const app = express() // const createBundleRenderer = require("vue-server-renderer").createBundleRenderer app.set("port", (process.env.port || 3000)) app.use(favicon(resolve("../dist/favicon.ico"))) app.use(bodyParser.json()) app.use(bodyParser.urlencoded({extended: false})) app.use(cookieParser()) app.use("/dist", express.static(resolve("../dist"))) app.use(api) app.post("/api/setup", function (req, res) { new db.User(req.body) .save() .then(() => { res.status(200).end() db.initialized = true }) .catch(() => res.status(500).end()) }) app.get("*", function (req, res) { const fileName = db.initialized ? "index.html" : "setup.html" const html = fs.readFileSync(resolve("../" + fileName), "utf-8") res.send(html) }) app.listen(app.get("port"), function () { console.log("Visit http://localhost:" + app.get("port")) })
服務器做的事情很簡單,畢竟路由在前端。在接受請求的時候判斷一下數據庫是否初始化,如果初始化就轉向主頁,否則轉向setup.html,之所以沒有直接sendfile是因為考慮到之后添加服務端渲染(雖然主頁并沒有啥值得渲染的,因為很簡單)
express框架中使用了mongoose來連接mongoDB數據庫,在接收請求時做對應的curd操作,比如這就是在接收保存文章時對應的操作:
api.jsrouter.post("/api/saveArticle", (req, res) => { const id = req.body._id const article = { title: req.body.title, date: req.body.date, content: req.body.content } if (id) { db.Article.findByIdAndUpdate(id, article, fn) } else { new db.Article(article).save() } res.status(200).end() })后記
當然還有很多沒提及的地方,最早寫這個博客管理器的時候用的還是vue 1.x,后來用2.0改寫后文檔一直沒改,所以最近更新了一下,避免誤解。
其實整個管理器最復雜的地方時vuex異步數據視圖的部分,不過這一部能講的太多,就不在這里展開了,可以看官方文檔后,參考源代碼的注釋。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80406.html
摘要:利用中間件實現異步請求,實現兩個用戶角色實時通信。目前還未深入了解的一些概念。往后會寫更多的前后臺聯通的項目。刪除分組會連同組內的所有圖片一起刪除。算是對自己上次用寫后臺的一個強化,項目文章在這里。后來一直沒動,前些日子才把后續的完善。 歡迎訪問我的個人網站:http://www.neroht.com/? 剛學vue和react時,利用業余時間寫的關于這兩個框架的訓練,都相對簡單,有的...
摘要:三更新內容在原來項目的基礎上,做了如下更新數據庫重新設計,改成以用戶分組的數據庫結構應數據庫改動,所有接口重新設計,并統一采用和網易立馬理財一致的接口風格刪除原來游客模式,增加登錄注冊功能,支持彈窗登錄。 這個項目最初其實是fork別人的項目。當初想接觸下mongodb數據庫,找個例子學習下,后來改著改著就面目全非了。后臺和數據庫重構,前端增加了登錄注冊功能,僅保留了博客設置頁面,但是...
摘要:開發一個完整博客流程前言前段時間剛把自己的個人網站寫完,于是這段時間因為事情不是太多,便整理了一下,寫了個簡易版的博客系統服務端用的是框架進行開發技術棧目錄結構講解的配置文件放置代碼文件項目參數配置的文件日志打印文件項目依賴模塊 Vue + Node + Mongodb 開發一個完整博客流程 前言 前段時間剛把自己的個人網站寫完, 于是這段時間因為事情不是太多,便整理了一下,寫了個簡易...
閱讀 977·2021-11-22 09:34
閱讀 2161·2021-11-11 16:54
閱讀 2196·2021-09-27 14:00
閱讀 940·2019-08-30 15:55
閱讀 1525·2019-08-29 12:46
閱讀 599·2019-08-26 18:42
閱讀 639·2019-08-26 13:31
閱讀 3183·2019-08-26 11:52