Vue入门之Web端CURD前端项目示例

article/2025/9/26 6:28:00

Vue入门之Web端CURD前端项目示例

随着vue.js越来越火,很多不太懂前端的小伙伴想要入坑。而入坑最好的办法就是上手实际操作,因此本文将重点放在实际操作上,对理论不做过多解释,不明白的地方小伙伴们可以去看官方文档或者相关书籍。

目录

  • 一、安装npm
  • 二、安装vue-cli
  • 三、使用vue-cli创建项目
  • 四、修改项目配置
  • 五、启动项目
  • 六、安装依赖
  • 七、建立基本视图框架
  • 八、完善CURD功能
  • 九、总结

本文的示例项目操作环境如下:

平台/工具说明
操作系统Mac OS 10.13.6 (17G65)
浏览器Chrome 77.0.3865.120
nvm下nodejs版本10.13.0
编辑器Visual Studio Code 1.39.2

一、安装npm

npm有多种安装方式,这里推荐使用nvm进行安装。

1.1 安装nvm

  • windows

地址:https://github.com/coreybutler/nvm-windows/releases

根据文档说明安装,记得设置淘宝的镜像。

nvm node_mirror https://npm.taobao.org/mirrors/node/
nvm npm_mirror https://npm.taobao.org/mirrors/npm/

或者修改settings.txt文件,在后面加上淘宝镜像设置。

node_mirror: https://npm.taobao.org/mirrors/node/
npm_mirror: https://npm.taobao.org/mirrors/npm/
  • linux/mac

地址:https://github.com/creationix/nvm

根据文档说明安装,记得设置淘宝的镜像。

# bash_profile
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
export NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node

1.2 配置npm

npm config set registry https://registry.npm.taobao.org
npm config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass

1.3 安装yarn

npm install -g yarn

1.4 配置yarn

已配置过npm则无需再次配置。

yarn config set registry https://registry.npm.taobao.org -g
yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g

二、安装vue-cli

细心的小伙伴会发现vue官网是不推荐入门直接上vue-cli的,这里考虑到很多小伙伴不是前端工程师,而仅仅是需要了解vue项目的基本结构,所以直接使用vue-cli创建项目吧。

使用npm或者yarn全局安装vue-cli:

注意:这里的@vue/cli不要写成了vue-cli,vue-cli是旧版本。

npm install -g @vue/cli
# OR
yarn global add @vue/cli

三、使用vue-cli创建项目

现在可以开始使用vue-cli创建项目了,这里项目名称为example-curd

这里也可以通过vue ui来创建,使用方法是控制台输入vue ui,具体内容本文不做展示

vue create example-curd

这时会有一个选项,第一项为默认配置,这里我们选择第二项手动配置,回车确定。

在这里插入图片描述

之后会出现一个多选,这时的操作是空格键选择,空格选择完所有需要的配置之后,最后按回车确定。

本文用于演示基本的项目流程,只选择3项,其它项小伙伴们自行查阅资料按需选择

在这里插入图片描述

选好依赖项后,进入vue-router设置提示,是否使用history mode,输入n然后回车确定。

这里的区别小伙伴们自己查阅资料。

在这里插入图片描述

然后会问如何处理Babel、ESLint之类的配置文件,这里为了便于修改,不与package.json混在一起,选择第一项。

在这里插入图片描述

最后问你是否记录下这套配置,由于本文只是演示,选择的配置项并不适合正式项目,所以选择不记录。

在这里插入图片描述

选择包管理器,这里推荐使用yarn。

在这里插入图片描述

项目配置完成。

在这里插入图片描述

四、修改项目配置

生成的项目目录结构如图:
在这里插入图片描述
为了避免默认端口被占用的情况,我们新建一个名为vue.config.js的配置文件,指定hostport。配置参考

module.exports = {devServer: {open: true,host: '0.0.0.0',port: 9000,},
};

五、启动项目

可以在package.json中修改脚本命令,例如增加一个与serve功能相同的dev命令:

{"name": "example-curd","version": "0.1.0","private": true,"scripts": {"serve": "vue-cli-service serve","build": "vue-cli-service build","dev": "vue-cli-service serve"},"dependencies": {"core-js": "^3.1.2","vue": "^2.6.10","vue-router": "^3.0.6","vuex": "^3.0.1"},"devDependencies": {"@vue/cli-plugin-babel": "^4.0.0","@vue/cli-plugin-router": "^4.0.0","@vue/cli-plugin-vuex": "^4.0.0","@vue/cli-service": "^4.0.0","vue-template-compiler": "^2.6.10"}
}

启动项目

yarn dev

在这里插入图片描述

至此,基本的项目创建与启动演示完毕,接下来进入实例演示。

六、安装依赖

本文主要目的是演示创建基本CURD的前端WEB页面,因此不做后端API的创建,这里使用mock.js拦截请求并返回模拟数据

本文需要用到的依赖有:

  • element-ui
  • mockjs
  • axios

使用yarn安装以上依赖

