目录
后端写了,现在写前端使用vue+vue router+element实现代码。
在《hualinux 进阶 vue 5.1:用Element实现增删改查(一)需求及分析》已经做了分析了,在这里我就不再讲了,直接上代码。
一、运行环境
1.1 安装vue router及axios
前端element实现代码,这个是基于《hualinux 进阶 vue 3.1:vue cli手工创建Vue router》的基础上安装了axios,为了解决cors在根目录创建了一个vue.config.js,内容如下:
module.exports = {
devServer: {
proxy: 'http://192.168.3.200/index.php'
}
}
1.2 安装及引入element
我这里使用npm方式安装element ui,只要有webstorm终端terminal执行上面给出的命令即可。
安装完之后还不行,还要引入vue插件,我这里使用引入element全部组件,在src/main.js,添加如下代码
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI)
二、elemnet实现增删除改查代码
element之后把实现代码写在about页中,代码如下:
<template>
<div class="width_100 height_100" style="padding:50px 20px">
<!-- 一定要 highlight-current-row 选项,要不span和input标签切换不了-->
<el-table :data="info" stripe style="width: 100%" ref="multipleTable"
:row-class-name="tableRowClassName"
@selection-change="handleSelectionChange" highlight-current-row>
<el-table-column type="selection" width="80"></el-table-column>
<el-table-column type="index"></el-table-column>
<!-- 如果要隐藏此页用 v-if=false -->
<el-table-column prop="picid" label="图片ID" width="80">
<template v-slot="scope">
<span>{{ scope.row.picid }}</span>
</template>
</el-table-column>
<el-table-column prop="picurl" label="图片" width="150">
<template v-slot="scope">
<span v-if="scope.row.isSet">
<el-upload
class="avatar-uploader"
:data="{'picid':scope.row.picid}"
action="http://192.168.3.200/index.php/index/upload"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload">
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</span>
<span v-else><el-image class="img" :src="scope.row.picurl"></el-image></span>
</template>
</el-table-column>
<el-table-column prop="lable" label="图片名" width="100">
<template v-slot="scope">
<span v-if="scope.row.isSet">
<el-input size="mini" placeholder="请输入内容" v-model="rowSelect.lable">
</el-input>
</span>
<span v-else>{{ scope.row.lable }}</span>
</template>
</el-table-column>
<el-table-column prop="describe" label="说明" width="200">
<template v-slot="scope">
<span v-if="scope.row.isSet">
<el-input size="mini" placeholder="请输入内容" v-model="rowSelect.describe">
</el-input>
</span>
<span v-else>{{ scope.row.describe }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="">
<template v-slot="scope">
<span v-if="scope.row.isSet" class="el-tag el-tag--success el-tag--small" style="cursor: pointer;"
@click.stop="saveRow(scope.row,scope.$index)">
保存
</span>
<span v-else class="el-tag el-tag--primary el-tag--small" style="cursor: pointer;"
@click="editRow(scope.row,scope.$index)">
编辑
</span>
<span class="el-tag el-tag--danger el-tag--small" style="cursor: pointer;"
@click="deleteRow(scope.row,scope.$index)">
删除
</span>
</template>
</el-table-column>
</el-table>
<div v-show="isShow" style="margin-top:20px;width: 200px">
<el-button type="primary" icon="el-icon-delete" @click="delSel()">删除</el-button>
<el-button type="primary" @click="toggleSelection()">取消选择</el-button>
</div>
<div v-show="!isShow" style="margin-top:20px;width: 200px">
<el-button type="primary" @click="add()">添加</el-button>
</div>
<div>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes=[5,10,20,30,50]
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
hide-on-single-page
:total="pageTotal"
>
</el-pagination>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
name: 'element-curl',
data() {
return {
//总条目数
pageTotal: 7,
//总页数
pageCount: 10,
//每页条数
pageSize: 5,
//当前页
currentPage: 1,
//get获取数据的信息
info: null,
//所选择的行
rowSelect: null,
//图片Url,这个是上传头像功能
imageUrl: '',
//所上传没保存之前PHP返回的的临时目录,
picTempPath: '0',
//多选
multipleSelection: [],
//是否jjofi
isShow: false,
//axios请示返回的数据
axiosres: null
}
},
methods: {
// row-class-name 处理函数
// eslint-disable-next-line no-unused-vars
tableRowClassName(row, index) {
// 给每条数据添加一个索引,方便批量删除
row.row.index = row.rowIndex;
},
// 行编辑按钮对应的方法
editRow(row) {
//alert(JSON.stringify(row));
for (let i of this.info) {
// 为每行添加一个isSet=属性,否则点保存,会保存不了,1为true,0为false
if (i.isSet) return this.$message.warning("请先保存当前编辑项");
}
this.rowSelect = row
//1为真,0为假
row.isSet = 1;
this.imageUrl = row.picurl;
// 先清空上次只在的 picTemp 内容,这个picTemp是图片的保存路径
this.picTempPath = '0';
},
//保存功能
// eslint-disable-next-line no-unused-vars
saveRow(row, index) {
let flag = true;
//更新row的url,如果是原来的则不变。
row.picurl = this.imageUrl;
//alert(JSON.stringify(this.rowSelect));
if ((!this.rowSelect['lable'].trim()) || (!this.rowSelect['describe'].trim())) {
flag = false;
console.log('flag is false', false);
}
if (flag) {//判断主要字段是否填写,名字和描述,图片是不必须的
let data = JSON.parse(JSON.stringify(this.rowSelect));
for (let k in data) row[k] = data[k];
let urlStr = '/vue/' + row.picid;
//判断是新增加的字段
if (row.picid == null) {
//alert('这是新添加字段');
axios
.post('/vue', {
picrow: {
savename: this.picTempPath,
lable: row.lable,
describe: row.describe
}
})
.then(response => (this.axiosres = response.data));
} else {
axios
.put(urlStr, {
picrow: {
savename: this.picTempPath,
lable: row.lable,
describe: row.describe
}
})
.then(response => (this.axiosres = response.data));
}
this.$message.success("保存成功!" + this.axiosres);
row.isSet = false;//点击保存后该为false值,隐藏保存按钮,显示编辑按钮
} else {
this.$message({
type: 'warning',
message: "请全部填写"
})
}
},
//图片成功on-success 对应事件。
handleAvatarSuccess(res, file) {
this.imageUrl = URL.createObjectURL(file.raw);
this.picTempPath = res;
},
// 上传前处理 before-upload
beforeAvatarUpload(file) {
const isImg =
file.type === 'image/jpg' ||
file.type === 'image/jpeg' ||
file.type === 'image/png' ||
file.type === 'image/gif';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isImg) {
this.$message.error('上传头像图片只能是 JPG,png,gif 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
return isImg && isLt2M;
},
// 取消选择
toggleSelection(rows) {
if (rows) {
rows.forEach(row => {
this.$refs.multipleTable.toggleRowSelection(row);
});
} else {
this.$refs.multipleTable.clearSelection();
}
},
//多选 selection-change 事件
handleSelectionChange(rows) {
this.multipleSelection = rows;
//没有被选中
if (this.multipleSelection.length < 1) {
this.isShow = false;
} else {
this.isShow = true;
}
},
//删除行
deleteRow(row, index) {
let delstr = '/vue/' + row.picid;
axios
.delete(delstr)
.then(response => (this.axiosres = response.data))
.catch(error => (this.mydata = error));
if (this.axiosres === 1) {
this.info.splice(index, 1);
this.$message.success("删除成功!")
}
},
//批量删除,删除选项的行
delSel() {
//打印所选的行
//alert(JSON.stringify(this.multipleSelection));
let rows = this.multipleSelection
//放删除的id
let selPicids = [];
if (rows.length === 1) {
alert("你只选择一条数据!")
this.deleteRow(rows[0], rows[0].index);
}
/*
* 注意,这里不能直接在for of中,使用数组的splice方法进行删除多个元素,因为会变的,会出问题。
* 因为删除一个元素数组的下标就会发生变化,这样就会产生错乱
* 要用Set集合的delete方法进行删除
* */
let mySet = new Set(this.info)
for (let row of rows) {
selPicids.push(row.picid);
//删除vue展示
mySet.delete(row);
}
//alert(JSON.stringify(selPicids));
//alert(JSON.stringify(...mySet));
//删除数据库
axios
// delete第二个参数为config,所以传值时需要借助config中data字段,用data携带过去
// 注意:data的格式为: data:对象,如 data:{picid:'001'}
.delete('/index/dels', {data: {picids: JSON.stringify(selPicids)}})
.then(response => (this.axiosres = response.data))
.catch(error => (this.axiosres = error));
if (this.axiosres != 0) {
this.$message.success("成功删除记录::" + selPicids.length);
// 使用 ... 把Set转为数组
this.info = [...mySet];
} else {
this.$message.error("出错了:" + this.dlerss);
}
},
//添加一行
add() {
for (let i of this.info) {
if (i.isSet) return this.$message.warning("请先保存当前编辑项");
}
let emptyRow = {
picurl: null,
lable: '',
describe: '',
// 这个一定要设置
isSet: 1
}
this.info.push(emptyRow);
this.rowSelect = emptyRow;
},
//分页,size-change事件,pageSize 改变时会触发
handleSizeChange(val) {
//每页 val 条
this.pageSize = val;
this.listDataByPage();
},
// 分页,current-change 事件,currentPage 改变时会触发
handleCurrentChange(val) {
// 当前页: val
//alert(val);
this.currentPage = val;
this.listDataByPage();
},
// axios get 获取当前页数据
listDataByPage() {
axios
//默认第1页,5条,可以修改一下currentPage 和 pageSize 的值
.get('/vue?page=' + this.currentPage + '&pageSize=' + this.pageSize)
.then(
response => {
let res = response.data;
this.axiosres = res;
this.pageTotal = this.axiosres['list']['total'];
this.pageCount = this.axiosres['list']['last_page'];
this.info = res['list']['data'];
return this.info;
}
);
}
},
mounted()
{
this.listDataByPage();
}
,
}
</script>
<style scoped>
.img {
max-height: 80px;
max-width: 80px;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
max-width: 80px;
max-height: 80px;
display: block;
}
/* /deep/ 深度选择器 有兴趣可以搜索一下 https://www.love85g.com/?p=1879*/
/deep/ .el-table__header-wrapper .el-checkbox__input::after {
content: '全选';
position: absolute;
margin-left: 5px;
}
</style>
三、运行效果
打开 http://<ip地址>8080/about,我这里为http://192.168.3.10:8080/about
完成之后可以测试一下这些功能,应该是正常的。