说明

此文是针对“全栈之巅”,Nodejs全栈开发大佬的视频所做的笔记,加入了个人的一些理解,不完全模仿,适合新手Nodejs开发者入门,有点计算机基础的都可以直接上手,所见即所得。对于不了解或者没有接触过Nodejs的同学,此文尽量做到通俗易懂,可以直接搭建出完整的前后端框架,后续有复杂的功能可以在此基础上添加。至于Nodejs的语法可以在宏观上把握此框架后再陆续学习。
原视频地址:https://www.bilibili.com/video/BV1t441187pL?p=1
(Element UI + NodeJs(Express)全栈开发后台管理界面)
非常推荐新手入门观看。

Element UI简介

Element UI是饿了么开发的一款Vue UI Framework(https://element.eleme.cn/),包含丰富的组件和页面布局样例,可以直接引用,大大简化了前端界面开发,非常适合全栈开发者使用。

安装@vue/cli

前提是安装了Node.js>=8的版本,暂时推荐v10版本。
Nodejs安装可参考https://www.jianshu.com/p/13f45e24b1de
新建一个文件夹作为项目工程,在文件夹下命令行执行:

vue create element-admin

提示版本过低,需要安装vue cli3
在这里插入图片描述
先卸载

npm uninstall -g vue-cli

再重新安装

npm install -g @vue/cli

等待几分钟安装完成,安装了1000个包。
在这里插入图片描述

快速上手

重新执行以下命令

vue create element-admin

在这里插入图片描述在这里插入图片描述
方向键选择手动,回车:
在这里插入图片描述
其中Babel和Linter/Formatter默认选中,我们新选中Router:用下方向键到Router,点击空格键选中,然后回车:
在这里插入图片描述
输入n回车:
在这里插入图片描述
后面一路回车即可:
在这里插入图片描述
在这里插入图片描述
提示安装成功。
会生成一个前端的项目模板,后端项目建立一个文件夹再编写代码。
cd element-admin
vue add element
在这里插入图片描述
依次选择Fully import 、 No 、 zh-CN然后回车
在这里插入图片描述
add element会修改src文件夹下的App.vue和main.js文件。

运行程序npm run serve

npm run serve

在这里插入图片描述
浏览器打开http://localhost:8080/,看到下述页面即为成功。此页面对应App.vue文件,出现了“el-button”按钮,是因为执行了“vue add element”命令。截止到目前,已经搭建出前端框架,可在此基础上添加页面,再用后端程序编写API服务,就可以实现完整的后台管理功能。
在这里插入图片描述

修改首页App.vue

开发软件推荐VS Code,用VS Code打开文件夹element-admin。修改src下的App.vue文件为以下内容,即得到常用的后台管理界面模板(以下为Element-UI官网组件-Container布局容器-实例改写)

<template>
  <el-container style="height: 100vh; border: 1px solid #eee">
  <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
    <el-menu router :default-openeds="['1', '3']">
      <el-submenu index="1">
        <template slot="title"><i class="el-icon-message"></i>导航一</template>
        <el-menu-item-group>
          <template slot="title">分组一</template>
          <el-menu-item index="/articles/create">选项1</el-menu-item>
          <el-menu-item index="/articles/index">选项2</el-menu-item>
        </el-menu-item-group>
        <el-menu-item-group title="分组2">
          <el-menu-item index="1-3">选项3</el-menu-item>
        </el-menu-item-group>
        <el-submenu index="1-4">
          <template slot="title">选项4</template>
          <el-menu-item index="1-4-1">选项4-1</el-menu-item>
        </el-submenu>
      </el-submenu>
      <el-submenu index="2">
        <template slot="title"><i class="el-icon-menu"></i>导航二</template>
        <el-menu-item-group>
          <template slot="title">分组一</template>
          <el-menu-item index="2-1">选项1</el-menu-item>
          <el-menu-item index="2-2">选项2</el-menu-item>
        </el-menu-item-group>
        <el-menu-item-group title="分组2">
          <el-menu-item index="2-3">选项3</el-menu-item>
        </el-menu-item-group>
        <el-submenu index="2-4">
          <template slot="title">选项4</template>
          <el-menu-item index="2-4-1">选项4-1</el-menu-item>
        </el-submenu>
      </el-submenu>
      <el-submenu index="3">
        <template slot="title"><i class="el-icon-setting"></i>导航三</template>
        <el-menu-item-group>
          <template slot="title">分组一</template>
          <el-menu-item index="3-1">选项1</el-menu-item>
          <el-menu-item index="3-2">选项2</el-menu-item>
        </el-menu-item-group>
        <el-menu-item-group title="分组2">
          <el-menu-item index="3-3">选项3</el-menu-item>
        </el-menu-item-group>
        <el-submenu index="3-4">
          <template slot="title">选项4</template>
          <el-menu-item index="3-4-1">选项4-1</el-menu-item>
        </el-submenu>
      </el-submenu>
    </el-menu>
  </el-aside>
  
  <el-container>
    <el-header style="text-align: right; font-size: 12px">
      <el-dropdown>
        <i class="el-icon-setting" style="margin-right: 15px"></i>
        <el-dropdown-menu slot="dropdown">
          <el-dropdown-item>查看</el-dropdown-item>
          <el-dropdown-item>新增</el-dropdown-item>
          <el-dropdown-item>删除</el-dropdown-item>
        </el-dropdown-menu>
      </el-dropdown>
      <span>王小虎</span>
    </el-header>
    
    <el-main>
      <el-table :data="tableData">
        <el-table-column prop="date" label="日期" width="140">
        </el-table-column>
        <el-table-column prop="name" label="姓名" width="120">
        </el-table-column>
        <el-table-column prop="address" label="地址">
        </el-table-column>
      </el-table>
    </el-main>
  </el-container>
</el-container>
</template>

<style>
html,body{
  padding: 0;
  margin: 0;
}
  .el-header {
    background-color: #B3C0D1;
    color: #333;
    line-height: 60px;
  }
  
  .el-aside {
    color: #333;
  }
</style>

<script>
  export default {
    data() {
      const item = {
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      };
      return {
        tableData: Array(20).fill(item)
      }
    }
  };
</script>

https://element.eleme.cn/#/zh-CN/component/menu
其中<el-menu :default-openeds="[‘1’, ‘3’]">表示默认展开第1个和第三个主菜单。在其中添加router(https://element.eleme.cn/#/zh-CN/component/menu),表示
使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转,例如<el-menu-item>可以添加跳转,index="/articles/index"
将上述cmd窗口关闭,重新在element-admin文件夹下运行npm run serve,可以看到首页已经变成了一个典型的后台管理界面。

npm run serve

浏览器打开http://localhost:8080/
在这里插入图片描述

新建Vue页面

页面在src/views文件夹下,删除Home.vue和About.vue,新建两个页面CreateArticle.vue和ListArticle.vue,分别为创建文章和文章列表。
新建文章需要使用Element UI中的Form表单组件(https://element.eleme.cn/#/zh-CN/component/form),对典型表单改造如下:

//CreateArticle.vue
<template>
  <el-form ref="form" :model="article" label-width="100px">
  <el-form-item label="文章标题">
    <el-input v-model="article.title"></el-input>
  </el-form-item>
  <el-form-item label="文章内容">
    <el-input type="textarea" v-model="article.body"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="onSubmit">立即创建</el-button>
    <el-button>取消</el-button>
  </el-form-item>
</el-form>
</template>
<script>
  export default {
    data() {
      return {
        article: {
        }
      }
    },
    methods: {
      onSubmit() {
        console.log('submit!');
      }
    }
  }
</script>

Element UI表单组件中有如下备注:

W3C 标准中有如下规定:

When there is only one single-line text input field in a form, the user agent should accept Enter in that field as a request to submit the form.

即:当一个 form 元素中只有一个输入框时,在该输入框中按下回车应提交该表单。如果希望阻止这一默认行为,可以在 <el-form> 标签上添加 @submit.native.prevent。

我们在<el-form> 标签上添加 @submit.native.prevent,将"立即创建"按钮的@click="onSubmit"去掉,改为native-type="submit"表示提交按钮。最终的CreateArticle.vue如下:

//CreateArticle.vue
<template>
  <el-form @submit.native.prevent="saveArticle" ref="form" :model="article" label-width="100px">
  <el-form-item label="文章标题">
    <el-input v-model="article.title"></el-input>
  </el-form-item>
  <el-form-item label="文章内容">
    <el-input type="textarea" v-model="article.body"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" native-type="submit">立即创建</el-button>
    <el-button>取消</el-button>
  </el-form-item>
</el-form>
</template>
<script>
  export default {
    data() {
      return {
        article: {}
      }
    },
    methods: {
      saveArticle() {
        this.$http.post('articles',this.article).then(res => {
          console.log(res.data);
          this.$message({
            message: "文章创建成功",
            type: "success"
          });
          this.$router.push('/articles/index')
        });
      }
    }
  }
</script>

其中使用的v-model为双向绑定,可以初步理解为将变量与输入框值进行了绑定关系,一个改变时另一个随之改变。
saveArticle表单提交方法使用this.$http.post调用了后端接口articles的post方法,后面会给出代码。
在src/views文件夹下创建文章列表页面ListArticle.vue如下

//ListArticle.vue
<template>
  <div>
    <el-table :data="articles">
      <el-table-column prop="title" label="标题" width="140"></el-table-column>
      <el-table-column prop="body" label="内容" width="600"></el-table-column>
      <el-table-column fixed="right" label="操作" width="100">
        <template slot-scope="scope">
          <el-button @click="edit" type="text" size="small">编辑</el-button>
          <el-button @click="remove(scope.row._id)" type="text" size="small">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        articles: []
      };
    },
    methods: {
      //获取数据
      fetch(){
        this.$http.get('articles').then(res => {
          this.articles = res.data
        });
      },
      edit(){
      },
      remove(id){
        this.$http.delete(`articles/${id}`).then(res => {
          console.log(res.data);
          this.$message({
            message: "文章删除成功",
            type: "success"
          });
          this.fetch()
        });
      }
    },
    //进入页面需要获取数据
    created(){
      this.fetch()
    }
  };
