前言
这篇文章主要是记录一下,我在用tag标签的时候遇到的一些问题,因为是后端管理系统中的标签管理页面,所以只有基本的增删改查功能。。。,好了,废话不多说了,直接开始
Tag标签
因为需要进行标签的更改,所以直接使用Tag标签里面的动态编辑标签,直接把代码拿过来用
<el-tag
:key="tag"
v-for="tag in dynamicTags"
closable
:disable-transitions="false"
@close="handleClose(tag)">
{{tag}}
</el-tag>
<el-input
class="input-new-tag"
v-if="inputVisible"
v-model="inputValue"
ref="saveTagInput"
size="small"
@keyup.enter.native="handleInputConfirm"
@blur="handleInputConfirm"
>
</el-input>
<el-button v-else class="button-new-tag" size="small" @click="showInput">+ New Tag</el-button>
<style>
.el-tag + .el-tag {
margin-left: 10px;
}
.button-new-tag {
margin-left: 10px;
height: 32px;
line-height: 30px;
padding-top: 0;
padding-bottom: 0;
}
.input-new-tag {
width: 90px;
margin-left: 10px;
vertical-align: bottom;
}
</style>
<script>
export default {
data() {
return {
dynamicTags: ["标签一", "标签二", "标签三"],
inputVisible: false,
inputValue: "",
};
},
methods: {
handleClose(tag) {
this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
},
showInput() {
this.inputVisible = true;
this.$nextTick((_) => {
this.$refs.saveTagInput.$refs.input.focus();
});
},
handleInputConfirm() {
let inputValue = this.inputValue;
if (inputValue) {
this.dynamicTags.push(inputValue);
}
this.inputVisible = false;
this.inputValue = "";
},
},
};
</script>
这样就直接拥有了一个基本Tag标签页面
调取数据获取接口
调取自己封装好的数据接口,拿取后端返回的数据。。。。,在我看到到后端返回我的数据格式,我就知道这个页面之后的增删改查功能将会不是太好实现。。。,数据长成这样。。。。
看到数据的不断嵌套,我就感觉自己头已经有点大了。。。,啥也不说了,直接调取接口拿到数据:
//获取数据
getdata() {
getwarninglabel({
pageNum: this.pageNum,
pageSize: this.pageSize,
}).then((res) => {
console.log(res);
this.total = res.data.count; //分页
this.tagtitle = res.data.results; //总数据
});
},
进行数据获取,而要获取标签的数据keywords,需要进行两层的嵌套循环,第一层遍历,通过item.keywords拿到每一个keywords的数据,之后再遍历item.keywords,来循环keywords里面的数据,代码如下:
<div v-for="(item, ki) in tagtitle" :key="ki" class="text item">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span> {{ item.label_name }}</span> //标签标题
</div>
<div>
<el-tag
:key="indext"
//遍历循环item.keywords,拿到标签数据
v-for="(tag, indext) in item.keywords"
:disable-transitions="false"
closable
@close="handleClose(tag)"
>
{{ tag }}
</el-tag>
此时已经完成了页面数据的基本渲染,之后开始添加其他的功能
按钮添加
按照需求,需要在点击编辑按钮时,tag标签后面才会出现删除图标,同时编辑按钮变成保存提交按钮,因而需要对删除图标是否出现以及编辑/保存按钮的切换进行处理
- 添加编辑/保存以及模块删除按钮
<el-button
@click="hangdelDelete(item.id)"
style="float: right; padding: 3px 0; color: red"
type="text"
>删除</el-button
>
<el-button
v-show="activeIndex != ki"
@click="handelUpdata(item.id, ki)"
style="float: right; padding: 3px 0"
type="text"
>编辑</el-button
>
<el-button
v-show="activeIndex === ki"
@click="handelUpdatat(item.id, ki)"
style="float: right; padding: 3px 0"
type="text"
>保存</el-button
>
2.控制tag标签的删除按钮是否出现
我是直接删除了tag标签自带的删除图标,也就是closable,之后自己在后面添加了一个icon图标,通过v-show来判断是否显示
<el-tag
:key="indext"
v-for="(tag, indext) in item.keywords"
:disable-transitions="false"
>
{{ tag }}
<i
v-show="activeIndex === ki"
class="el-icon-circle-close"
@click="handleClose(tag,indext)"
></i>
</el-tag>
结果如下:
遇到问题
此时已经写好了编辑/保存,删除按钮以及tag标签的删除图标,而且对它们是否显示也进行了判断,但是此时就遇到了第一个问题,也就是在点击编辑按钮时,所有的tag标签后面都出现了icon图标,同时所有的编辑按钮也变成了保存,问题展示如下:
此时,需要处理的是,如何实现点击哪一个标签模块,哪一个便签模块进行改变,而不是全部发生改变,解决办法如下:
一、定义一个字段,并给它一个初始化的值,如-1,因为index排序从0开始,所以不能赋值为0
activeIndex: -1,
二、将v-show是否显示的true/false判断,改成通过点击时将获取的index值赋值给activeIndex之后和index的值来进行判断,相等即为true,进行展示,不相等极为false,不进行展示
代码如下:
<div v-for="(item, ki) in tagtitle" :key="ki" class="text item">
<el-button
@click="handelUpdata(item.id, ki)" //拿取渲染排序的值
style="float: right; padding: 3px 0"
type="text"
>编辑</el-button
>
//方法
handelUpdata(id, ki) { //ki index排序
console.log(id);
console.log(ki);
this.activeIndex = ki; //将排序值赋值给activeIndex
}
//使用
<i
v-show="activeIndex === ki" //即可进行是否显示判断
class="el-icon-circle-close"
@click="handleClose(tag,indext)"
></i>
实现功能如下:
删除功能
模块的删除功能比较简单,直接通过后端给的模块id,通过id传递给后端即可,这里主要解决的是,tag标签的删除,这些标签没有id存在,打开 Tag标签,查看一下删除功能的实现:
直接使用这个方法,但是会突然发现,后端返回的数据格式和需要的数据格式不同:
Element UI数据格式:
后端返回的数据格式:
也就是说如果使用Element UI自带的方法,那么就需要使用和它一样的数据格式,也就是相当于results[0].keywords里面的数据,如下:
通过这种比较,很容易想到通过模块的index值,在点击时,将index的值放到results[].keywords中,即可拿到每一个keywords中的数据,之后放到新定义的数组中,即可使用tag标签自带的方法:
this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
实现代码如下:
一、定义一个新数组
deleIndex: [],
二、定义一个新的字段来获取模块的index值
numberid: "",
三、拿取index值并赋值给 numberid
//编辑
handelUpdata(id, ki) { //ki index排序
this.activeIndex = ki;
this.numberid = ki; //获取index值
}
四、将numberid放入到results[].keywords,即可拿取到keywords中的数据,并放到deleIndex中
//获取数据
getdata() {
getwarninglabel({
pageNum: this.pageNum,
pageSize: this.pageSize,
}).then((res) => {
console.log(res);
this.total = res.data.count;
this.tagtitle = res.data.results;
console.log(res.data.results[0].keywords);
console.log(res.data.results[this.numberid].keywords);
console.log(res.data.results[this.numberid].label_name);
this.deleIndex = res.data.results[this.numberid].keywords; //赋值
this.deletitle = res.data.results[this.numberid].label_name;
});
},
五、使用tag标签自带的删除方法
//删除方法
handleClose(tag, indext) {
console.log(indext)
this.deleIndex.splice(this.deleIndex.indexOf(tag), 1);
},
标签删除功能实现:
新增功能
新增功能实现也比较简单,唯一的麻烦就是如何将输入的字符串格式的数据转化成数组,同时将新增的标签数据与其他没有改变的数据进行合并,也就是将两个数组进行合并:、
1、新增数据格式:
将name的值取出来,放到一个数组中,即可生成后端需要的数据格式,代码如下:
//新建数组,获取新增的数据
mileEdit:[]
//进行数据处理
this.mileEdit = this.ruleForm.options;
console.log(this.mileEdit);
//定义一个新数组来存放处理后的数据
const eddvalue = this.mileEdit.map((value) => {
return value.name;
});
2、处理后结果如下:
3、将新增的数据与没有改变的数据一起给后端传递过去,即新增数组与原来的数组进行合并,通过concat来实现数组的合并,代码如下:
titleEdit(id,{
label_name: this.deletitle,
keywords: eddvalue.concat(this.deleIndex) ,//数组合并
}).then((res) => {
console.log(res);
this.$message({
message: "新增成功!",
type: "success",
});
即完成了标签的增加功能
完整代码:
<template>
<div>
<el-button type="primary" @click="Addmunu()">新增主类</el-button>
<div v-for="(item, ki) in tagtitle" :key="ki" class="text item">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span> {{ item.label_name }}</span>
<el-button
@click="hangdelDelete(item.id)"
style="float: right; padding: 3px 0; color: red"
type="text"
>删除</el-button
>
<el-button
v-show="activeIndex != ki"
@click="handelUpdata(item.id, ki)"
style="float: right; padding: 3px 0"
type="text"
>编辑</el-button
>
<el-button
v-show="activeIndex === ki"
@click="handelUpdatat(item.id, ki)"
style="float: right; padding: 3px 0"
type="text"
>保存</el-button
>
</div>
<div>
<el-tag
:key="indext"
v-for="(tag, indext) in item.keywords"
:disable-transitions="false"
>
{{ tag }}
<i
v-show="activeIndex === ki"
class="el-icon-circle-close"
@click="handleClose(tag,indext)"
></i>
</el-tag>
<span v-show="activeIndex === ki">
<el-form :inline="true" :model="ruleForm" ref="ruleForm">
<el-form-item
v-for="(item, index) in ruleForm.options"
:key="index"
>
<el-row>
<el-col :span="4">
<el-input
clearable
style="width: 200px"
v-model="item.name"
placeholder="请输入标签名"
></el-input>
</el-col>
<!-- <el-col :span="8">
<el-button type="danger" plain @click="deleteOption(index)"
>删除选项</el-button
>
</el-col> -->
</el-row>
</el-form-item>
<el-button type="primary" plain @click="addOption(index)"
>新增标签</el-button
>
</el-form>
</span>
</div>
</el-card>
</div>
<!-- 分页 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="pageNum"
:limit.sync="pageSize"
@pagination="getdata"
/>
<!-- 新增主类弹窗 -->
<el-dialog title="添加标签" :visible.sync="dialogruleForm4Visible">
<el-form
:model="ruleForm4"
ref="ruleForm4"
label-width="100px"
class="demo-ruleForm"
>
<el-form-item label="标签主类" prop="title">
<el-input v-model="ruleForm4.title"></el-input>
</el-form-item>
<template>
<el-form-item
:label="'标签' + (index + 1)"
v-for="(item, index) in ruleForm4.options"
:key="index"
>
<el-row>
<el-col :span="16">
<el-input
v-model="item.name"
placeholder="请输入标签名"
style="width: 90%"
></el-input>
</el-col>
<el-col :span="8"> </el-col>
</el-row>
</el-form-item>
<el-button
type="primary"
style="float: left"
plain
@click="addppOption"
>新增标签</el-button
>
</template>
<el-form-item> </el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogruleForm4Visible = false">取 消</el-button>
<el-button type="primary" @click="checkAddppQuestion()"
>确 定</el-button
>
</div>
</el-dialog>
</div>
</template>
<script>
import {
getwarninglabel,
hangdleadd,
deletedata,titleEdit
} from "@/api/label/riskwarning";
export default {
data() {
return {
// 分页
total: "",
pageNum: 1,
pageSize: 10,
//题目排序
numberid: "",
deleteadd:"",
isShow:false,
deleIndex: [],
deletitle: "",
activeIndex: -1,
tagtitle: [], //标签题目
milepost: [],//新增数据处理
mileEdit: [],//修改数据处理
tagclosable: false,
dynamicTags: ["标签一", "标签二", "标签三"],
inputVisible: false,
inputValue: "",
//添加标签
ruleForm: {
options: [
{
name: "", //标签
},
],
},
//添加主类
ruleForm4: {
title: "", //主类
options: [
{
name: "", //标签
},
],
},
dialogruleForm4Visible: false,
};
},
methods: {
//添加添加标签
addOption(index) {
this.ruleForm.options.push({
name: "",
});
this.deleteadd = index
console.log(888777)
},
getdelete(){
console.log(99999)
this.ruleForm.options.splice(this.deleteadd, 1);
},
//添加添加标签
addppOption() {
this.ruleForm4.options.push({
name: "",
});
},
//新增主类
Addmunu() {
this.dialogruleForm4Visible = true;
},
//新增
checkAddppQuestion() {
console.log(this.ruleForm4.options);
this.milepost = this.ruleForm4.options;
console.log(this.milepost);
const checker = this.milepost.map((value) => {
return value.name;
});
console.log(checker);
hangdleadd({
label_name: this.ruleForm4.title,
keywords: checker,
}).then((res) => {
console.log(res);
this.$message({
message: "新增成功!",
type: "success",
});
this.ruleForm4 = {
id: 0,
title: "",
options: [""],
};
this.getdata();
});
this.dialogruleForm4Visible = false;
},
//标签新增
//获取数据
getdata() {
getwarninglabel({
pageNum: this.pageNum,
pageSize: this.pageSize,
}).then((res) => {
console.log(res);
this.total = res.data.count;
this.tagtitle = res.data.results;
console.log(res.data.results[0].keywords);
console.log(this.numberid);
console.log(res.data.results[this.numberid].keywords);
console.log(res.data.results[this.numberid].label_name);
this.deleIndex = res.data.results[this.numberid].keywords;
this.deletitle = res.data.results[this.numberid].label_name;
console.log(this.deleIndex)
});
},
//编辑
handelUpdata(id, ki) {
//ki index排序
console.log(id);
console.log(ki);
this.activeIndex = ki;
this.numberid = ki;
this.ruleForm = {
id: 0,
options: [""],
};
this.getdata();
// this.addOption();
this.getdelete();
},
//保存
handelUpdatat(id, ki) {
console.log(id);
console.log(ki);
this.activeIndex = -1;
console.log(this.ruleForm.options);
this.mileEdit = this.ruleForm.options;
console.log(this.mileEdit);
const eddvalue = this.mileEdit.map((value) => {
return value.name;
});
console.log(eddvalue)
titleEdit(id,{
label_name: this.deletitle,
keywords: eddvalue.concat(this.deleIndex) ,
}).then((res) => {
console.log(res);
this.$message({
message: "新增成功!",
type: "success",
});
this.ruleForm = {
options: [""],
};
this.getdata();
});
this.getdata();
},
//删除主模块
hangdelDelete(id) {
this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
center: true,
})
.then(() => {
deletedata(id).then((res) => {
console.log(res);
this.$message({
type: "success",
message: "删除成功!",
});
this.getdata();
});
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
},
//删除方法
handleClose(tag, indext) {
console.log(indext)
// this.deleIndex.splice(indext, 1);
this.deleIndex.splice(this.deleIndex.indexOf(tag), 1);
},
},
mounted() {
console.log(88888);
this.getdata();
},
};
</script>
<style scoped>
/* 卡片 */
.item {
margin-bottom: 18px;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both;
}
.box-card {
width: 100%;
}
/* 标签 */
.el-tag + .el-tag {
margin-left: 10px;
}
.button-new-tag {
margin-left: 10px;
height: 32px;
line-height: 30px;
padding-top: 0;
padding-bottom: 0;
}
.input-new-tag {
width: 90px;
margin-left: 10px;
vertical-align: bottom;
}
</style>