成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Vue.js實(shí)踐:一個(gè)Node.js+mongoDB+Vue.js的博客內(nèi)容管理系統(tǒng)

Dr_Noooo / 2041人閱讀

摘要:項(xiàng)目來源以前曾用過搭建自己的博客網(wǎng)站,但感覺很是臃腫。所以一直想自己寫一個(gè)博客內(nèi)容管理器。正好近日看完了各個(gè)插件的文檔,就用著嘗試寫了這個(gè)簡約的博客內(nèi)容管理器。關(guān)于后端后端是用作為服務(wù)器的,使用了框架。

項(xiàng)目來源

以前曾用過WordPress搭建自己的博客網(wǎng)站,但感覺WordPress很是臃腫。所以一直想自己寫一個(gè)博客內(nèi)容管理器。

正好近日看完了Vue各個(gè)插件的文檔,就用著Vue嘗試寫了這個(gè)簡約的博客內(nèi)容管理器(CMS)。

嗯,我想完成的功能:

一個(gè)基本的博客內(nèi)容管理器功能,如后臺(tái)登陸,發(fā)布并管理文章等

支持markdown語法實(shí)時(shí)編輯

支持代碼高亮

管理博客頁面的鏈接

博客頁面對(duì)移動(dòng)端適配優(yōu)化

賬戶管理(修改密碼)

Demo

登陸后臺(tái)按鈕在頁面最下方“站長登陸”,可以以游客身份登入后臺(tái)系統(tǒng)。

源碼 用到的技術(shù)和實(shí)現(xiàn)思路: 前端:Vue全家桶

Vue.js

Vue-Cli

Vue-Resource

Vue-Router

Vuex

后端:Node

Node.js

mongoDB (mongoose)

Express

工具和語言

Webpack

ES6

SASS

整體思路:

Node服務(wù)端不做路由切換,這部分交給Vue-Router完成

Node服務(wù)端只用來接收請(qǐng)求,查詢數(shù)據(jù)庫并用來返回值

所以這樣做前后端幾乎完全解耦,只要約定好restful數(shù)據(jù)接口,和數(shù)據(jù)存取格式就OK啦。

后端我用了mongoDB做數(shù)據(jù)庫,并在Express中通過mongoose操作mongoDB,省去了復(fù)雜的命令行,通過Javascript操作無疑方便了很多。

Vue的各個(gè)插件:

vue-cli:官方的腳手架,用來初始化項(xiàng)目

vue-resource:可以看作一個(gè)Ajax庫,通過在跟組件引入,可以方便的注入子組件。子組件以this.$http調(diào)用

vue-router:官方的路由工具,用來切換子組件,是用來做SPA應(yīng)用的關(guān)鍵

vuex:規(guī)范組件中數(shù)據(jù)流動(dòng),主要用于異步的http請(qǐng)求后數(shù)據(jù)的刷新。通過官方的vue-devtools可以無縫對(duì)接

文件目錄
│  .babelrc           babel配置
│  .editorconfig
│  .eslintignore  
│  .eslintrc.js       eslintrc配置
│  .gitignore
│  index.html         入口頁面
│  package.json
│  README.md
│  setup.html         初始化賬戶頁面
│  webpack.config.js  webpack配置
│
├─dist                打包生成
│     
├─server              服務(wù)端
│      api.js         Restful接口
│      db.js          數(shù)據(jù)庫
│      index.js
│      init.json      初始數(shù)據(jù)
│
└─src
    │  main.js        項(xiàng)目入口
    │  setup.js       初始化賬戶
    │
    ├─assets          外部引用文件
    │  ├─css
    │  ├─fonts
    │  ├─img
    │  └─js         
    │
    ├─components      vue組件
    │  ├─back         博客控制臺(tái)組件
    │  ├─front        博客頁面組件
    │  └─share        公共組件
    │
    ├─router          路由
    │
    ├─store           vuex文件
    │
    └─style           全局樣式

