vue中将tree组件水平放置

效果图
在这里插入图片描述
在这里插入图片描述
可以对子节点进行编辑操作。
具体使用组件
components/RightTree/index.vue

<template>
  <div class="main-info">
    <div ref="column" class="column-header">
      <div
        :style="styleWidth"
        v-for="i in columnData"
        :key="i">{{ i }}</div>
    </div>
    <div
      class="background-info"
      :style="{
        width: `${width}px`,
        height: `${height}px`
      }">
      <div
        class="background-border"
        :style="{
          width: `${width}px`,
          height: `${height}px`
        }"
      >
        <div
          :style="styleWidth"
          v-for="i in bgGridNum"
          :key="i"></div>
      </div>
    </div>
    <div ref="main" class="tree-contain" :style="{ top: `-${height}px` }">
      <Tree
        v-for="(item, index) in data"
        :key="item.id"
        :index="index"
        :data="item"
        :isTree="true"
        ></Tree>
    </div>
  </div>
</template>

<script>
import Tree from '@/components/RightTree/Tree.vue'
export default {
  name: "index",
  components: {
    Tree
  },
  props: {
    data: {
      type: Array
    },
    columnData: {
      type: Array
    },
    columnWidth: {
      type: Number,
      default: 200
    },
    columnHeight: {
      type: Number,
      default: 53
    },
  },
  data() {
    return {
      width: 0,
      height: 0,
    };
  },
  created() {
    this.$on("edit-value", (data) => {
      this.$emit("edit-data", data);
    })
  },
  computed: {
    styleWidth() {
      return {
        width: `${this.columnWidth}px`
      }
    },
    bgGridNum() {
      return this.height / this.columnHeight * this.columnData.length
    },
  },
  watch: {
    data: {
      handler(nVal) {
        this.$nextTick(() => {
          this.height = this.$refs.main.offsetHeight;
          this.width = this.$refs.column.offsetWidth;
        })
      },
      deep: true,
    }
  },
  provide() {
    return {
      styleWidth: this.styleWidth,
      columnHeight: this.columnHeight,
    }
  }
};
</script>

<style lang="less" scoped>
  .main-info {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    overflow-x: auto;
  }
  .background-info {
    // position: absolute;
    // top: 161px;
    // left: 650px;
    position: relative;
    top: 0;
    left: 0;
    z-index: 0;
    .background-border {
      display: grid;
      // grid-template-columns: repeat(auto-fill, 200px);
      grid-template-columns: repeat(8, 1fr);
      div {
        display: flex;
        align-items: center;
        justify-content: center;
        box-sizing: border-box;
        padding: 10px 20px;
        border-right: 1px solid #e1e6f0;
        border-bottom: 1px solid #e1e6f0;
        &:nth-child(8n + 1) {
          border-left: 1px solid #e1e6f0;
        }
      }
    }
  }
  .tree-contain {
    position: relative;
    left: 0;
    z-index: 33;
  }
  .column-header {
    display: grid;
    // grid-template-columns: repeat(auto-fill, 200px);
    grid-template-columns: repeat(8, 1fr);
    // display: flex;
    // align-items: center;
    div {
      background-color: #f5f7fa;
      user-select: none;
      display: flex;
      align-items: center;
      justify-content: center;
      box-sizing: border-box;
      padding: 18px 20px;
      border-right: 1px solid #e1e6f0;
      border-bottom: 1px solid #e1e6f0;
      border-top: 1px solid #e1e6f0;
      &:first-child {
        border-left: 1px solid #e1e6f0;
      }
    }
  }
</style>

/components/RightTree/tree.vue

<template>
  <div class="tree">
    <div class="tree-item-name"
      :style="{
        minHeight: `${columnHeight}px`,
        marginLeft: getMarginLeft(data)
      }">
      <span>{{ data.template }}</span>
      <div
        :style="styleWidth"
        class="input-content"
        @dblclick="(e) => {
          editTree(e, data)
        }">
        <template v-if="data.weight_edit">
          <YsInput
            size="small"
            icon="ios-create-outline"
            v-model="inputValue"
            @on-blur="editValue(data)"
            @on-change="handleQuery($event)"
            @on-click="handleQuery($event)" 
          />
        </template>
        <template v-else>
          <span>{{ data.weight}}</span>
        </template>
      </div>
    </div>
    <div
      class="tree-children"
      v-if="data.children && data.children.length">
      <Tree
        v-for="item in data.children"
        :key="item.id"
        :data="item"
        :index="index"
        :isTree="isTree"
        ></Tree>
    </div>
  </div>