如果已经启动了项目,可以先ctrl + c退出,安装完依赖后再启动。

yarn add element-ui mockjs axios

七、建立基本视图框架

修改App.vuemain.jsrouter.js,同时删除项目创建时的默认文件About.vueHome.vueHelloWorld.vue,在src/views目录下创建一个layout目录和page目录,分别用于存放布局和页面。

7.1 修改main.js文件

引入element组件库及其样式

这里的@在vue-cli默认语法中代表项目中的src目录

src/main.js:

import Vue from 'vue';
import App from '@/App.vue';
import router from '@/router';
import store from '@/store';
import ElementUI from 'element-ui'; // ElementUI组件库
import 'element-ui/packages/theme-chalk/lib/index.css'; // ElementUI组件库样式// 注册饿了么UI
Vue.use(ElementUI);new Vue({router,store,render: h => h(App)
}).$mount('#app')

7.2 修改App.vue

同时调整一些必要的全局html样式。

src/App.vue:

<template><div id="app"><router-view></router-view></div>
</template><style>
html,
body {padding: 0;margin: 0;
}
#app {font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,Microsoft YaHei, SimSun, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;
}
a:focus,
a:active {outline: none;
}a,
a:focus,
a:hover {cursor: pointer;color: inherit;text-decoration: none;
}
</style>

7.3 创建布局文件

layout目录下创建一个default.vue作为默认布局文件,初学可以使用element的Container 布局容器组件。

src/views/layout/default.vue:

<template><el-container><el-aside width="200px">Aside</el-aside><el-container><el-header>Header</el-header><el-main><router-view></router-view></el-main></el-container></el-container>
</template>

7.4 修改router

指定src/views/page/index.vue为本项目默认首页,且作用于默认布局下。

() => import(‘xxx’) 为动态加载组件,这样做的好处是用到哪个页面加载哪个页面,避免导致首页加载时间过长。

src/router/index.js:

import Vue from 'vue'
import VueRouter from 'vue-router'
import DefaultLayout from '@/views/layout/default'Vue.use(VueRouter)const routes = [{path: '',component: DefaultLayout,redirect: 'index',children: [{path: 'index',name: 'index',component: () => import('@/views/page/index'),}],},
]const router = new VueRouter({routes
})export default router;

7.5 修改index.vue

修改首页内容,测试布局是否生效。

src/views/page/index.vue:

<template><div><el-button type="primary">首页的按钮</el-button></div>
</template>

7.6 查看基本布局是否生效

可以看到首页的ElementUI的按钮组件正常显示,且首页位于默认布局之下。
在这里插入图片描述

此时项目结构如下:

在这里插入图片描述

八、完善CURD功能

最后只剩下界面优化及基本的业务功能页面了。

8.1 优化界面

增加左侧菜单以及右侧上方的导航栏。可以使用ElementUI的NavMenu 导航菜单组件来实现。

此时可以将菜单栏和标题栏拆分成独立组件引入默认布局,创建src/views/layout/components目录并新建header.vuemenu.vue

此时我们希望菜单根据router配置自动生成,所以需要修改router,可以将router配置单独提取成routes.js便于其它页面调用。同时新建一个CURD页面curd.vue

[标题栏] src/views/layout/components/header.vue:

<template><div class="layout-header"><i class="icon-collapse" :class="`el-icon-s-${collapse ? 'unfold' : 'fold'}`" @click="collapseMenu"></i><div v-if="$route.name === 'index'" class="el-page-header"><div class="el-page-header__content">首页</div></div><el-page-header v-else @back="goBack" :content="content"></el-page-header></div>
</template><script>
export default {props: {collapse: {type: Boolean,}},data: () => ({content: ''}),watch: {$route: {handler(to) {this.content = to.meta.title;},immediate: true}},methods: {goBack() {this.$router.back();},collapseMenu() {this.$emit('collapse-menu');}},
}
</script><style>
.layout-header {position: relative;height: 100%;padding: 0 20px;background: #fff;box-shadow: 0 1px 4px rgba(0,21,41,.08);display: flex;align-items: center;
}
.layout-header .icon-collapse {cursor: pointer;font-size: 20px;padding-right: 20px;
}
</style>

[导航菜单] src/views/layout/components/menu.vue:

<template><el-menuref="menu"class="layout-menu"background-color="#001529"text-color="#fff"active-text-color="#1890ff":collapse="collapse":default-active="$route.name"><router-link v-for="(menu, index) in menus" :key="index" :to="menu.path"><el-menu-item :index="menu.name"><i :class="`el-icon-${menu.meta.icon || 'menu'}`"></i><span slot="title">{{ menu.meta.title }}</span></el-menu-item></router-link></el-menu>
</template><script>
import routes from '@/router/routes';export default {props: {collapse: Boolean},computed: {menus() {return routes[0].children || [];}},
}
</script><style>
.layout-menu {height: 100%;width: 100%;
}
</style>

[路由设置] src/router/index.js:

import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes'Vue.use(VueRouter)const router = new VueRouter({routes
})export default router;

[路由表] src/router/routes.js:

import DefaultLayout from '@/views/layout/default';export default [{path: '',component: DefaultLayout,redirect: 'index',children: [{path: 'index',name: 'index',component: () => import('@/views/page/index'),meta: { title: '首页', icon: 's-home' }},{path: 'curd',name: 'curd',component: () => import('@/views/page/curd'),meta: { title: '增删改查', icon: 's-opportunity' }}],},
]

src/views/page/curd.vue:

<template><div>CURD页面</div>
</template>

src/views/layout/default.vue

<template><el-container class="layout-default"><el-aside class="layout-default__menu" :style="{ width: `${collapse ? 64 : 256}px` }"><layout-menu :collapse="collapse"></layout-menu></el-aside><el-container class="layout-default__main" :style="{ 'margin-left': `${collapse ? 64 : 256}px` }"><el-header><layout-header @collapse-menu="collapse = !collapse" :collapse="collapse"></layout-header></el-header><el-main><router-view></router-view></el-main></el-container></el-container>
</template><script>
import LayoutMenu from './components/menu';
import LayoutHeader from './components/header';export default {components: { LayoutMenu, LayoutHeader },data: () => ({collapse: false,}),
}
</script><style>
.layout-default .el-header {padding: 0;
}
.layout-default__menu {position: fixed;overflow-x: hidden;background-color: #001529;transition: width 300ms;overflow-x: hidden !important;height: 100vh;
}
.layout-default__main {transition: margin 300ms;
}
.layout-default__menu, .layout-default__menu .el-menu {border: 0 !important;
}
</style>

此时的目录结构是这样的:
在这里插入图片描述
这时可以看到页面已经有了较为美观的样式:

在这里插入图片描述
在这里插入图片描述
且菜单支持收起和展开:
在这里插入图片描述

8.2 修改curd页面结构

一个基本的CURD页面应该包括:查询条件操作按钮数据列表列表分页编辑表单详情展示等几个基本模块。

因此我们可以修改原有的curd.vue为一个curd目录,目录下包括index.vue及其相关组件。由于表单页面相对而言重复性较高,代码较为冗长,所以我们将其拆分为index.vuesearch.vueform.vue三个组件,其中index.vue为列表分页展示及数据控制,search.vue和form.vue为表单组件。

search.vue搜索表单我们可以参照element的行内表单示例进行修改:

src/views/curd/search.vue:

<template><el-card shadow="never"><el-form inline :model="model" size="small"><el-form-item label="姓名"><el-input v-model="model.name" placeholder="请输入姓名"></el-input></el-form-item><el-form-item label="性别"><el-select v-model="model.gender" placeholder="请选择性别"><el-option label="小姐姐" value="famale"></el-option><el-option label="小哥哥" value="male"></el-option></el-select></el-form-item><el-form-item><el-button type="primary" @click="handleSubmit">查询</el-button><el-button plain @click="handleReset">重置</el-button></el-form-item></el-form></el-card>
</template><script>export default {props: {value: {type: Object,default: () => {return {};}},},data: () => ({model: {}}),watch: {value: {handler(val) {if (val) {Object.keys(this.model).forEach(key => {this.model[key] = val[key];});} else {Object.keys(this.model).forEach(key => {this.model[key] = null;});}},immediate: true,},model: {handler(val) {this.$emit("input", val);},deep: true}},methods: {handleSubmit() {this.$emit('search', this.model);},handleReset() {Object.keys(this.model).forEach(key => {this.model[key] = null;});}}}
</script>

form.vue搜索表单我们可以参照element的表单验证示例进行修改:

src/views/curd/form.vue:

<template><el-form ref="form" :model="model" :rules="rules" size="small" label-width="100px"><el-form-item label="姓名" prop="name"><el-input v-model="model.name"></el-input></el-form-item><el-form-item label="性别" prop="gender"><el-select v-model="model.gender" placeholder="请选择性别"><el-option label="小姐姐" value="famale"></el-option><el-option label="小哥哥" value="male"></el-option></el-select></el-form-item><el-form-item label="年龄" prop="age"><el-input-number v-model="model.age"></el-input-number></el-form-item><el-form-item><el-button type="primary" size="small" @click="handleSubmit">确定</el-button><el-button plain size="small" @click="handleCancel" style="margin-left: 8px">取消</el-button></el-form-item></el-form>
</template><script>
export default {props: {value: {type: Object,default: () => {return {};}},},data: () => ({model: {name: '',gender: null,age: 18,},rules: {name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],gender: [{ required: true, message: '请选择性别', trigger: 'change' }],age: [{ required: true, message: '请输入年龄', trigger: 'change' }],}}),watch: {value: {handler(val) {if (val) {Object.keys(this.model).forEach(key => {this.model[key] = val[key];});} else {Object.keys(this.model).forEach(key => {this.model[key] = null;});}},immediate: true,},model: {handler(val) {this.$emit("input", val);},deep: true}},methods: {// 点击确定提交表单的操作handleSubmit(name) {this.$refs.form.validate(valid => {if (valid) {const result = this.submitPure ? this.getPureModel() : JSON.parse(JSON.stringify(this.model));this.$emit("submit", result);}});},// 校验表单validate() {this.$refs.form.validate(valid => {this.$emit("validate", valid);});},// 重置表单reset() {Object.keys(this.model).forEach(key => {this.model[key] = undefined;});this.$nextTick(() => {this.$refs.form.clearValidate();});},// 点击取消的操作handleCancel() {this.$emit("cancel");}}
};
</script>