前端的文件統(tǒng)一放到了src目錄下,有兩個(gè)入口文件,分別是main.jssetup.js,有過WordPress經(jīng)驗(yàn)應(yīng)該知道,第一次進(jìn)入博客是需要設(shè)置用戶名密碼和數(shù)據(jù)庫的,這里的setup.js就是第一次登入時(shí)的頁面腳本,而main.js則是剩余所有文件的入口

main.js
import Vue          from "vue"
import VueResource  from "vue-resource"
import {mapState}   from "vuex"

//三個(gè)頂級(jí)組件,博客主頁和控制臺(tái)共享
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")

而后所有頁面分割成一個(gè)單一的vue組件,放在components中,通過入口文件main.js,由webpack打包生成,生成的文件放在dist文件夾下。

后端文件放在server文件夾內(nèi),這就是基于Expressnode服務(wù)器,在server文件夾內(nèi)執(zhí)行

node index

就可以啟動(dòng)Node服務(wù)器,默認(rèn)偵聽3000端口。

?關(guān)于 Webpack

Webpack的配置文件主體是有vue-cli生成的,但為了配合后端自動(dòng)刷新、支持Sass和生成獨(dú)立的css文件,稍微修改了一下:

webpack.config.js
const 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生成獨(dú)立文件
    extractCSSFromVue,
    extractCSSFromSASS,
    new CopyWebpackPlugin([
      {from: "./src/assets/img", to: "./"}
    ])
  ],
  resolve: {
    alias: {
      "vue$": "vue/dist/vue"
    }
  },
  //服務(wù)器代理,便于開發(fā)時(shí)所有http請(qǐng)求轉(zhuǎn)到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
    })
  ])
}

運(yùn)行

npm start

后,node端開啟了3000端口,接著運(yùn)行

npm run dev

打開webpack在8080端口服務(wù)器,具有動(dòng)態(tài)加載的功能,并且所有的http請(qǐng)求會(huì)代理到3000端口

關(guān)于Vue-Router

因?yàn)閷懙氖堑矐?yīng)用(SPA),服務(wù)器不負(fù)責(zé)路由,所以路由方面交給Vue-Router來控制。

router.js
import Vue      from "vue"
import Router   from "vue-router"
//博客頁面
import Archive  from "../components/front/Archive.vue"
import Article  from "../components/front/Article.vue"
//控制臺(tái)頁面
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元素分別是等待效果(轉(zhuǎn)圈圈)的彈出層和信息的彈出層,和背景樣式的切換。

關(guān)于后端

后端是用node.js作為服務(wù)器的,使用了express框架。

其中代碼非常簡單:

index.js
const 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"))
})

服務(wù)器做的事情很簡單,畢竟路由在前端。在接受請(qǐng)求的時(shí)候判斷一下數(shù)據(jù)庫是否初始化,如果初始化就轉(zhuǎn)向主頁,否則轉(zhuǎn)向setup.html,之所以沒有直接sendfile是因?yàn)榭紤]到之后添加服務(wù)端渲染(雖然主頁并沒有啥值得渲染的,因?yàn)楹芎唵危?/p>

express框架中使用了mongoose來連接mongoDB數(shù)據(jù)庫,在接收請(qǐng)求時(shí)做對(duì)應(yīng)的curd操作,比如這就是在接收保存文章時(shí)對(duì)應(yīng)的操作:

api.js
router.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()
})
后記

當(dāng)然還有很多沒提及的地方,最早寫這個(gè)博客管理器的時(shí)候用的還是vue 1.x,后來用2.0改寫后文檔一直沒改,所以最近更新了一下,避免誤解。

其實(shí)整個(gè)管理器最復(fù)雜的地方時(shí)vuex異步數(shù)據(jù)視圖的部分,不過這一部能講的太多,就不在這里展開了,可以看官方文檔后,參考源代碼的注釋。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/80406.html

