在树节点上填上按钮结合Vue和ElementUI
- span标签代表按钮
==expand-on-click-node==:是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。
==show-checkbox node-key==:展示复选框,以及复选框的id。
==:default-expanded-keys==="expanded"冒号代表是v-bind的缩写,是为了动态绑定数据,这个属性说明默认打开第一个树节点,因为绑定数据是一个变量,需要在data数据方法中写好
data() {
return {
category:{name:"",parentCid:0,catLevel:0,showStatus:1,sort:0},
dialogVisible:false,
menus: [],
expanded:[],
defaultProps: {
children: 'children',
label: 'name'
}
};
},
下面是树的点击按钮
<el-tree :data="menus" :props="defaultProps" :expand-on-click-node="false" show-checkbox node-key="catId" :default-expanded-keys="expanded">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<!--这里判断了一下层级小于等于2的时候显示添加,反之-->
<el-button
v-if="node.level<=2"
type="text"
size="mini"
@click="() => append(data)">
添加
</el-button>
<!--这里判断了没有子节点的话才显示删除-->
<el-button
v-if="node.childNodes.length==0"
type="text"
size="mini"
@click="() => remove(node, data)">
删除
</el-button>
</span>
</span>
</el-tree>
- 在methods的方法体中写上请求后台的方法。
这里的==this.$http==方法是封装请求后台的,详细见项目中的httpRequest.js文件。
methods: {
// 树节点的添加
append(data) {
console.log("append"+data)
this.dialogVisible = true;
//点击当前的id
this.category.parentCid = data.catId;
// 得到下一个的层级先乘1是防止是字符串
this.category.catLevel = data.catLevel*1 + 1;
},
//添加的方法
addCategory(){
console.log("提交的三级分类的数据是:"+this.category.name)
this.$http({
url: this.$http.adornUrl('/product/category/save'),
method: 'post',
data: this.$http.adornData(this.category, false)
}).then(({data}) => {
this.$message({
message: '恭喜你,这是一条成功消息',
type: 'success'
});
//关闭窗口
this.dialogVisible = false
//刷新出新的菜单
this.getMenus();
//设置需要默认展开的菜单
this.expanded=[this.category.parentCid];
})
},
// 树节点的删除
remove(node, data) {
console.log("remove"+node,data);
var ids = [data.catId];
this.$confirm(`是否删除[${data.name}]菜单?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/product/category/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({data}) => {
this.$message({
message: '恭喜你,这是一条成功消息',
type: 'success'
});
//刷新出新的菜单
this.getMenus();
//删除之后默认展开当前的菜单
this.expanded=[node.parent.data.catId];
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
},
- 先写删除的方法,删除方法在这写的是逻辑删除,并非真正的删除,结合Mybatisplus的使用
1).逻辑删除的配置首先在yml中配置:
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
# 主键自增
global-config:
db-config:
id-type: auto
logic-delete-value: 1 #代表删除(不显示)
logic-not-delete-value: 0 #没删除(显示)
2).配置好之后还要在实体类上加上
/**
* 是否显示[0-不显示,1显示]
*/
//逻辑删除的注解,这里发现,数据库的设置与配置文件的是相反的,就可以在注解后面加上value和delval两个来替换下。
@TableLogic(value = "1",delval = "0")
private Integer showStatus;
3)逻辑删除的语法
@Override
public void removeMenuByIds(List<Long> asList) {
//TODO 检查当前删除的菜单,是否被别的地方引用
baseMapper.deleteBatchIds(asList);
}
4)想看打印出来的日志,在yml文件中配置debug
logging:
level:
com.atdada.dadamall: debug
- 在做新增树节点的时候,需要一个弹窗
<!-- dialogVisible值为true是打开窗口,反之...:close-on-click-modal="false"鼠标点击其他地方不会关闭窗口,注意他是一个boolen值,要绑定加: 冒号 -->
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="30%" :close-on-click-modal="false">
<el-form :model="category">
<el-form-item label="分类名称">
<el-input v-model="category.name" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="addCategory">确 定</el-button>
</span>
</el-dialog>
5.再点击@click="() => append(data)按钮的时候会触发一个函数,在append中把:expand-on-click-node="true"就打开窗口了。
此函数是在methods: {}中的。并且在点击的时候要拿到当前的id和要添加这一级的层级+1.也要在data(){}中把变量写好
category:{name:"",parentCid:0,catLevel:0,showStatus:1,sort:0},
// 树节点的添加
append(data) {
console.log("append"+data)
this.dialogVisible = true;
//点击当前的id
this.category.parentCid = data.catId;
// 得到下一个的层级先乘1是防止是字符串
this.category.catLevel = data.catLevel*1 + 1;
},
6.在弹出窗口之后点击确定绑定@click="addCategory"函数。
//添加的方法
addCategory(){
console.log("提交的三级分类的数据是:"+this.category.name)
this.$http({
url: this.$http.adornUrl('/product/category/save'),
method: 'post',
data: this.$http.adornData(this.category, false)
}).then(({data}) => {
this.$message({
message: '恭喜你,这是一条成功消息',
type: 'success'
});
//关闭窗口
this.dialogVisible = false
//刷新出新的菜单
this.getMenus();
//设置需要默认展开的菜单
this.expanded=[this.category.parentCid];
})
},
7.后台的保存方法,已经有逆向工程自动生成
/**
* 保存
*/
@RequestMapping("/save")
public R save(@RequestBody CategoryEntity category){
categoryService.save(category);
return R.ok();
}
8.再做修改的时候,可以把添加的按钮复制下来,哪些节点可能都需要修改,所以就不用判断了。紧接着就需要写edit的函数了;
<el-button
type="text"
size="mini"
@click="() => edit(data)">
修改
</el-button>
9.因为修改的时候是根据id来修改的,所以也要把catId写到
category:{name:"",parentCid:0,catLevel:0,showStatus:1,sort:0,catId:null},
10.还有再更改的时候,因为添加和编辑用的都是同一个对话框,所以在添加的时候给某个值赋值为add,更改就赋值为edit,
也要在,
11.判断是更改还是新增,就应该在修改和新增的弹窗事件的时候分别给这个标识位赋值,然后去判断当前的操作是更改还是添加
this.dialogType = "edit";//放到更改的弹窗位置
this.dialogType = "add";
submitData(){
if (this.dialogType == "add"){
this.addCategory();
}
if (this.dialogType == "edit"){
this.editCategory();
}
},
同时想修改上面的标题的话需要把title加一个双向绑定事件,在from表单中写上:title="title",然后再data(){}中加入这个变量,最后也是在更改和新增的弹窗方法上写上this.title="添加/修改",下面是修改的弹窗:。
edit(data){
this.title="修改";
this.dialogType = "edit";
console.log("要更改的数据"+data)
this.dialogVisible = true ;//打开窗口
this.$http({
url:this.$http.adornUrl(`/product/category/info/${data.catId}`),
method:"get",
}).then(({data})=>{
console.log("要回显的数据:"+data)
this.category.name = data.data.name;
this.category.catId = data.data.catId;
this.category.icon = data.data.icon;
this.category.productUnit = data.data.productUnit;
this.category.parentCid = data.data.parentCid;
});
//这样的回显是不合理的,容易出现脏读的现象,所以还是要每次请求后台来查询出最新的数据
// this.category.name = data.name;
// this.category.catId = data.catId;
},
12.数据回显之后就可以做更改操作了
editCategory(){
//因为有的值不需要传,所以可以把需要传递的值放到{}里,如果不这样就把所有数据回显出来
var {catId,name,icon,productUnit} = this.category;
var data1 = {catId:catId,name: name,icon: icon,productUnit: productUnit};
var data = {catId,name,icon,productUnit};//key value一样的话 也可以这样写
this.$http({
url:this.$http.adornUrl("/product/category/update"),
method:"post",
data:this.$http.adornData(data,false)
}).then(({data})=>{
this.$message({
message: '恭喜你,这是一条成功消息',
type: 'success'
});
//关闭窗口
this.dialogVisible = false
//刷新出新的菜单
this.getMenus();
//设置需要默认展开的菜单
this.expanded=[this.category.parentCid];
});
},
13.此时会发现修改之后,再次点击添加发现添加窗口还是有值的这是因为没有把字段置空
14.draggable它是tree的属性,写上它可以拖拽节点的位置。
<el-tree :data="menus" :props="defaultProps" :expand-on-click-node="false" show-checkbox node-key="catId" :default-expanded-keys="expanded" draggable></<el-tree>
15.判断哪个层级是能拖拽的,那个层级是不能拖拽的,这里默认最多3层级
//判断是否能够拖拽
allowDrop(draggingNode, dropNode, type) {
//1.被拖动的当前节点以及所在的父节点总层数不能大于3
//1)被拖动的当前节点的总层数
console.log("拖拽方法:",draggingNode, dropNode, type)
var level = this.countNodeLevel(draggingNode.data);
//当前正在拖动的节点+父节点所在的深度不大于3即可
let deep = (this.maxLevel - draggingNode.data.catLevel)+1;
console.log("深度:",deep)
//拖到节点里面是相加关系
if (type == "inner"){
return (deep + dropNode.level) <= 3;
}else{
return (deep + dropNode.parent.level) <= 3;
}
},
countNodeLevel(node){//当前节点
//找到所有子节点,求出最大深度
//先判断当前节点是否有子节点
if(node.children !=null && node.children.length >0){
//进来的话说明有子节点,开始遍历所有的子节点
for(let i = 0;i<node.children.length;i++){
//如果当前层级大于设置的0的时候就给他交换值,相当于自己调用自己的一个递归了
if(node.children[i].catLevel > this.maxLevel){
this.maxLevel = node.children[i].catLevel;
}
this.countNodeLevel(node.children[i]);
}
}
},