index.vue则是对以上组件的整合以及列表数据的展示操作。

src/views/curd/index.vue:

<template><div class="page-curd"><curd-search @search="handleSearch"></curd-search><div class="page-curd__action-bar"><el-button type="primary" icon="el-icon-plus" size="small" @click="handleNew">新增</el-button><el-button icon="el-icon-delete" size="small" :disabled="tableSelection && tableSelection.length <= 0" @click="handleDeleteMul">批量删除</el-button></div><el-table size="mini" :data="tableData" class="page-curd__table" border @selection-change="handleTableSelectionChange"><el-table-column type="selection" min-width="35"></el-table-column><el-table-column label="姓名" prop="name" min-width="100"><template slot-scope="{ row }"><span><i class="el-icon-user-solid"></i>{{ row.name }}</span></template></el-table-column><el-table-column label="性别" prop="gender"><template slot-scope="{ row }"><el-tag v-if="row.gender === 'male'" size="small">小哥哥 ♂</el-tag><el-tag v-else type="danger" size="small">小姐姐 ♀</el-tag></template></el-table-column><el-table-column label="年龄" prop="age"></el-table-column><el-table-column label="操作" min-width="140" fixed="right"><template slot-scope="slotScope"><el-button class="eagle-scheme__table-btn" type="text" icon="el-icon-view" title="详情" @click="handleView(slotScope)"></el-button><el-button class="eagle-scheme__table-btn" type="text" icon="el-icon-edit" title="编辑" @click="handleEdit(slotScope)"></el-button><el-button type="text" icon="el-icon-delete" title="删除" @click="handleDelete(slotScope)"></el-button></template></el-table-column></el-table><el-paginationclass="page-curd__pagination"@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="[10, 20, 50, 100]":page-size="pageSize"layout="total, sizes, prev, pager, next, jumper":total="total"background></el-pagination><el-dialog :visible.sync="dialogVisible" :title="title" width="450px" :close-on-click-modal="dialogMode === 'view'" append-to-body><template v-if="dialogMode === 'view'"><el-row :gutter="20"><el-col :span="12">姓名:{{ formModel.name }}</el-col><el-col :span="12">性别:<template v-if="formModel.gender"><el-tag v-if="formModel.gender === 'male'" size="small">小哥哥 ♂</el-tag><el-tag v-else type="danger" size="small">小姐姐 ♀</el-tag></template></el-col><el-col :span="12" style="margin-top: 20px;">年龄:{{ formModel.age }}</el-col></el-row></template><template v-else><curd-form ref="curdForm" v-model="formModel" @submit="handleSubmit" @cancel="handleCancel"></curd-form></template></el-dialog></div>
</template><script>
import CurdSearch from './search';
import CurdForm from './form';export default {components: { CurdSearch, CurdForm },data: () => ({dialogMode: 'new',dialogVisible: false,tableData: [{ name: '古力娜扎', age: 27, gender: 'famale' },{ name: '迪丽热巴', age: 27, gender: 'famale' },{ name: '尼格买提', age: 36, gender: 'male' },],currentPage: 1,pageSize: 10,total: 3,tableSelection: [],formModel: {}}),computed: {title() {if (this.dialogMode === 'view') {return '查看';}return this.dialogMode === 'edit' ? '编辑' : '新增';}},methods: {async handleSearch(value, needReset) {if (needReset) {this.currentPage = 1;}const param = {...value,currentPage: this.currentPage,pageSize: this.pageSize,};console.log(param);},handleNew() {if (this.$refs['curdForm']) { this.$refs['curdForm'].reset(); }this.dialogMode = 'new';this.dialogVisible = true;this.formModel = {};},handleView({ row }) {this.dialogMode = 'view';this.dialogVisible = true;this.formModel = { ...row };},handleEdit({ row }) {if (this.$refs['curdForm']) { this.$refs['curdForm'].reset(); }this.dialogMode = 'edit';this.dialogVisible = true;this.formModel = { ...row };},handleDelete({ row }) {console.log('delete:', row);},handleDeleteMul() {console.log('mul delete:', this.tableSelection);},handleSubmit() {if (this.dialogMode === 'new') {console.log('new', this.formModel);} else if (this.dialogMode === 'edit') {console.log('edit', this.formModel);}},handleCancel() {this.dialogVisible = false;},handleTableSelectionChange(selection) {this.tableSelection = selection;},handleSizeChange(val) {this.currentPage = 1;this.pageSize = val;this.handleSearch();},handleCurrentChange(val) {this.currentPage = val;this.handleSearch();},}
}
</script><style>
.page-curd__action-bar {margin: 20px 0px;
}
.page-curd__table {margin-bottom: 20px;
}
.page-curd .el-icon-user-solid {padding-right: 10px;
}
.page-curd__pagination {text-align: right;
}
</style>

