Vue + Element UI + NodeJs(Express)全栈开发后台管理系统_笔记
说明
此文是针对“全栈之巅”,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
更多推荐
所有评论(0)