相關(guān)文章

  • 一些基于React、Vue、Node.jsMongoDB技術(shù)棧實(shí)踐項(xiàng)目

    摘要:利用中間件實(shí)現(xiàn)異步請(qǐng)求,實(shí)現(xiàn)兩個(gè)用戶角色實(shí)時(shí)通信。目前還未深入了解的一些概念。往后會(huì)寫更多的前后臺(tái)聯(lián)通的項(xiàng)目。刪除分組會(huì)連同組內(nèi)的所有圖片一起刪除。算是對(duì)自己上次用寫后臺(tái)的一個(gè)強(qiáng)化,項(xiàng)目文章在這里。后來一直沒動(dòng),前些日子才把后續(xù)的完善。 歡迎訪問我的個(gè)人網(wǎng)站:http://www.neroht.com/? 剛學(xué)vue和react時(shí),利用業(yè)余時(shí)間寫的關(guān)于這兩個(gè)框架的訓(xùn)練,都相對(duì)簡單,有的...

    tangr206 評(píng)論0 收藏0
  • 一個(gè)基于Vue.js+Mongodb+Node.js博客內(nèi)容管理系統(tǒng)

    摘要:三更新內(nèi)容在原來項(xiàng)目的基礎(chǔ)上,做了如下更新數(shù)據(jù)庫重新設(shè)計(jì),改成以用戶分組的數(shù)據(jù)庫結(jié)構(gòu)應(yīng)數(shù)據(jù)庫改動(dòng),所有接口重新設(shè)計(jì),并統(tǒng)一采用和網(wǎng)易立馬理財(cái)一致的接口風(fēng)格刪除原來游客模式,增加登錄注冊功能,支持彈窗登錄。 這個(gè)項(xiàng)目最初其實(shí)是fork別人的項(xiàng)目。當(dāng)初想接觸下mongodb數(shù)據(jù)庫,找個(gè)例子學(xué)習(xí)下,后來改著改著就面目全非了。后臺(tái)和數(shù)據(jù)庫重構(gòu),前端增加了登錄注冊功能,僅保留了博客設(shè)置頁面,但是...

    wh469012917 評(píng)論0 收藏0
  • vue+node+mongodb 搭建一個(gè)完整博客

    摘要:開發(fā)一個(gè)完整博客流程前言前段時(shí)間剛把自己的個(gè)人網(wǎng)站寫完,于是這段時(shí)間因?yàn)槭虑椴皇翘啵阏砹艘幌?,寫了個(gè)簡易版的博客系統(tǒng)服務(wù)端用的是框架進(jìn)行開發(fā)技術(shù)棧目錄結(jié)構(gòu)講解的配置文件放置代碼文件項(xiàng)目參數(shù)配置的文件日志打印文件項(xiàng)目依賴模塊 Vue + Node + Mongodb 開發(fā)一個(gè)完整博客流程 前言 前段時(shí)間剛把自己的個(gè)人網(wǎng)站寫完, 于是這段時(shí)間因?yàn)槭虑椴皇翘啵阏砹艘幌?,寫了個(gè)簡易...

    Miracle_lihb 評(píng)論0 收藏0
  • 前端學(xué)習(xí)資源匯總

    摘要:建立該倉庫的目的主要是整理收集學(xué)習(xí)資源,統(tǒng)一管理,方便隨時(shí)查找。目前整合的學(xué)習(xí)資源只是前端方向的,可能會(huì)存在漏缺比較好的資源,需要慢慢的完善它,歡迎在該上補(bǔ)充資源或者提供寶貴的建議。 說明 平時(shí)的學(xué)習(xí)資源都比較的凌亂,看到好的資源都是直接收藏在瀏覽器的收藏夾中,這樣其實(shí)并不方便,整理在云筆記上,也不方便查看修改記錄,索性就整理在 github 上并開源出來,希望幫助大家能夠更快的找到需...

    SnaiLiu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

Dr_Noooo

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<