</script>

其中进入页面时使用this.fetch()获取数据库中的数据,文章列表包含了编辑和删除按钮。上述代码仅实现了“删除”功能,“编辑”功能可按视频操作自行完成。
修改router下的index.js,此文件为路由配置文件,用于配置页面的跳转关系。引入了CreateArticle.vue和ListArticle.vue两个文件:

//index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import CreateArticle from '../views/CreateArticle.vue'
import ListArticle from '../views/ListArticle.vue'

Vue.use(VueRouter)

  const routes = [
  {
    path: '/',
    name: 'Home',
    redirect: '/articles/index'
  },
  {
    path: '/articles/index',
    name: 'list-article',
    component: ListArticle
  },
  {
    path: '/articles/create',
    name: 'create-article',
    component: CreateArticle
  }
]

const router = new VueRouter({
  routes
})

export default router

对于首页App.vue进行了精简,仅包含新建文章和文章列表两个页面:

//App.vue
<template>
  <el-container style="height: 100vh; border: 1px solid #eee">
  <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
    <el-menu router :default-openeds="['1']">
      <el-submenu index="1">
        <template slot="title">
			<i class="el-icon-tickets"></i>内容管理
		</template>
        <el-menu-item index="/articles/create">新建文章</el-menu-item>
        <el-menu-item index="/articles/index">文章列表</el-menu-item>
      </el-submenu>
    </el-menu>
  </el-aside>
  
  <el-container>
    <el-header style="text-align: right; font-size: 12px">
      <el-dropdown>
        <i class="el-icon-setting" style="margin-right: 15px"></i>
        <el-dropdown-menu slot="dropdown">
          <el-dropdown-item>查看</el-dropdown-item>
          <el-dropdown-item>新增</el-dropdown-item>
          <el-dropdown-item>删除</el-dropdown-item>
        </el-dropdown-menu>
      </el-dropdown>
      <span>文章管理系统</span>
    </el-header>
    
    <el-main>
      <router-view></router-view>
    </el-main>
  </el-container>