假如你有强迫症的话,那就顺便把首页略微修改一下。

src/views/page/index.vue:

<template><div class="page-index">Vue入门项目CURD示例</div>
</template><style>
.page-index {text-align: center;padding-top: calc(50vh - 60px - 24px);font-size: 24px;
}
</style>

此时的项目效果如下:

首页
在这里插入图片描述
CURD页面
在这里插入图片描述
新增
在这里插入图片描述
编辑
在这里插入图片描述
查看详情
在这里插入图片描述

8.3 模拟接口数据

本示例项目为纯前端项目,所以使用mockjs来模拟增删改查的基本API。

在项目中新建一个mock目录用于存放模拟mockjs配置文件。包括index.jsutil.jsmodule/user.js

src/mock/index.js:

import Mock from 'mockjs';
import { parseUrl } from './util';
import userAPI from './module/user';// 临时缓存mockjs数据
let MockCache = {};const MockBot = {// 通用模板APIfastAPI: {// 获取数据列表page: (base) => config => {const list = MockCache[base] || [];const param = parseUrl(config.url) || {};const { page = 1, size = 10, ...query } = param;// 计算有几个搜索条件let queryCount = false;for (let key in query) {if (query[key]) {queryCount += 1;break;}}// 根据搜索条件过滤结果const filteredList = queryCount > 0 ? list.filter(data => {let result = false;for (let key in query) {if (data[key] === query[key]) {result = true;break;}}return result;}) : list;// 根据结果处理分页数据const _page = Number(page);const _limit = Number(size);const pageList = filteredList.filter((item, index) => index < _limit * _page && index >= _limit * (_page - 1));const response = {page: _page,size: _limit,result: {list: pageList,total: filteredList.length,},success: true,};return response;},// 查询数据详情get: (base) => config => {const list = MockCache[base] || [];const param = parseUrl(config.url) || {};const id = param.id;const result = list.find((item) => item.id == id);return {result: result,success: true,};},// 新增数据add: (base) => config => {const param = JSON.parse(config.body);MockCache[base].unshift(param);return {success: true,};},// 编辑数据update: (base) => config => {const param = JSON.parse(config.body);const index = MockCache[base].findIndex(item => item.id === param.id);MockCache[base][index] = param;return {success: true,};},// 删除数据delete: (base) => config => {const ids = JSON.parse(config.body);ids.forEach(id => {MockCache[base] = MockCache[base].filter(item => item.id !== id);});return {success: true,};}},// 根据通用模板API快速创建模拟接口fastMock: (url, list) => {MockCache[url] = list;Mock.mock(new RegExp(`\/${url}\/page`), 'get', MockBot.fastAPI.page(url));Mock.mock(new RegExp(`\/${url}\/get`), 'get', MockBot.fastAPI.get(url));Mock.mock(new RegExp(`\/${url}\/add`), 'post', MockBot.fastAPI.add(url));Mock.mock(new RegExp(`\/${url}\/update`), 'post', MockBot.fastAPI.update(url));Mock.mock(new RegExp(`\/${url}\/delete`), 'post', MockBot.fastAPI.delete(url));},
}// 产品管理
MockBot.fastMock('user', userAPI.userList);

src/mock/util.js:

import Mock from 'mockjs';export const parseUrl = (url) => {let obj = {};// 创建一个Objectlet reg = /[?&][^?&]+=[^?&]+/g;// 正则匹配 ?&开始 =拼接  非?&结束  的参数let arr = url.match(reg);// match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。// arr数组形式 ['?id=12345','&a=b']if (arr) {arr.forEach((item) => {/*** tempArr数组    ['id','12345']和['a','b']* 第一个是key,第二个是value* */let tempArr = item.substring(1).split('=');let key = decodeURIComponent(tempArr[0]);let val = decodeURIComponent(tempArr[1]);obj[key] = val;});}return obj;
}export default {// 根据配置文件和数量快速生成数据列表fastList: (config, count) => {const list = []for (let i = 0; i < count; i++) {list.push(Mock.mock(config));}return list;},
}

src/mock/module/user.js:

import MockUtil from '../util';export default {// 用户列表userList: MockUtil.fastList({id: '@guid()',name: '@cname()','gender|1': ['male', 'famale'],'age|16-40': 1,}, 43),
}

8.4 对接接口数据

模拟好接口,接下来就需要进行接口对接了,首先我们修改main.js,将axios创建一个实例并设置为Vue的prototype,这样可以在每个Vue页面或组件中直接通过this进行访问。

