vuetify tree diy

屏幕快照 2019-04-13 下午7.35.07.png

找不到合适的工作,弄完这个就去开出租车糊口了。

对于一个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>

修改组件回传的节点可以直接修改节点。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 时间还在慢慢迷失。对这个有点黑色幽默,神经质,敏感并且喜欢天气骤变的世界来讲,我可能有点失重。回想那个月份的某一...
    奇爱博士q阅读 178评论 0 0
  • 1、这个行业适不适合你,为什么 每个行业的发展都大同小异,没有适不适合,只有喜不喜欢,想不想做。 这个行业...
    Aileen___琳阅读 147评论 0 0
  • OMG! LPL的终极全华班,一直都是我的信仰与支持。 曾经的感动,我依然铭记在心。 但是在近日来OMG的各种举动...
    黄铜刀阅读 544评论 1 1