vue.js实践:一个node.js+mongodb+vue.js的博客内容管理系统

author author     2022-08-27     105

关键词:

项目来源

以前曾用过WordPress搭建自己的博客网站,但感觉WordPress很是臃肿。所以一直想自己写一个博客内容管理器。

正好近日看完了Vue各个插件的文档,就用着Vue尝试写了这个简约的博客内容管理器(CMS)。

嗯,我想完成的功能:

  • 一个基本的博客内容管理器功能,如后台登陆,发布并管理文章等

  • 支持markdown语法实时编辑

  • 支持代码高亮

  • 管理博客页面的链接

  • 博客页面对移动端适配优化

  • 账户管理(修改密码)

Demo

登陆后台按钮在页面最下方“站长登陆”,可以以游客身份登入后台系统。

源码

用到的技术和实现思路:

前端:Vue全家桶

  • Vue.js

  • Vue-Cli

  • Vue-Resource

  • Vue-Router

  • Vuex

后端:Node

  • Node.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.jssetup.js,有过WordPress经验应该知道,第一次进入博客是需要设置用户名密码和数据库的,这里的setup.js就是第一次登入时的页面脚本,而main.js则是剩余所有文件的入口

main.js

import 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文件夹内,这就是基于Expressnode服务器,在server文件夹内执行

node index

就可以启动Node服务器,默认侦听3000端口。

 关于 Webpack

Webpack的配置文件主体是有vue-cli生成的,但为了配合后端自动刷新、支持Sass和生成独立的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生成独立文件
    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.js

import 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  

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>cms2simple</title>
    <link rel="stylesheet" href="dist/index.css">
    <link rel="stylesheet" href="dist/styles.css">
  </head>
  <body>
    <div id="CMS2" style="height: 100%">
      <my-canvas></my-canvas>
      <spinner v-show="isLoading"></spinner>
      <Toast v-show="isToasting"></Toast>
      <router-view ></router-view>
    </div>
    <script src="/dist/main.js"></script>
  </body>
</html>

可以看到路由控制在body元素下的router-view中。前面的spinnertoast元素分别是等待效果(转圈圈)的弹出层和信息的弹出层,和背景样式的切换。

关于后端

后端是用node.js作为服务器的,使用了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‘))
})

服务器做的事情很简单,毕竟路由在前端。在接受请求的时候判断一下数据库是否初始化,如果初始化就转向主页,否则转向setup.html,之所以没有直接sendfile是因为考虑到之后添加服务端渲染(虽然主页并没有啥值得渲染的,因为很简单)

express框架中使用了mongoose来连接mongoDB数据库,在接收请求时做对应的curd操作,比如这就是在接收保存文章时对应的操作:

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()
})

后记

当然还有很多没提及的地方,最早写这个博客管理器的时候用的还是vue 1.x,后来用2.0改写后文档一直没改,所以最近更新了一下,避免误解。

其实整个管理器最复杂的地方时vuex异步数据视图的部分,不过这一部能讲的太多,就不在这里展开了,可以看官方文档后,参考源代码的注释。

windows10安装node.js,vue.js以及创建第一个vue.js项目(代码片段)

【工具官网】Node.js: http://nodejs.cn/淘宝NPM: https://npm.taobao.org/一、安装环境1、本机系统:Windows10Pro(64位)2、Node.js:v6.9.2LTS(64位)二、安装Node.js步骤1、下载对应你系统的Node.js版本:https://nodejs.org/en/download/2、选安装目录... 查看详情

利用vue.js+node.js+mongodb实现一个博客系统(附源码)

前言本文主要介绍了利用Vue.js+Node.js+MongoDB实现一个博客系统,这个博客使用Vue做前端框架,Node+express做后端,数据库使用的是MongoDB。实现了用户注册、用户登录、博客管理、文章编辑、标签分类等功能实现的功能   &... 查看详情

vue.js开发环境搭建以及创建一个vue实例

Vue.js是一套构建用户界面的渐进式框架。Vue只关注视图层,采用自底向上增量开发的设计。Vue的目标是通过尽可能简单的API实现响应的数据绑定和组合的视图组件。在使用vue.js之前首先需要搭建vue.js的开发环境,下面,我们就来... 查看详情

开始vue.js,第一个应用程序

开始Vue.jsvue-cli需要环境Node.js:https://nodejs.org/en/download/选择自己的版本   Git:https://git-scm.com/download    查看是否安装了Node.js和nmp(软件包管理器)cmd下输入node-vnpm-vPS:Node.js安装完后自带了n 查看详情

开始vue.js,第一个应用程序