</el-container>
</template>

<style>
html,body{
  padding: 0;
  margin: 0;
}
  .el-header {
    background-color: #B3C0D1;
    color: #333;
    line-height: 60px;
  }
  
  .el-aside {
    color: #333;
  }
</style>

<script>
  export default {
    data() {
      return {
      }
    }
  };
</script>

上述router-view会把router文件夹下的index.js定义的链接内容渲染到本页。
修改src下的main.js文件如下,由于要调用后端api,需要安装axios。

//main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'

Vue.config.productionTip = false

import axios from 'axios' //用来请求接口的。前后端都可以用axios请求接口。没有安装axios的需要安装下npm install axios
Vue.prototype.$http = axios.create({
  baseURL: 'http://localhost:3001/api'//填写后端接口,后面有后端接口的样例
})//可以在任意页面使用this.$http访问axios实例

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

后端接口index.js

前面创建文章和文章列表使用this.$http调用的接口还没有创建,需要创建接口后,前端才能通过API接口获取到数据库中的值。
因接口较为简单,在同个目录下创建一个文件index.js专门处理前端的请求。
(本例使用mongodb数据库,如未安装过mongodb,需要现行安装mongodb,配置好数据库data和log的位置。如使用其他数据库,可参考后续文章,将介绍如何使用oracle和sqlserver数据库)

