找不到合适的工作,弄完这个就去开出租车糊口了。
对于一个40多半路出家,学了7、8年的伪码农,接触vue一个月了,感觉进度很慢,把代码记下来备忘,有很多不足的地方等有时间再优化下。
基础差,花了大半天google了关于vuetify treevie的例子,在跟服务取数据添充时总是出错,youtube上看了毛子的例子,还是不会用,没办法回到vue,油管上看了一个排在前边的,花了不到20分钟,样式是看懂了,没有添加删除节点的代码,第二天花了一天时间才把这个组件弄完,包括跟后端交互。
treeview.vue
<template>
<ul>
<li v-ripple>
<v-layout align-center justify-start row fill-height>
<v-icon left>{{ icon }}</v-icon>
<label @click="toggle">{{ node.name }}</label>
<v-spacer></v-spacer>
<v-btn v-show="!hasChildren&&!noRoot" @click="deleteClicked">删除</v-btn>
<v-btn v-show="!noRoot" @click="editClicked">编辑</v-btn>
<v-btn @click="appendClicked">添加下级</v-btn>
</v-layout>
</li>
<ul v-if="open">
<tree-view
v-for="(child,index) in node.children"
:key="index"
:node="child"
:depth="depth + 1"
@onDeleteClick="(node)=>$emit('onDeleteClick',node)"
@onEditClick="(node)=>$emit('onEditClick',node)"
@onAppendClick="(node)=>$emit('onAppendClick',node)"
></tree-view>
</ul>
</ul>
</template>
<script>
export default {
name: "tree-view",
data() {
return {
open: true
};
},
props: {
node: Object,
depth: {
type: Number,
default: 0
}
},
computed: {
// 判断是否根结点,不显示 删除 编辑 按钮
noRoot(){
return this.node.name==='root'
},
// 是否有子结点 显示不同的图标
hasChildren() {
return this.node.children && this.node.children.length;
},
// 图标
icon() {
return this.hasChildren
? this.open
? "arrow_drop_down"
: "arrow_right"
: "note";
}
},
methods: {
// 三个操作结点的事件
deleteClicked() {
if (!this.hasChildren) {
this.$emit("onDeleteClick", this.node);
}
},
editClicked(){
this.$emit("onEditClick", this.node);
},
appendClicked(){
this.open = true
this.$emit("onAppendClick", this.node);
},
// 打开关闭节点
toggle() {
if (this.hasChildren) {
this.open = !this.open;
return;
}
},
}
};
</script>
<style>
ui,
li {
list-style: none;
}
</style>
调用
<template>
<div>
<v-dialog v-model="dialog" max-width="500px">
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container grid-list-md>
<v-layout wrap>
<v-flex xs12 sm12 md12>
<v-text-field label="上级分类" v-model="editedItem.parent.name" disabled></v-text-field>
</v-flex>
<v-flex xs12 sm12 md12>
<v-text-field v-model="editedItem.name" label="名称"></v-text-field>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" flat @click="close">Cancel</v-btn>
<v-btn color="blue darken-1" flat @click="save">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<tree-view
:node="tree"
@onDeleteClick="nodeDeleteClick"
@onAppendClick="nodeAppendClick"
@onEditClick="nodeEditClick"
></tree-view>
</div>
</template>
<script>
import TreeView from "../../components/TreeView";
import instance from "../../axios";
export default {
data() {
return {
tree: {},
dialog: false,
editfield: false,
formTitle: "添加分类",
targetItem: {},
editedItem: {
id: 0,
name: "",
p_id: 0,
children: [],
parent: { name: "" }
},
defaultItem: {
id: 0,
name: "",
p_id: 0,
children: [],
parent: { name: "" }
}
};
},
created() {
this.getmessagetype();
},
methods: {
// 删除操作
nodeDeleteClick(node) {
if (confirm("确认要删除此条记录吗?")) {
instance({
method: "delete",
url: "/api/v1/admin/messagetype/" + node.id
}).then(response => {
if (response.data.code > 0) {
this.changetree(node, this.tree, null, "delete");
} else {
alert(response.data.msg);
}
});
}
},
// 打开编辑对话框
nodeEditClick(node) {
this.editfield = true;
this.targetItem = node;
this.editedItem = { id: node.id, name: node.name, p_id: node.p_id };
this.editedItem.parent = this.getparent(node, this.tree);
this.dialog = true;
},
// 打开添加对话框
nodeAppendClick(node) {
this.editfield = false;
this.targetItem = node;
this.editedItem.parent = node;
this.dialog = true;
},
// 后端取得树结构数据
getmessagetype() {
instance({
method: "get",
url: "/api/v1/admin/messagetype"
}).then(response => {
if (response.data.code > 0) {
this.tree = response.data.data;
} else {
alert(response.data.msg);
}
});
},
// 关闭对话框
close() {
Object.assign(this.editedItem, this.defaultItem);
this.dialog = false;
},
// 保存
save() {
if (!this.editfield) {
// 添加
let data = {
name: this.editedItem.name,
pid: this.editedItem.parent.id
};
instance({
method: "post",
url: "/api/v1/admin/messagetype",
data
}).then(response => {
if (response.data.code == 200) {
this.changetree(
this.targetItem,
this.tree,
{
id: response.data.data.id,
name: response.data.data.name,
p_id: response.data.data.p_id
},
"append"
);
} else {
alert(response.data.msg);
}
});
} else {
// 编辑
let data = {
id: this.editedItem.id,
name: this.editedItem.name,
pid: this.editedItem.parent.id
};
instance({
method: "put",
url: "/api/v1/admin/messagetype",
data
}).then(response => {
if (response.data.code == 200) {
this.targetItem.name = response.data.data.name;
} else {
alert(response.data.msg);
}
});
}
this.close();
},
// 从树结构中查找结定结点的父结点
getparent(node, tree) {
if (tree.children) {
for (let i = 0; i < tree.children.length; i++) {
if (tree.children[i].id == node.id) {
return tree;
}
}
for (let i = 0; i < tree.children.length; i++) {
let p = this.getparent(node, tree.children[i]);
if (p != null) {
return p;
}
}
}
return null;
},
// 添加 或 删除 结点
changetree(node, tree, newnode, methed) {
// 判断根结点匹配
if (node.id == tree.id) {
if (methed == "append") {
if (!tree.children) {
this.$set(tree, "children", []);
}
tree.children.push({
id: newnode.id,
name: newnode.name,
p_id: node.id
});
return true;
}
}
// 判断子节点匹配
if (tree.children && tree.children.length) {
let found = false;
for (let i = 0; i < tree.children.length; i++) {
if (node.id !== tree.children[i].id) {
continue;
}
found = true;
if (methed == "append") {
if (!tree.children[i].children) {
this.$set(tree.children[i], "children", []);
}
tree.children[i].children.push({
id: newnode.id,
name: newnode.name,
p_id: node.id
});
return found;
} else if (methed == "delete") {
tree.children.splice(i, 1);
return found;
} else {
return found;
}
}
if (!found) {
// 递归匹配
for (let i = 0; i < tree.children.length; i++) {
if (!tree.children[i].children) {
continue;
}
found = this.changetree(node, tree.children[i], newnode, methed);
if (found) {
return found;
}
}
}
return found;
}
}
},
components: {
TreeView
}
};
</script>
修改组件回传的节点可以直接修改节点。