开始Vue.jsvue-cli需要环境Node.js:https://nodejs.org/en/download/选择自己的版本   Git:https://git-scm.com/download    查看是否安装了Node.js和nmp(软件包管理器)cmd下输入node-vnpm-vPS:Node.js安装完后自带了n 查看详情

如何在 Node.js 服务器上部署 Vue.js 应用程序

....jsserver【发布时间】:2019-02-1305:25:00【问题描述】:我有一个dist文件夹,其中包含CSS、字体、JS文件夹和一个为Vue.js最小化的index.html文件,可以部署和使用。我想使用Node.js来运行这个应用程序。如何将其设置为仅运行npmrunserver... 查看详情

将 PHP 会话与 Vue/Node.js 集成

...e/Node.js【发布时间】:2018-08-1122:32:08【问题描述】:我有一个PHP应用程序,它对用户进行身份验证、执行MySQL查询并依赖于$_SESSIONcookie。一切正常,但我意识到我需要在前端做更多事情,因此不得不使用Vue.js和websockets。因此,我... 查看详情

如何创建服务于 Vue.js SPA 的 Node.js Express 应用程序?

...布时间】:2019-05-1300:05:11【问题描述】:我正在尝试建立一个Node.js项目,该项目使用Express来提供一些后端API并提供一个使用Vue.js构建的SPA。当我使用Vuecli初始化项目时,我得到例如src/main.ts主文件和 查看详情

Node.js、Vue.js 和 Passport.js。 .isAuthenticated() 总是返回 false? Axios 标头可能吗?

...ly?【发布时间】:2019-01-0502:34:09【问题描述】:我正在将一个项目转移到Vue.js,但我无法使用任何中 查看详情

老卫拆书009期:vue+node肩挑全栈!《node.js+express+mongodb+vue.js全栈开发实战》开箱

...原理到整合开发实战,以丰富的项目展现全栈开发的一个技巧。这本书主要是涉及vue.j+node.js架构的一些基础知识及核心技术。然后这里面也会有一些详细的项目演练,演示如何从零开始实现一个完整的企业级应用。好... 查看详情

安装vue.js

...相应的版本号,则说明安装成功。测试看node.js在c盘建立一个叫app的文件夹,里面放test.js varhttp=require("http");http.createServer(function(req,res){res.writeHead(200,{"Content-Type":"text/ 查看详情

Node.js 和 Vue.js,为啥 Refresh 让 vue.js 的 store 清晰?我如何在 vue.js 中使用上传的图片?

】Node.js和Vue.js,为啥Refresh让vue.js的store清晰?我如何在vue.js中使用上传的图片?【英文标题】:Node.jsandVue.js,whyRefreshmakevue.js\'sstoreclear?Andhowcaniuseuploadedimageinvue.js?Node.js和Vue.js,为什么Refresh让vue.js的store清晰?我如何在vue.js中使... 查看详情

如何运行一个vue工程

在师兄的推荐下入坑vue.js发现无法运行GitHub上的开源项目。通过查阅网上教程,成功搭建好项目环境,同时对前段工程化有了朦朦胧胧的认知,因此将环境搭建过程分享给大家。 首先,列出来我们需要的东西:  node.j... 查看详情

尽管视图初始化,有时仍会显示已删除的项目-Vue,Node.js [重复]

...描述】:我在Vue.js、Node.js和MongoDB中创建应用程序。我有一个项目列表,每个项目旁边都有删除按钮。通常它可以 查看详情

无法访问我的站点中的链接(复制和粘贴):Node.js - Express.js - Webpack - Vue.js - 历史模式

...发布时间】:2021-01-1304:29:48【问题描述】:我最近创建了一个基于Node.js、Express.j 查看详情

在 Node.js 和 Vue.js 之间共享 TypeScript 代码

】在Node.js和Vue.js之间共享TypeScript代码【英文标题】:SharingTypeScriptcodebetweenNode.jsandVue.js【发布时间】:2021-09-1803:43:50【问题描述】:我很难弄清楚如何做到这一点。我的环境是:Node.js16.1.xVue.js3.xTypeScript4.2.4我的目录结构是这样... 查看详情

vue.js学习之——安装

...NPM前两种不细说,重点讨论第三种——NPM安装Vue.js提供了一个名为Vue-cli的官方命令工具,使用之前先进行如下准备工作:1、安装nvm(NodeVersionManager),简单来说就是一个管理node.js版本的控制器。2、安装npm(NodepackageManager),... 查看详情

端口错误:heroku 中的 vue.js+node.js 项目

】端口错误:heroku中的vue.js+node.js项目【英文标题】:Errorwithports:vue.js+node.jsprojectinheroku【发布时间】:2018-08-2507:53:27【问题描述】:尝试部署我的全栈项目。它在本地构建并运行良好,但在Heroku中,在“gitpushherokumaster”命令和... 查看详情