创建axios实例后可以设置request和response拦截器,具体用法请查看axios官方文档

src/main.js:

import Vue from 'vue';
import axios from 'axios';
import App from '@/App.vue';
import router from '@/router';
import store from '@/store';
import ElementUI from 'element-ui'; // ElementUI组件库
import 'element-ui/packages/theme-chalk/lib/index.css'; // ElementUI组件库样式
import '@/mock';const request = axios.create({baseURL: 'http://localhost',timeout: 1000 * 60,withCredentials: true,
});// respone 拦截器
request.interceptors.response.use(response => {const { data = {} } = response;const { success } = data;if (success) {return data;} else {return { success };}},error => {return { success: false };});Vue.prototype.$request = request;// 注册饿了么UI
Vue.use(ElementUI);new Vue({router,store,render: h => h(App)
}).$mount('#app')

配置好axios之后,我们就可以在curd页面中进行对接了。

src/views/page/curd/index.vue:

<template><div class="page-curd"><curd-search @search="handleSearch"></curd-search><div class="page-curd__action-bar"><el-button type="primary" icon="el-icon-plus" size="small" @click="handleNew">新增</el-button><el-button icon="el-icon-delete" size="small" :disabled="tableSelection && tableSelection.length <= 0" @click="handleDeleteMul">批量删除</el-button></div><el-table size="mini" :data="tableData" class="page-curd__table" border @selection-change="handleTableSelectionChange"><el-table-column type="selection" min-width="35"></el-table-column><el-table-column label="姓名" prop="name" min-width="100"><template slot-scope="{ row }"><span><i class="el-icon-user-solid"></i>{{ row.name }}</span></template></el-table-column><el-table-column label="性别" prop="gender"><template slot-scope="{ row }"><el-tag v-if="row.gender === 'male'" size="small">小哥哥 ♂</el-tag><el-tag v-else type="danger" size="small">小姐姐 ♀</el-tag></template></el-table-column><el-table-column label="年龄" prop="age"></el-table-column><el-table-column label="操作" min-width="140" fixed="right"><template slot-scope="slotScope"><el-button class="eagle-scheme__table-btn" type="text" icon="el-icon-view" title="详情" @click="handleView(slotScope)"></el-button><el-button class="eagle-scheme__table-btn" type="text" icon="el-icon-edit" title="编辑" @click="handleEdit(slotScope)"></el-button><el-button type="text" icon="el-icon-delete" title="删除" @click="handleDelete(slotScope)"></el-button></template></el-table-column></el-table><el-paginationclass="page-curd__pagination"@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="[10, 20, 50, 100]":page-size="pageSize"layout="total, sizes, prev, pager, next, jumper":total="total"background></el-pagination><el-dialog :visible.sync="dialogVisible" :title="title" width="450px" :close-on-click-modal="dialogMode === 'view'" append-to-body><template v-if="dialogMode === 'view'"><el-row :gutter="20"><el-col :span="12">姓名:{{ formModel.name }}</el-col><el-col :span="12">性别:<template v-if="formModel.gender"><el-tag v-if="formModel.gender === 'male'" size="small">小哥哥 ♂</el-tag><el-tag v-else type="danger" size="small">小姐姐 ♀</el-tag></template></el-col><el-col :span="12" style="margin-top: 20px;">年龄:{{ formModel.age }}</el-col></el-row></template><template v-else><curd-form ref="curdForm" v-model="formModel" @submit="handleSubmit" @cancel="handleCancel"></curd-form></template></el-dialog></div>
</template><script>
import CurdSearch from './search';
import CurdForm from './form';export default {components: { CurdSearch, CurdForm },data: () => ({dialogMode: 'new',dialogVisible: false,tableData: [],currentPage: 1,pageSize: 10,total: 3,tableSelection: [],formModel: {},currentRow: {},}),computed: {title() {if (this.dialogMode === 'view') {return '查看';}return this.dialogMode === 'edit' ? '编辑' : '新增';}},created() {this.handleSearch();},methods: {async handleSearch(value, needReset) {if (needReset) {this.currentPage = 1;}const params = {...value,page: this.currentPage,size: this.pageSize,};this.$request.get('/user/page', { params }).then(response => {const { result: { list, total } = {} } = response;this.tableData = list;this.total = total;});},handleNew() {if (this.$refs['curdForm']) { this.$refs['curdForm'].reset(); }this.dialogMode = 'new';this.dialogVisible = true;this.formModel = {};},handleView({ row }) {this.dialogMode = 'view';this.dialogVisible = true;this.formModel = { ...row };},handleEdit({ row }) {if (this.$refs['curdForm']) { this.$refs['curdForm'].reset(); }this.dialogMode = 'edit';this.$request.get('/user/get', { params: { id: row.id } }).then(response => {const { result } = response;this.formModel = result;this.currentRow = result;this.dialogVisible = true;});},handleDelete({ row }) {this.$request.post('/user/delete', [row.id]).then(response => {const { success } = response;if (success) {this.$message.success('删除成功');this.handleSearch();}});},handleDeleteMul() {const ids = this.tableSelection.map(selection => selection.id);this.$request.post('/user/delete', ids).then(response => {const { success } = response;if (success) {this.$message.success('删除成功');this.handleSearch();}});},handleSubmit() {if (this.dialogMode === 'new') {this.$request.post('/user/add', { ...this.formModel, id: undefined }).then(response => {const { success } = response;if (success) {this.$message.success('新增成功');this.handleSearch();this.dialogVisible = false;}});} else if (this.dialogMode === 'edit') {this.$request.post('/user/update', { ...this.formModel, id: this.currentRow.id }).then(response => {const { success } = response;if (success) {this.$message.success('编辑成功');this.handleSearch();this.dialogVisible = false;}});}},handleCancel() {this.dialogVisible = false;},handleTableSelectionChange(selection) {this.tableSelection = selection;},handleSizeChange(val) {this.currentPage = 1;this.pageSize = val;this.handleSearch();},handleCurrentChange(val) {this.currentPage = val;this.handleSearch();},}
}
</script><style>
.page-curd__action-bar {margin: 20px 0px;
}
.page-curd__table {margin-bottom: 20px;
}
.page-curd .el-icon-user-solid {padding-right: 10px;
}
.page-curd__pagination {text-align: right;
}
</style>