安装npm模块express、mongoose、cors

npm i express@next mongoose cors

在element-admin下新建server文件夹,作为后端服务文件夹。在server文件夹下创建index.js文件,

//index.js
const express = require('express')//引用express框架
const app = express()//express的一个实例
const mongoose = require('mongoose')//使用mongodb数据库需要引入mongoose
mongoose.connect('mongodb://localhost:27017/element-admin',{ 
	useNewUrlParser: true,
	useFindAndModify: true,
	useCreateIndex: true,
})
//这里使用mongodb数据库,只要在本机上启动mongodb数据库即可,不需要已经创建数据库element-admin,将会自动创建
//const oracledb = require('oracledb') 
//如果使用oracle数据库需要使用oracledb,网上大部分样例都是mongodb和mysql
//后续文章将介绍使用oracle和sqlserver作为参考样例

//定义数据库操作模型
const Article = mongoose.model('Article',new mongoose.Schema({
	title:{ type: String },
	body:{ type: String },
}))

app.use(require('cors')())//允许跨域。允许前端不同的域来访问接口
app.use(express.json())//express识别提交的json格式数据

//默认首页
app.get('/',async(req, res) => {
	res.send('index')
})
//新增文章,提交数据用post方法
app.post('/api/articles', async(req, res) => {
	const article = await Article.create(req.body)
	res.send(article)
})
//文章列表,获取数据用get方法
app.get('/api/articles', async(req, res) => {
  const articles = await Article.find()
	res.send(articles)
})
//删除文章 :id表示接受动态参数
app.delete('/api/articles/:id', async(req, res) => {
  await Article.findOneAndDelete(req.params.id)
  res.send({
    status: true
  })
})

app.listen(3001,()=> {//启动监听3001端口,设置回调函数
	console.log('http://localhost:3001/')
})

启动后端服务,在element-admin/server文件夹下cmd命令行启动

node index.js

此时3001端口已经启动了API服务,供前端调用。

完整运行

将上述命令行运行的npm run serve窗口关掉,重新在element-admin文件夹下运行

npm run serve

浏览器打开http://localhost:8080/
首页为文章列表页,列出所有文章。可编辑、删除文章。
在这里插入图片描述
新建文章页:可新建文章。
在这里插入图片描述
上述为基本功能页面,如对上述页面效果不满意,可参考后续文章,将会介绍更为炫酷的页面效果。

总结

作为入门,上述步骤已经搭建了一个完整的前后端系统,并且对数据库进行了增删改查操作,是一个相对完整的初级系统。
再次推荐新手看完“全栈之巅”的视频,有兴趣可以观看其相关视频。

参考资料

https://element.eleme.cn/#/zh-CN/component/installation
https://www.bilibili.com/video/BV1t441187pL?p=1
https://www.cnblogs.com/zhoulifeng/p/9395295.html

Logo

前往低代码交流专区

更多推荐