Element Tag 标签
前言
这篇文章主要是记录一下,我在用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> <div slot="header"> <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> <div slot="header"> <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" @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" > <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"> <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>
作者:月__
链接:https://juejin.cn/post/7023659140253909029