此demo选用的vue2.x版本
看完你将收获以下几点技能:
- 快速创建vue项目
- 理解vue常用指令的使用场景
- 网站快速成型工具Element-ui使用
- 项目中增删改查的具体应用
效果图
技术栈
vue2.x + Element-ui + sass + esLint + standard
构建工具选择
如你遇到包下载慢、依赖不同导致各种bug等等(因为npm镜像地址在国外所以访问会慢有的时候还访问不到),可选用淘宝镜像地址(淘宝镜像同步频率目前为10分钟一次以保证尽量与官方服务同步)或者pnpm,
pnpm是高性能的npm,pnpm节省磁盘空间,安装速度快;通过内容可寻址存储(CAS)、符号链接(Symbolic Link)、硬链接(Hard Link)等管理依赖包。
设置淘宝镜像地址
// 淘宝镜像新地址旧地址
https://registry.npm.taobao.org // 旧
https://registry.npmmirror.com // 新
// 永久使用
npm config set registry https://registry.npmmirror.com
// 使用淘宝镜像并把npm设置为cnpm
npm install -g cnpm --registry=https://registry.npm.npmmirror.org
// 查看是否设置成功
npm get registry
换回npm官网地址
如果淘宝镜像影响你发布模块可这样换回去
npm config set registry https://registry.npmjs.org
安装pnpm
npm install -g pnpm
// 或
cnpm install -g pnpm
一.安装vue
在安装之前先确保安装了node环境, 如果没有安装,去官网最新稳定版下载nodejs
全局安装vue-cli
一键生成工程化的vue项目
cnpm install -g @vue/cli
# 或者
yarn global add @vue/cli
查看vue-cli版本
vue -V // @vue/cli 5.0.8 vue-^2.6.14
创建vue项目
vue create vue2-demo
// 或者
mkdir vue2-demo && cd vue2-demo // 创建vue2-demo文件夹并进入目录
vue create . // 在当前创建vue项目
接下来会出现选择以前的配置项还是vue默认创建的项目,还是手动选择,
选择Manually select features(手动安装),会进入下一步操作
用空格和上下箭头选择配置项
CSS Pre-processors // CSS 预处理器
Linter / Formatter // 代码风格检查和格式化(选择保存和提交时校验)
选择standard编码规范
Sass/SCSS (with dart-sass) // 如果不想安装node-sass选择dart-sass
查看standardjs编码规范
二.安装Element-ui
cnpm i element-ui -S
三.使用element-ui布局页面
第一步先在main.js 引入ui
完整引入
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});
两种引入方式: 完整引入和按需引入,建议选用按需引入,具体操作见官网
流程:官网-> 组件 -> 快速上手
element官网
第二步:布局页面
找到Container 布局容器模块,选择第一个模版 由header和main组成的模块,也就是分为标题和主内容部分
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
</el-container>
按模块添加如下代码:
<el-container>
<el-header>vue2.x增删改查part01</el-header>
<el-container>
<el-main>
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item>
<el-input placeholder="请输入用户名" v-model="formInline.username" clearable>
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search">查询</el-button>
<el-button type="success" @click="show">添加</el-button>
<el-button type="danger">批量删除</el-button>
</el-form-item>
</el-form>
<el-table v-if="tableData.length > 0" :data="tableData" border style="width: 100%">
<el-table-column type="selection" width="40">
</el-table-column>
<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="操作">
<template slot-scope="scope">
<el-button
@click="handleClick(scope.row)"
type="primary"
size="mini"
>查看</el-button
>
<el-button type="success" size="mini">编辑</el-button>
<el-button type="danger" size="mini">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="nodata" v-else>无数据...</div>
</el-main>
</el-container>
</el-container>
弹出框模版代码
<!-- dialog start -->
<el-dialog
title="默认弹层标题"
:visible.sync="showDialog"
custom-class="mydialog"
@close="close"
>
<div slot="title" align="left">添加信息</div>
<el-form
:model="addQuery"
:inline="true"
label-position="right"
label-width="80px"
>
<el-form-item label="用户名">
<el-input v-model="addQuery.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="选择日期">
<el-date-picker
v-model="addQuery.date"
type="date"
style="width:90%"
placeholder="选择日期"
>
</el-date-picker>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="close">取 消</el-button>
<el-button type="primary" @click="add">确 定</el-button>
</div>
</el-dialog>
<!-- dialog end! -->
页面js初始数据
data () {
return {
idx: 1, // 初始化id 为了使用本地数据
editId: 0, // 要编辑的id
showDialog: false, // 弹出层开关
addQuery: { // 添加字段
username: '',
date: ''
},
formInline: { // 查询字段
username: ''
},
tableData: [
{
id: 1,
date: '2016-05-02',
name: '王小虎1',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
id: 2,
date: '2016-05-04',
name: '王小虎2',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1517 弄',
zip: 200333
},
{
id: 3,
date: '2016-05-01',
name: '王小虎3',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1519 弄',
zip: 200333
},
{
id: 4,
date: '2016-05-03',
name: '王小虎4',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1516 弄',
zip: 200333
}
]
}
},
methods: {
handleClick (row) {
console.log(row) // 查看 暂时不做什么功能
}
}
备注:如果table出不来,一片空白,原因是element-ui版本过高,在package里修改版本后 element-ui版本,cnpm install即可
四.添加-增/删/改/查 逻辑
查询
<el-input placeholder="请输入用户名" v-model.trim="formInline.username" clearable></el-input>
<el-button type="primary" icon="el-icon-search" @click="search">查询</el-button>
// js-code
search () {
/*
第一步:先拿到input输入的内容
第二步: 遍历数组找到元素filter
第三步:原数组赋值-更新视图
*/
const userName = this.formInline.username
if (userName === '') {
alert('请输入查询内容哦') // 暂时用alert 哦~,可以用element自带的漂亮框
return
}
const tableData = JSON.parse(localStorage.getItem('tableData'))
this.tableData = tableData.filter(item => item.name === userName)
}
注意:因为是本地数据,当查询条件有一个成立,不刷新页面的情况,再次查询会出现无数据,原因是:
假如:第一次查询name为王小虎1,把过滤的结果赋值给tableData,那么,
此时tableData里就只有name为王小虎1的这条数据;
再次查询,即从最新的tableData里查询,查询name为王小虎2的,显
然找不到,所以也就会出现无数据情况。
解决办法:因为是本地数据库,那么我们可以在页面挂载成功后,把tableData放到本地缓存一份,增加或者删除的时候更新本地缓存,查询的时候从本地缓存里查询,即可解决这个问题。
新增localStoreSetItem函数
localStoreSetItem () {
localStorage.setItem('tableData', JSON.stringify(this.tableData))
}
mounted () {
this.idx = this.tableData.length // 本地数据生成id,用接口方式不需要这行代码哦
this.localStoreSetItem()
},
添加逻辑
<el-button type="primary" @click="add">确 定</el-button>
add () {
/*
第一步:拿到弹出层输入框内容
定义日期格式化函数:formatDate 转换格式
第二步:追加到tableData数组中
定义插入对象格式
第三步:给tableData赋值 ->更新视图
第四步:弹出层数据数据恢复默认,关闭弹出层后把属性设置为空 新增close
*/
const { username, date } = this.addQuery
const newDate = this.formatDate(date)
const obj = {
date: newDate,
name: username,
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
}
this.tableData.unshift(obj)
this.showDialog = false
},
close () {
this.showDialog = false
this.addQuery.name = ''
this.addQuery.date = ''
},
}
删除逻辑
// 模版
<el-button type="danger" size="mini" @click="del(scope.row.id)">删除</el-button>
// js
del (id) {
// 两种方法:filter,和splice 推荐splice
// this.tableData = this.tableData.filter((e) => e.id !== id)
// 先查找当前要删除的id在数组的位置
const index = this.tableData.findIndex((item) => item.id === id)
// 从当前位置开始删除1条内容
this.tableData.splice(index, 1)
// 更新缓存中的tableData数据
this.localStoreSetItem()
}
注意:删除的两种方法;注意更新本地缓存数据,不然有bug哦,删除后的元素还能被搜索到哦
批量删除
需要在el-table组件上绑定事件函数,@selection-change=“自定义函数”,可以拿到选中的元素集合数组展示
// 模版
<el-table
v-if="tableData.length > 0"
@selection-change="handleSelectionTable"
:data="tableData"
border
style="width: 100%"
>
// js
handleSelectionTable (val) {
this.selectionTableArr = val
},
delMore () {
/* 一.如果是后台接口只需要传递[id1,id],那我们直接把选中的id拿出来即可
两种方法:forEach,reduce
*/
console.time('forEach')
const ids = []
this.selectionTableArr.forEach(item => {
ids.push(item.id)
})
console.timeEnd('forEach') // forEach: 0.02099609375 ms
// reduce效率最高
console.time('reduce')
const ids1 = this.selectionTableArr.reduce((arr, item) => {
arr.push(item.id)
return arr
}, [])
console.timeEnd('reduce') // reduce: 0.009033203125 ms
console.log(ids1)
/* 二. 以上是给接口的,那么现在处理本地的批量删除
第一步:循环删除 -> 递归 do-while; 递归条件已选择的数组len小于0的时候停止
第二步:需要递归处理的事情,也就是while放的代码:先查找已选中的id在原数组的位置,然后splice删除1项
第三步:更新本地缓存
*/
let len = this.selectionTableArr.length
do {
const index = this.tableData.findIndex(item => item.id === this.selectionTableArr[len - 1].id)
this.tableData.splice(index, 1)
len--
// 刚更新本地缓存
this.localStoreSetItem()
} while (len > 0)
},
修改逻辑
因为修改逻辑处理完数据回填后,走的还是添加的逻辑,所以添加代码修改为
show () {
this.showDialog = true
this.editId = 0
},
edit (row) {
/*
分析:把当前要编辑的row拿到;然后赋值给弹出层表单model的addQuery对象,addQuery对象更新input的v-model值更新
第一步:拿到当前点击的row对象
第二步:给addQuery对象的属性赋值 for in 或者 深拷贝
第三步:点击保存后:1.如果是走的接口,那么会和添加是一样的逻辑
2.如果更新本地缓存,那么先找到当前id所在数组的位置
接着,用splice(index, 1, 新的内容对象) // 删除一条用新的内容替换
第四步:更新最新缓存数据tableData
*/
this.showDialog = true
for (const k in row) {
this.addQuery[k] = row[k]
}
this.editId = row.id
this.showDialog = true
},
add (id) {
/*
第一步:拿到弹出层输入框内容
定义日期格式化函数:formatDate 转换格式
第二步:追加到tableData数组中
定义插入对象格式
第三步:给tableData赋值 更新视图
第四步:弹出层数据数据恢复默认,关闭弹出层,
*/
!this.showDialog && (this.showDialog = true)
const { name, date } = this.addQuery
if (name === '' && this.date === '') {
alert('请填写内容')
return
}
// 如果有要修改的数据,把之前的旧数据删除
const index = this.tableData.findIndex(item => id === item.id)
const newDate = this.formatDate(date)
const obj = {
id: ++this.idx,
date: newDate,
name,
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
}
if (this.editId > 0) {
this.tableData.splice(index, 1, obj) // 如果是修改元素顺序不变
this.editId = 0
} else {
this.tableData.unshift(obj) // 如果是新添加第一条出现最上面
}
this.localStoreSetItem() // 不管是添加还是修改都要更新本地缓存
this.close()
},
五. 总结
1.添加或者修改数据后再次打开弹出层记得清空上一次的记录状态
2.使用本地数据和真实项目中的接口操作数据有很多地方变化,一定要注意之间的关系。