至此,一个基本的CURD示例就完成了。

在这里插入图片描述

九、总结

在本实例项目中,并没有使用多少依赖项,只有基本的UI组件库element、基于promise的HTTP库axios、前端模拟数据的mockjs,至于本文开始时,创建项目选择的vuex并没有提到,这个建议小伙伴们自己查阅相关资料去学习。

在我的学习理念中,每当学习到一个新的技术时,可以先查阅学习技术的简单教程,然后上手实践,从模仿到举一反三再到创新,千万不要只学习理论而不主动去实践,这样效果并不深刻。

本文中有一些ES6以上的语法并没有过多提及,有许多技巧也并没有过多的给大家解释,更多的技术细节我会在以后的文章中提到,如果有BUG或者不对的地方,欢迎各位小伙伴留言指正!

谢谢。


http://chatgpt.dhexx.cn/article/bJfSfoBV.shtml

相关文章

fastadmin一键生成CURD

1.登录后台以后安装在线命令插件 2.CRUD fastadmin自带一个test表可以用来测试&#xff0c;或者是自己在数据库随便新建一个表也行 自定义模块名这样填的话就是在admin->controller下->新建一个名为test文件夹 只写test的话是在 controller 目录下面 然后点击生成命令行…

php跨域curd,SpringBoot+Vue前后端分离(CURD)Demo

我发现我好久没有更新了&#xff0c;写一篇证明我还活着。 既然是前后端分离的话&#xff0c;肯定是要有前端和后端的。 这里前端我使用的VueElementUI,后端采用的是SpringBootMybatisSwagger2。 下面的话&#xff0c;我就做一个简单的Demo吧。 写的不好&#xff0c;请大家各位…

单表CURD操作

该项目纯粹用 Servlet 编写&#xff0c;理解跳转过程。理解原理..... 一、准备数据库脚本 USE test;DROP TABLE IF EXISTS dept;CREATE TABLE dept (deptno int(2) NOT NULL,dname varchar(14) DEFAULT NULL,loc varchar(13) DEFAULT NULL,PRIMARY KEY (DEPTNO) ) ENGINEInnoD…

Avue-curd个性化定制

在使用vue(js)elelment(ui)开发一些后台管理项目的时候&#xff0c;基本会用到 列表页&#xff0c;条件搜索(search),表格数据(table),分页&#xff0c;操作栏的&#xff0c;增、删、改、查几种操作。如下图这样的&#xff1a; 很多的页面都很类似&#xff0c;这里就给大家介绍…

Python简单CURD

python Python的注释模块 python变量 格式化输出 转义字符 与 数据类型 控制台输入 实体类 Student.dy class Emp:def __init__(self,id,name,age,sex,sal):self.id idself.name nameself.age ageself.sex sexself.sal saldef __str__(self):return "学号&#xf…

MySQL常用语句(CURD)

文章目录 一、数据库定义语言&#xff08;DDL&#xff09;1.1 库操作1.2 表操作 二、数据库操纵语言&#xff08;DML&#xff09;2.1 插入 insert2.2 修改 update2.3 删除 delete 三、数据库查询语言&#xff08;DQL&#xff09;3.1 单表查询①查询&#xff1a;select②条件&am…

SpringBoot实现CURD

SpringBoot实现CURD 项目列表 Pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http:/…

thinkphp curd 列表关联展现方式分享

在维护自己的开源框架中&#xff0c;针对后台列表模板&#xff0c;有时候我们需要在一键CURD的情况下&#xff0c;进行多个字段的关联显示&#xff0c;比如用户订单表里面存在user_id字段&#xff0c;那么在显示的时候&#xff0c;我们期望显示出用户的名称&#xff0c;而不是用…