</template>

<script>
export default {
  name: "Tree",
  props: {
    data: {
      type: Object
    },
    index: Number,
    isTree: {
      type: Boolean
    }
  },
  data() {
    return {
      inputValue: "",
      tree: null,
      }
    }
  },
  inject: ["styleWidth", "columnHeight"],
  created() {
    let parent = this.$parent;
    if (parent.isTree) {
      this.tree = parent.tree;
    } else {
      this.tree = parent;
    }
  },
  methods: {
    // 节点编辑框失焦时触发
    editValue(data) {
      this.$set(data, 'item_weight', this.inputValue);
      this.setStates(data);
      this.tree.$emit("edit-value", data);
    },
    // 双击节点执行的事件
    editTree(ev, data) {
      ev.stopPropagation();
      this.inputValue = data.item_weight;
      this.setStates(data);
      //实现双击后输入框自动聚焦
      this.$nextTick(() => {
        ev.currentTarget.getElementsByTagName("input")[0].focus();
      });
    },
    handleQuery(ev) {
      this.inputValue = ev.target.value;
    },
    setStates(data) {
      if (data.weight_edit) {
        this.$set(data, "weight_edit", false);
      } else {
        this.$set(data, "weight_edit", true);
      }
    },
    getMarginLeft(data) {
      let padding = 0;
      if (this.styleWidth) {
        padding = this.styleWidth.width.split("px")[0];
      }
      if (data.layer !== data.type) {
        if (data.type === 4) {
          if (data.layer === 2) {
            return `${4 * padding}px`;
          } else if (data.layer === 3) {
            return `${2 * padding}px`;
          }
        } else if (data.type === 3) {
          if (data.layer === 1) {
            return `${4 * padding}px`;
          } else if (data.layer === 2) {
            return `${2 * padding}px`;
          }
        } else if (data.type === 2) {
          if (data.layer === 1) {
            return `${2 * padding}px`;
          }
        }
      }
    },
  }
};
</script>
<style lang="less" scoped>
.tree {
  display: flex;
  flex-direction: row;
  &-item-name {
    display: flex;
    flex-direction: row;
    min-height: 53px;
    > div {
      box-sizing: border-box;
      padding: 10px 20px;
      border-right: 1px solid #e1e6f0;
      border-bottom: 1px solid #e1e6f0;
      display: flex;
      justify-content: center;
      align-items: center;
      &:first-child {
        border-left: 1px solid #e1e6f0;
      }
    }
    .input-content {
      cursor: pointer;
      display: flex;
      background: #fff;
      align-items: center;
      user-select: none;
    }
    .base-span-info {
      user-select: none;
      background: #fff;
    }
    .p-limit {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }
  &-children {
    display: flex;
    flex-direction: column;
    .tree-item-name {
      div {
        &:first-child {
          border-left: 0px;
        }
      }
    }
  }
}
</style>

使用
Test.vue

<template>
<div>
     <RightTree
           :column-data="columnData"
           :column-width="145"
           :column-height="53"
           :data="treeData"
           @edit-data="editData"
           ></RightTree>
</div>
</template>

<script>
import RightTree from '@/components/RightTree/index.vue'
const vm = {
  name: "Test",
  components: {
    RightTree
  },
  data() {
    return {
      columnData: [ "参数1", "参数2"],
      version_id: null,
      treeData: [],
    };
  },
  methods: {
    async getTreeData() {
      let res = await this.$http({...参数});
      this.treeData = this.resolveTreeData(data, 1);
    },
    editData(data) {
    	console.log(data) // 当前节点
    	console.log(this.findParentNode(data, data.id)) // 当前节点的父节点
      // 调用修改接口
    },
    // 找到当前节点的父节点
    findParentNode(data, id, parent) {
      for (let item of data) {
        if (item.id === id) {
          return parent || item;
        }
        if (item?.children?.length) {
          let node = this.findParentNode(item.children, id, item);
          if (node) {
            return node;
          }
        }
      }
      return null;
    },
    // 给树的每个节点添加属性
    resolveTreeData(treeData, layer) {
      const tree = treeData.map((item) => {
        item.layer = layer;
        if (Object.prototype.hasOwnProperty.call(item, "children")) {
          item.children && this.resolveTreeData(item.children, layer + 1);
        }
        return item;
      })
      return tree;
    },
  },
};
export default vm;
</script>


版权声明:本文为qq_38157825原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。