vue 项目实战 递归
1 递归函数必须接受参数。(比如我要递归谁?)2 在递归函数的定义初始,应该有一个判断条件,当参数满足这个条件的时候,函数停止执行,并返回值。(指定退出条件,否则就会死循环)3 每次递归函数执行自己的时候,都需要把当前参数做某种修改,然后传入下一次递归。(每次循环在调用自己一次并传参)4当参数被累积修改到符合初始判断条件了,递归就停止了。(最后满足条件就退出)简单的说递归函数就是在函数体内调用n次
·
1 递归函数必须接受参数。(比如我要递归谁?)
2 在递归函数的定义初始,应该有一个判断条件,当参数满足这个条件的时候,函数停止执行,并返回值。(指定退出条件,否则就会死循环)
3 每次递归函数执行自己的时候,都需要把当前参数做某种修改,然后传入下一次递归。(每次循环在调用自己一次并传参)
4当参数被累积修改到符合初始判断条件了,递归就停止了。(最后满足条件就退出)
简单的说递归函数就是在函数体内调用n次本函数。
看一下项目的要求怎么实现
项目要求
左侧树结构为“一级组织机构 到 三级设备”树,列表初始化显示选中的设备下已有的作业文本选项,
根节点不可以点击,默认选中第一个一级组织机构,第一个一级组织机构展开,其他均折叠。
列表按照文本的创建时间逆序排列。
如下图
代码
<template>
<div class="box">
<!-- 项目 -->
<div class="treebox">
<el-tree
:data="treeData"
:props="defaultProps"
node-key="id"
highlight-current
ref="trees"
:expand-on-click-node="false"
@node-click="handleNodeClick"
:default-expanded-keys="expanded"
@node-expand="_openNode"
@node-collapse="_closeNode"
>
<span class="custom-tree-node flex flexs" slot-scope="{ node, data }">
<img :src=" !data.device && !data.channel ? imgorg : data.device ? imgdevice : imgchannel " />
<span>{{ node.label }}</span>
</span>
</el-tree>
</div>
<div class="tabbox">
<div class="flex flexb tabhead">
<div>
<Label :name="title" />
</div>
<div class="searchform flex flexe">
<el-form
:inline="true"
@submit.native.prevent
class="demo-form-inline flex flexc"
>
<el-form-item v-if="action != 3">
<el-button type="primary" size="small" @click="_add"
>+ 新增巡视作业文本项目</el-button
>
</el-form-item>
</el-form>
</div>
</div>
<div class="tabmain">
<div class="tabs">
<el-table
:data="list"
style="width: 100%"
:height="'100%'"
:highlight-current-row="true"
ref="multipleTable"
v-loading="loading"
>
<!-- 序号 -->
<el-table-column
:label="$t('theads.Numbers')"
align="center"
type="index"
width="50"
:index="indexMethod"
></el-table-column>
<el-table-column prop="partCode" label="部位名称" align="center">
</el-table-column>
<el-table-column
prop="secondType"
label="二级分类"
align="center"
>
</el-table-column>
<el-table-column prop="firstType" label="一级分类" align="center">
</el-table-column>
<el-table-column prop="orgName" label="组织机构" align="center">
</el-table-column>
<el-table-column prop="itemName" label="项目名称" align="center">
</el-table-column>
<!-- 操作 -->
<el-table-column
width="340"
:label="$t('theads.Operation')"
align="center"
>
<template slot-scope="scope">
<el-button
type="primary"
size="mini"
@click="_look(scope.row.id)"
>{{ $t("btns.see") }}</el-button
>
<!-- v-if="action != 3 && hasPerm('system:edit')" -->
<el-button
type="warning"
size="mini"
v-if="action != 3"
@click="_edit(scope.row.id)"
>{{ $t("btns.modify") }}</el-button
>
<!-- && hasPerm('system:delete') -->
<el-button
type="danger"
size="mini"
v-if="action != 3"
@click="_del(scope.row)"
>{{ $t("btns.delete") }}</el-button
>
</template>
</el-table-column>
</el-table>
<!-- style="position: absolute;bottom: 30px;left: 24px;" -->
<div
class="pagebox"
>
<el-pagination
@size-change="_changeSize"
@current-change="_changePage"
:page-sizes="[10, 20, 30, 40]"
:page-size="size"
:current-page="page"
layout="total, prev, pager, next, sizes"
:total="total"
></el-pagination>
</div>
</div>
</div>
</div>
<div
style="text-align: right;position: absolute;right: 15px;
bottom: 15px;"
>
<el-button type="primary" @click="_back">{{ $t("btns.back") }}</el-button>
</div>
<!--删除提示-->
<Del
:isdel="isdel"
:content="content"
@sure="_delApi"
@cancle="_closeDel"
/>
<!--新增修改-->
<Edit
:isdialog="isEdit"
:title="names"
:id="id"
:action="actions"
@close="_closeEdit"
@submit="_submit"
/>
<message
:success="success"
:info="message"
:show="ismess"
@close="_closemess"
/>
</div>
</template>
<script>
import Label from "@/components/Label";
import Del from "@/components/Del";
import Edit from "../common/ProjectShow";
import {
Tripletree, //三级树
getDataList //新增
// delEnyData,// 删除
} from "@/api/xunjian";
export default {
components: {
Label,
Del,
Edit
},
name: "mypage",
data() {
return {
title: "巡视作业文本项目", //this.$t("lables.DataI"),
names: "新增巡视作业文本项目", //this.$t("lables.NewDAT"),
list: [],
mess: null, // message 对象 重复提示 用于关于上一个
loading: false, // 列表loading
isdel: false, // 删除提示框显示、隐藏
content: "", // 删除提示语
isEdit: false, // 新增修改弹框显示隐藏
action: 0, // 新增、修改动作 1 新增 2修改
actions: 0,
total: 0,
page: 1,
size: 10,
id: "",
ismess: false,
message: "",
success: 1,
treeData: [], //树结构数据
expanded: [], //默认展开
defaultProps: {
children: "children",
label: "orgName",
id: "id",
orgPid: "orgPid"
},
orgId: "", //选中的组织机构id 接收传的id
workTextName: "", //接收传的 文本名称
// this.value = this.$route.query.id
orgName: "", //选中的组织机构名称
treelist: [],
harr: [],
imgorg: require("../../../../assets/images/icon_org.png"),
imgchannel: require("../../../../assets/images/icon_channel.png"),
imgdevice: require("../../../../assets/images/icon_device.png"),
rowObj: {}
};
},
created() {
//获取列表
this.action = this.$route.query.action;
this.loading = true;
this._getList(); //tab表格
this.getBaseOrg(); //获取树 **主要递归的逻辑在这里**
},
methods: {
// 获取列表
_getList() {
this.loading = false;
getDataList({
current: this.page,
size: this.size,
workTextName: JSON.parse(sessionStorage.getItem("workTextName"))
}).then(res => {
console.log(res, "tab数据列表");
this.loading = false;
if (res.code == "SUCCESS") {
this.list = res.data.records;
this.total = res.data.total;
}
});
},
// 序号
indexMethod(i) {
return i + (this.page == 1 ? 0 : (this.page - 1) * this.size) + 1;
},
// 删除接口
_delApi() {
this.isdel = false;
let params = {
id: this.rowObj.id
};
console.log(params, "/params项目");
delEnyData(params)
.then(res => {
if (res.code == "SUCCESS") {
this.ismess = true;
this.success = 1;
this.message = this.$t("phrase.DelSucc");
this._getList();
} else {
this.ismess = true;
this.success = 2;
this.message = res.message;
}
})
.catch(err => {
this.isdel = false;
this.ismess = true;
this.success = 3;
this.message = err.title;
});
},
// 取消删除
_closeDel() {
this.$refs.multipleTable.clearSelection();
this.isdel = false;
},
// 新增 一定判断一下有没有权限,这个权限是有没有选中三级
_add() {
console.log(this.orgId, this.WorkTextName, "//./././././");
let isfalse = this._checkPromise(this.orgId); // filter组织机构权限
if (!isfalse) {
//如果没有
this.ismess = true;
this.success = 3;
this.message = this.$t("phrase.noauthorg");
this.WorkTextName = sessionStorage.getItem("workTextName");
this.OrgId = sessionStorage.getItem("orgId");
console.log(this.orgId, this.WorkTextName, "//./././././");
return;
}
// 跳转编辑新增页面
this.actions = 1;
this.names = "新增巡视作业文本项目"; //this.$t("lables.NewDAT");
this.isEdit = true;
},
// 关闭新增
_closeEdit() {
this.actions = 0;
this.isEdit = false;
},
// 选择每页显示条数
_changeSize(val) {
this.size = val;
this.page = 1;
this.loading = true;
this._getList();
},
// 选择页码
_changePage(val) {
this.page = val;
// this.size = 10;
this.loading = true;
this._getList();
},
// 查看
_look(id) {
this.id = id;
this.actions = 3;
this.names = this.$t("lables.Look");
this.isEdit = true;
},
// 编辑
_edit(id) {
this.id = id;
this.actions = 2;
this.names = this.$t("lables.Modify");
this.isEdit = true;
},
// 提交回调
_submit(msg, isfalse) {
this.isEdit = isfalse;
this.ismess = true;
this.success =
msg == this.$t("phrase.Savedsucc")
? 1
: msg == this.$t("phrase.Savefailed")
? 2
: 3;
this.message = msg;
if (!isfalse) {
this.actions = -1;
this._getList();
}
},
// 关闭消息
_closemess() {
this.ismess = false;
},
// 删除
_del(row) {
this.rowObj = row;
this.isdel = true;
this.content = this.$t("phrase.suredelete");
},
// 返回
_back() {
this.$router.push("/Textbox");
},
// 拿到树结构 存默认显示的id和名字 给下一个页面 获取组织机构
getBaseOrg() {
//给树结构传参数 type:1 // 后端要的参数条件,这里是固定的如果有类似的可以不要参数,直接拿用
Tripletree( { type: 1 } ).then(res => {
console.log(res, "获取参数后的组织机构树");
if (res.code == "SUCCESS") { // 请求成功后执行的条件语句
this.treeData = res.data;
// 默认展开项
if (res.data.length) { // 返回的data有数据
let treelist = sessionStorage.getItem("Treelist"); // 取出来sessionStorage里的树结构
if (treelist) { // 如果有就不用执行递归条件, 在if 语句中直接去取存储的值
console.log("没有执行递归条件");
this.expanded = JSON.parse(treelist);
let myOrgId = sessionStorage.getItem("orgId");
this.orgId = myOrgId.replace(/\"/g, ""); // 把/替换成 ''。
this.orgName = sessionStorage.getItem("orgname");
} else { // 如果不存在 表结构 ,就进行循环递归
console.log("执行递归");
this._currData(this.treeData[0]); //循环递归,在递归中处理数据 part =1 后台要的
this.orgId = this.expanded[0]; // 执行递归,在进行查找子集的三级设备并选中
sessionStorage.setItem("orgId", this.orgId);
sessionStorage.setItem("Treelist", JSON.stringify(this.expanded));
}
this.$nextTick(function() {
this.$refs.trees.setCurrentKey(this.orgId); // 这里的 setCurrentKey是("需要被选中的节点的参数");
});
let harr = [];
this.harr = this._formData(this.treeData[0], harr); // 合并数据
let isfalse = this._checkPromise(this.orgId); // filter 判断是否有组织机构权限
console.log("执行其他");
if (isfalse) {
this.pages = 1;
this.size = 10;
this._getList();
}
}
}
});
},
// 树结构数据
handleNodeClick(val) {
if (val.id == 0 || val.part != 1 || this.expanded.length == 0) {
this.$nextTick(function() {
this.$refs.trees.setCurrentKey(this.orgId);
});
return;
}
// 缓存数据结构
let treelist = sessionStorage.getItem("treelist");
if (treelist) {
// 存在缓存
treelist = JSON.parse(treelist);
treelist.push(val.id);
let b = new Set(treelist);
treelist = [...b];
// sessionStorage.setItem("treelist", JSON.stringify(treelist));
} else {
let arr = [];
arr.push(val.id);
let b = new Set(arr);
arr = [...b];
// sessionStorage.setItem("treelist", arr);
}
// 选择机构
this.orgId = val.id;
this.orgName = val.orgName;
sessionStorage.setItem("orgid", this.orgId);
sessionStorage.setItem("orgname", this.orgName);
if (val.flag) {
console.log(111);
this.loading = true;
this.pages = 1;
this.size = 10;
this._getList();
} else {
console.log(222);
this.ismess = true;
this.isSucc = 3;
this.tipmsg = this.$t("phrase.noauthorg");
}
},
// 合并数据 也是递归存储合并
_formData(data, arr) {
if (data) {
arr.push(data);
if (data.children.length) {
data.children.forEach(item => {
this._formData(item, arr);
});
}
}
return arr;
},
// 判断是否有组织机构权限
_checkPromise(id) {
console.log(id, "这个id是递归得到的第一个三级id信息");
let isarr = this.harr.filter(item => item.id == id);
let isfalse = false;
if (isarr.length) {
if (isarr[0]["flag"]) {
isfalse = true;
} else {
isfalse = false;
}
}
return isfalse;
},
// 递归查询组织机构id
_currData(data) { // 参数是 this.treeData[0]) 这个数组
if (data) {
let IDD = sessionStorage.getItem("orgid"); // 取到sessionStorage 值
if (IDD == data.id) { // 如果能满足获取的id 和存储的id 一样
this._DataArr(data); // 这里也是递归函数 参数是part = 1
} else { / 其他条件 去找 children
if (data.children.length) {
data.children.forEach(item => {
if (this.expanded.length == 0) {
this._currData(item);
}
});
}
}
}
},
// 再次递归
_DataArr(data) {
// part 为1的时候是有三级设备的
if (data.part == 1) {
let id = data.id;
this.expanded.push(id);
this.orgName = data.orgName;
sessionStorage.setItem("orgname", data.orgName);
}
if (data.children.length) {
data.children.forEach(item => {
if (this.expanded.length == 0) {
this._DataArr(item);
}
});
}
},
// 节点被展开触发
_openNode(val) {
let arr = sessionStorage.getItem("treelist");
if (arr) {
arr = JSON.parse(arr);
arr.push(val.id);
let brr = new Set(arr);
let crr = [...brr];
sessionStorage.setItem("treelist", JSON.stringify(crr));
}
},
// 节点关闭触发
_closeNode(val) {
// 清除过往选中项 判断是否被选中 如果被选中 只删除子项
let arr = sessionStorage.getItem("treelist");
if (arr) {
arr = JSON.parse(arr);
let rarr = [];
let aid = this._currId(val, rarr);
let b = arr.filter(item => aid.indexOf(item) == -1);
let brr = new Set(b);
let crr = [...brr];
sessionStorage.setItem("treelist", JSON.stringify(crr));
}
},
// 递归id
_currId(data, arr) {
if (data) {
arr.push(data.id);
if (data.children.length) {
data.children.forEach(item => {
this._currId(item, arr);
});
}
}
return arr;
}
}
};
</script>
<style scoped lang="scss">
@import "../index.css";
.treebox {
width: 200px;
flex-grow: 0;
flex-shrink: 0;
height: 100%;
overflow-y: auto;
overflow-x: auto;
}
.custom-tree-node img {
width: 16px;
margin-right: 5px;
}
</style>
到这里就结束了。
为了更为方便的看效果
在给一个小例子1
let num = 0;
function recursion(params) {
if (params > 100) {
return
} else { // 先会走这里知道值为100的时候
num += params;
return recursion(params + 1)
}
}
recursion(0) // 参数0
console.log(num); // 5050
小例子2
// 升级版,递归树
假设一个模拟的数据
const data = [{
"area_id": 5,
"name": "广东省",
"parent_id": 0,
}, {
"area_id": 6,
"name": "广州市",
"parent_id": 5,
}, {
"area_id": 7,
"name": "深圳市",
"parent_id": 5,
}, {
"area_id": 4,
"name": "北京市",
"parent_id": 3,
}, {
"area_id": 3,
"name": "北京",
"parent_id": 0,
}, {
"area_id": 2,
"name": "测试子地区",
"parent_id": 1,
}, {
"area_id": 1,
"name": "测试地区",
"parent_id": 0,
}]
function toTreeData(data, pid) { // 参数 数组 - id
function tree(id) { // 接收的参数 第一级节点的父id,是null或者0
let arDat = []
data.filter(item => { // filter过滤data数组每一项
return item.parent_id === id; // 返回符合条件 每一项id 和 传入的id 数据相同的数据 ,这里返回的是一个数组 ,那么直接进行forEach循环
}).forEach(item => {
console.log(arDat .length); // 打印一下,看看长度,有没有值
if (!tree(item.area_id).length) { // 如果没有id的长度
arDat .push({ // push方法,存入名称和 id
area_id: item.area_id,
label: item.name,
})
} else { 如果有
arDat .push({ // push 名称,id,和二三级子项
area_id: item.area_id,
label: item.name,
children: tree(item.area_id)
})
}
})
return arDat // 把变量数组arDat return出去
}
return tree(pid) // 第一级节点的父id,是null或者0,视情况传入
}
console.log(toTreeData(data, 0));
更多推荐
已为社区贡献14条内容
所有评论(0)