mysql curd_mysql 基础之CURD

原文:mysql 基础之CURD 增删改查基本语法学习 增: insert Insert 3问: 1: 插入哪张表? 2: 插入哪几列? 3: 这几列分别插入什么值? Insert into TableName (列1,列2....列n) Values (值1,值2,....值n) 值 与 列,按顺序,一一对应 特殊: insert语句 允不允许不写列名 答:允许. …

小白入门:什么是CURD?

CRUD是CREATE、READ、UPDATE和DELETE的首字母缩写词&#xff0c;在数据库操作中频繁出现&#xff0c;本文针对小白&#xff0c;如果你已经是开发人员或者对数据库有一定认识的工程师可以默默离开了。让我直接走进CURD的世界。 为什么 CRUD 如此重要&#xff1f; CRUD 经常用于…

大龄焦虑?如何看待程序员35岁职业危机?

往期精选&#xff08;欢迎转发~~&#xff09; Java全套学习资料&#xff08;14W字&#xff09;&#xff0c;耗时半年整理 消息队列&#xff1a;从选型到原理&#xff0c;一文带你全部掌握 肝了一个月的ETCD&#xff0c;从Raft原理到实践 我肝了三个月&#xff0c;为你写出了…

Sitemesh前段框架基础

用sitemesh框架解决项目统一布局的解决方案 Sitemesh装饰框架 Sitemesh项目简介&#xff1a; Sitemesh是一个用来在jsp中实现页面布局和装饰&#xff08;layout and decoration&#xff09;的框架组件&#xff0c;能够帮助网站开发人员较容易实现页面中动态和静态装饰外观的分…

Sitemesh Demo

简介 sitemesh是一个网页布局与装饰体系,主要应用于创建具有大量一致性用户界面、导航与布局框架的站点。sitemesh拦截一切经过web server的静态或动态生成的HTML页面请求,处理页面内容,并将其与一个或多个装饰页面进行融合,生成最终页面。sitemesh也可用于构建由多个部分小…

spring集成sitemesh3

1、SiteMesh是什么&#xff1f; SiteMesh是一个网页布局和修饰的框架&#xff0c;利用它可以将网页的内容和页面结构分离&#xff0c;以达到页面结构共享的目的。 SiteMesh是基于Servlet的filter&#xff0c;通过截取response&#xff0c;并进行装饰后再交付给客户。 2、SiteMe…

sitemesh框架的简单使用(springboot+maven+jsp+sitemesh)

一 简单介绍 sitemesh是一种模板框架&#xff0c;是为了解决页面重复代码而设计的sitemesh的设计思想是装饰者设计模式 二 简单使用 目录结构&#xff0c;因为我这个项目本来是用来学习flowable的&#xff0c;后面为了方便快速学习&#xff0c;直接把sitemesh集成到这里了&a…

SiteMesh3简介及使用

最近项目用到SiteMesh3&#xff0c;研究学习一段时间后决定写篇博文来记录收获。 SiteMesh SiteMesh 介绍工作原理配置及使用 下载1添加maven依赖2webxml中添加SiteMesh过滤器3创建一个装饰页面decorator page4创建一个被装饰页面content page5配置 1XML方式1Java方式 6查看…

sitemesh初步

sitemesh小项目 1.工程目录 2.需要的lib:sitemesh-2.4.2.jar http://wiki.sitemesh.org/wiki/display/sitemesh/Download 3.配置 decorators.xml[sitemesh的配置文件] <?xml version"1.0" encoding"ISO-8859-1"?><!-- 在defaultdir目录…

SiteMesh框架统一布局用法介绍

SiteMesh 是一个网页布局和修饰的框架&#xff0c;基于 Servlet 中的 Filter&#xff0c;类似于 ASP.NET 中的‘母版页’技术。 介绍&#xff1a; 1&#xff0c;SiteMesh是OpenSymphony团队开发的JEE框架之一,它是一个非常优秀的页面装饰器框架。它通过对所有的用户请求进行过…

SIteMesh介绍

转自:http://javauu.com/thread-27-1-1.html 一、SIteMesh介绍 一、SiteMesh简介 SiteMesh是由一个基于Web页面布局、装饰以及与现存Web应用整合的框架。它能帮助我们在由大量页面构成的项目中创建一致的页面布局和外观&#xff0c;如一致的导航条&#xff0c;一致的banner&a…

【CSRF】学习关于CSRF攻击和防范

文章目录 1.CSRF攻击是什么2.CSRF攻击如何实现2.1 使用GET请求的CSRF的攻击例子2.2 使用post请求的CSRF攻击 3.如何防御CSRF攻击3.1 什么是CSRF令牌3.2 反-CSRF令牌工作流程3.3 同站Cookie策略 4.结论 高质量原文&#xff1a; CSRF Attacks: Anatomy, Prevention, and XSRF To…