前后端分离
什么叫前后端分离:
前端和后端分离开
前端: 将浏览器中为用户进行页面展示的部分称之为前端
后端: 为前端提供业务逻辑和数据准备的所有代码统称为后端
前后端分工:
前后端开发工作的分工就是前后端分离。 前后端分工;(错误的认识)
真的前后端分离:
不仅仅是前端和后端的分工开发,而是架构的模式
前后端分离好处
(1) 专业的人做专业的事情
(2) 提高开发效率 --并行开发
(3) 应对复杂多变的需求
(4) 提高维护性
(5) 成本高 有钱人做的
搭建脚手架工程
1)创建一个web项目
2)vue init webpack
3)npm run dev
Elementui
Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库,网站快速成型的工具 类似easyui layui
elementui使用
1)安装 : npm i element-ui -S
2)在main.js 引入:
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
3)组件
测试elementui的组件
elementui组件
layout
<template>
<div class="hello">
<el-row>
<el-col :span="24"><div class="grid-content bg-purple-dark"></div></el-col>
</el-row>
<el-row>
<el-col :span="12"><div class="grid-content bg-purple"></div></el-col>
<el-col :span="12"><div class="grid-content bg-purple-light"></div></el-col>
</el-row>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'layouta'
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: khaki;
}
.el-row {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
.el-col {
border-radius: 4px;
}
.bg-purple-dark {
background: #99a9bf;
}
.bg-purple {
background: #d3dce6;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
</style>
message
<template>
<div class="hello">
<el-button :plain="true" @click="open1">消息</el-button>
<el-button :plain="true" @click="open2">成功</el-button>
<el-button :plain="true" @click="open3">警告</el-button>
<el-button :plain="true" @click="open4">错误</el-button>
<el-button :plain="true" @click="openVn">VNode</el-button>
</div>
</template>
<script>
export default {
methods: {
open1() {
this.$message({
showClose: true,
message: '这是一条消息提示'
});
},
open2() {
this.$message({
showClose: true,
message: '恭喜你,这是一条成功消息',
type: 'success'
});
},
open3() {
this.$message({
showClose: true,
message: '警告哦,这是一条警告消息',
type: 'warning'
});
},
open4() {
this.$message({
showClose: true,
message: '错了哦,这是一条错误消息',
type: 'error'
});
},
openVn() {
const h = this.$createElement;
this.$message({
message: h('p', null, [
h('span', null, '内容可以是 '),
h('i', { style: 'color: teal' }, 'VNode')
])
});
}
}
}
</script>
container
<template>
<div class="hello">
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-container>
<el-main>Main</el-main>
<el-footer>Footer</el-footer>
</el-container>
</el-container>
</el-container>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'container'
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.el-header, .el-footer {
background-color: orchid;
color: aquamarine;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: salmon;
color: #42b983;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: firebrick;
color: goldenrod;
text-align: center;
line-height: 160px;
}
body > .el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
</style>
tree
<template>
<div class="custom-tree-container">
<div class="block">
<p>使用 render-content</p>
<el-tree
:data="data"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false"
:render-content="renderContent">
</el-tree>
</div>
<div class="block">
<p>使用 scoped slot</p>
<el-tree
:data="data"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button
type="text"
size="mini"
@click="() => append(data)">
Append
</el-button>
<el-button
type="text"
size="mini"
@click="() => remove(node, data)">
Delete
</el-button>
</span>
</span>
</el-tree>
</div>
</div>
</template>
<script>
let id = 1000;
export default {
data() {
const data = [{
id: 1,
label: '一级 1',
children: [{
id: 4,
label: '二级 1-1',
children: [{
id: 9,
label: '三级 1-1-1'
}, {
id: 10,
label: '三级 1-1-2'
}]
}]
}, {
id: 2,
label: '一级 2',
children: [{
id: 5,
label: '二级 2-1'
}, {
id: 6,
label: '二级 2-2'
}]
}, {
id: 3,
label: '一级 3',
children: [{
id: 7,
label: '二级 3-1'
}, {
id: 8,
label: '二级 3-2'
}]
}];
return {
data: JSON.parse(JSON.stringify(data)),
data: JSON.parse(JSON.stringify(data))
}
},
methods: {
append(data) {
const newChild = { id: id++, label: 'testtest', children: [] };
if (!data.children) {
this.$set(data, 'children', []);
}
data.children.push(newChild);
},
remove(node, data) {
const parent = node.parent;
const children = parent.data.children || parent.data;
const index = children.findIndex(d => d.id === data.id);
children.splice(index, 1);
},
renderContent(h, { node, data, store }) {
return (
<span class="custom-tree-node">
<span>{node.label}</span>
<span>
<el-button size="mini" type="text" on-click={ () => this.append(data) }>Append</el-button>
<el-button size="mini" type="text" on-click={ () => this.remove(node, data) }>Delete</el-button>
</span>
</span>);
}
}
};
</script>
<style>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
</style>
button
<template>
<div class="hello">
<el-row>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
</el-row>
<br>
<el-row>
<el-button plain>朴素按钮</el-button>
<el-button type="primary" plain>主要按钮</el-button>
<el-button type="success" plain>成功按钮</el-button>
<el-button type="info" plain>信息按钮</el-button>
<el-button type="warning" plain>警告按钮</el-button>
<el-button type="danger" plain>危险按钮</el-button>
</el-row>
<br>
<el-row>
<el-button round>圆角按钮</el-button>
<el-button type="primary" round>主要按钮</el-button>
<el-button type="success" round>成功按钮</el-button>
<el-button type="info" round>信息按钮</el-button>
<el-button type="warning" round>警告按钮</el-button>
<el-button type="danger" round>危险按钮</el-button>
</el-row>
<br>
<el-row>
<el-button icon="el-icon-search" circle></el-button>
<el-button type="primary" icon="el-icon-edit" circle></el-button>
<el-button type="success" icon="el-icon-check" circle></el-button>
<el-button type="info" icon="el-icon-message" circle></el-button>
<el-button type="warning" icon="el-icon-star-off" circle></el-button>
<el-button type="danger" icon="el-icon-delete" circle></el-button>
</el-row>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'button'
}
}
}
</script>
dialog
<template>
<div class="hello">
<!-- Table -->
<el-button type="text" @click="dialogTableVisible = true">打开嵌套表格的 Dialog</el-button>
<el-dialog title="收货地址" :visible.sync="dialogTableVisible">
<el-table :data="gridData">
<el-table-column property="date" label="日期" width="150"></el-table-column>
<el-table-column property="name" label="姓名" width="200"></el-table-column>
<el-table-column property="address" label="地址"></el-table-column>
</el-table>
</el-dialog>
<!-- Form -->
<el-button type="text" @click="dialogFormVisible = true">打开嵌套表单的 Dialog</el-button>
<el-dialog title="收货地址" :visible.sync="dialogFormVisible">
<el-form :model="form">
<el-form-item label="活动名称" :label-width="formLabelWidth">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="活动区域" :label-width="formLabelWidth">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogFormVisible = false">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
gridData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}],
dialogTableVisible: false,
dialogFormVisible: false,
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
},
formLabelWidth: '120px'
};
}
};
</script>
table
<template>
<div class="hello">
<el-table
:data="tableData"
style="width: 100%"
max-height="250">
<el-table-column
fixed
prop="date"
label="日期"
width="150">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="120">
</el-table-column>
<el-table-column
prop="province"
label="省份"
width="120">
</el-table-column>
<el-table-column
prop="city"
label="市区"
width="120">
</el-table-column>
<el-table-column
prop="address"
label="地址"
width="300">
</el-table-column>
<el-table-column
prop="zip"
label="邮编"
width="120">
</el-table-column>
<el-table-column
fixed="right"
label="操作"
width="120">
<template slot-scope="scope">
<el-button
@click.native.prevent="deleteRow(scope.$index, tableData)"
type="text"
size="small">
移除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
methods: {
deleteRow(index, rows) {
rows.splice(index, 1);
}
},
data() {
return {
tableData: [{
date: '2016-05-03',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
}, {
date: '2016-05-02',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
}, {
date: '2016-05-04',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
}, {
date: '2016-05-01',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
}, {
date: '2016-05-08',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
}, {
date: '2016-05-06',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
}, {
date: '2016-05-07',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
}]
}
}
}
</script>
form
<template>
<div class="hello">
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="活动名称" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="活动区域" prop="region">
<el-select v-model="ruleForm.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间" required>
<el-col :span="11">
<el-form-item prop="date1">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm.date1" style="width: 100%;"></el-date-picker>
</el-form-item>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-form-item prop="date2">
<el-time-picker placeholder="选择时间" v-model="ruleForm.date2" style="width: 100%;"></el-time-picker>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="即时配送" prop="delivery">
<el-switch v-model="ruleForm.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质" prop="type">
<el-checkbox-group v-model="ruleForm.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="特殊资源" prop="resource">
<el-radio-group v-model="ruleForm.resource">
<el-radio label="线上品牌商赞助"></el-radio>
<el-radio label="线下场地免费"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="活动形式" prop="desc">
<el-input type="textarea" v-model="ruleForm.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
ruleForm: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
},
rules: {
name: [
{ required: true, message: '请输入活动名称', trigger: 'blur' },
{ min: 1, max: 8, message: '长度在 1 到 8 个字符', trigger: 'blur' }
],
region: [
{ required: true, message: '请选择活动区域', trigger: 'change' }
],
date1: [
{ type: 'date', required: true, message: '请选择日期', trigger: 'change' }
],
date2: [
{ type: 'date', required: true, message: '请选择时间', trigger: 'change' }
],
type: [
{ type: 'array', required: true, message: '请至少选择一个活动性质', trigger: 'change' }
],
resource: [
{ required: true, message: '请选择活动资源', trigger: 'change' }
],
desc: [
{ required: true, message: '请填写活动形式', trigger: 'blur' }
]
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('提交成功!');
} else {
console.log('错误!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>
tabs
<template>
<div class="hello">
<el-radio-group v-model="tabPosition" style="margin-bottom: 30px;">
<el-radio-button label="top">top</el-radio-button>
<el-radio-button label="right">right</el-radio-button>
<el-radio-button label="bottom">bottom</el-radio-button>
<el-radio-button label="left">left</el-radio-button>
</el-radio-group>
<el-tabs :tab-position="tabPosition" style="height: 200px;">
<el-tab-pane label="用户管理">用户管理</el-tab-pane>
<el-tab-pane label="配置管理">配置管理</el-tab-pane>
<el-tab-pane label="角色管理">角色管理</el-tab-pane>
<el-tab-pane label="定时任务补偿">定时任务补偿</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
export default {
data() {
return {
tabPosition: 'bottom'
};
}
};
</script>
alert
<template>
<div class="hello">
<el-alert
title="不可关闭的 alert"
type="success"
:closable="false">
</el-alert>
<el-alert
title="自定义 close-text"
type="info"
close-text="知道了">
</el-alert>
<el-alert
title="设置了回调的 alert"
type="warning"
@close="hello">
</el-alert>
</div>
</template>
<script>
export default {
methods: {
hello() {
alert('886');
}
}
}
</script>
mock.js
为什么需要模拟数据?
主要针对前端人员 , 前端没有后台的数据,需要模拟进行测试
使用mockjs:
(1)安装
npm install mockjs
(2)测试
新创建一个js文件:
var data = Mock.mock({
name: {
first: '@FIRST',
middle: '@FIRST',
last: '@LAST',
full: '@first @middle @last',
email:'@email',
ip:'@ip'
}
})
// 输出结果
console.log(JSON.stringify(data, null, 4))
3)运行 node demo
axios请求
axios类似 ajax ,封装promise(异步请求)
安装:
npm install axios --save
mockjs流程
注意:
main.js引入文件
import axios from 'axios'
import userMock from '../userMock'
//配置axios的全局基本路径 t
axios.defaults.baseURL=''
//全局属性配置,在任意组件内可以使用this.$http获取axios对象
Vue.prototype.$http = axios
crud.vue
1)发送请求:
getUsers(){
let params = {
page:this.page
}
//发送请求 controller {data:[],total:100}
this.$http.post('/user/list',params).then(res=>{
console.log("-------------------res.data {data: total}");
console.log(res);
this.users = res.data.data;
this.total = res.data.total;
})
}
2)被mock拦截(了解)
Mock.mock(new RegExp('/user/list'),'post',(opts) => {
//赋值
var list =dataList;
console.log(opts.body) ;// "{page:2}"
//json字符串转换成JSON对象
var index = JSON.parse(opts.body).page; //2
//每页条数
var size = 10;
//公共的条数
var total = list.length
//分页方法
list = pagination(index, size, list);
return {
'total': total,
'data': list
}
})