tree 动态添加、删除树结构数据

tree.vue 组件

<template>
    <div>
        <div @click="getData" :style="getDetph(currentItem.level)" class="li">
            <span class="icon"></span>
            <div contenteditable class="edit" :class="'input' + currentItem.id"
                @keydown="textareaKeydown($event, currentItem, itemIndex)">{{ currentItem.id }}</div>
        </div>
        <div v-if="isShow">
            <tree :currentItem="item" :itemIndex="index" v-for="(item, index) in currentItem.children" @insert="insert" @delete="deleteFun" :key="index">
            </tree>
        </div>
    </div>
</template>

<script>
export default {
    name: "tree",
    components: {},
    data: function () {
        return {
            isShow: true
        };
    },
    props: {
        // 接收标题
        currentItem: {
            type: Object
            // default: "标题"
        },
        itemIndex: {
            type: Number
        }
    },
    methods: {
        getDetph(level) {
            return `transform:translate(${level * 20}px)`;
        },
        insert(obj){
            this.$emit('insert', obj)
        },
        deleteFun(obj){
            this.$emit('delete', obj)
        },
        getData: function () {
            this.isShow = true
        },
        textareaKeydown(event, currentItem, index) {
            console.log(event.target.innerText)
            if (event.keyCode === 13) {
                this.$emit('insert', {
                    parentId: currentItem.parentId,
                    level: currentItem.level
                });
                event.preventDefault() // 阻止浏览器默认换行操作
                return false
            } else if (event.key =="Backspace" && !event.target.innerText) {
                this.$emit('delete', {
                    parentId: currentItem.parentId,
                    level: currentItem.level,
                    index
                });
                event.preventDefault() // 阻止浏览器默认换行操作
                return false
            } else if (event.keyCode === 9 && event.target.innerText) {
                this.$emit('insert', {
                    parentId: currentItem.id,
                    level: currentItem.level + 1
                });
                event.preventDefault() // 阻止浏览器默认换行操作
                return false
            } else if (event.keyCode === 9 && !event.target.innerText) {
                event.preventDefault() // 阻止浏览器默认换行操作
                return false
            }
        },
    }
};
</script>
<style scoped>
/* @import url(); 引入css类 */
.li{
    width: 100%;
    height: 30px;
    line-height: 30px;
}
.edit{
    width: calc(100% - 16px);
    float: left;
    margin-left: 10px;
}
.edit:focus{
    border:none;
    outline: none; 
}
.icon{
    display: inline-block;
    height: 6px;
    width: 6px;
    border-radius: 50%;
    background: #000;
    float: left;
    margin-top: 10px;
}
</style>

 

父组件

<template>
    <div class="home">
      <div >
        <tree v-for="(item, index) in list" :key="index" :currentItem="item" @insert="insert" @delete="deleteFun" :itemIndex="index"></tree>
      </div>
    </div>
</template>
<script>
import tree from '../components/tree'
export default {
  name: "Home",
  components: {
    tree
  },
  data: function () {
    return {
      list: [{
        id: 0,
        name: "标题",
        level: 0,
        children:[{
          id: 1 + '-' + 0,
          name: "酒店",
          level: 1,
          parentId: 0,
          children: []
        }]
      }]
    };
  },
  methods: {
    deleChildFun(arr, obj){
      arr.forEach(item=>{
        if(item.id == obj.parentId){
          console.log('obj.index', obj.index)
          const preItem = obj.index> 0 ? item.children[obj.index -1] : item
          console.log('preItem', preItem)
          item.children.splice(obj.index, 1)
          this.$nextTick(() => {
            const notesDom = document.getElementsByClassName('input' + preItem.id)[0]
            this.setRang(notesDom)
          })
        }
        if(item.children && item.children.length > 0){
          this.deleChildFun(item.children, obj)
        }
      })
    },
    deleteFun(obj){
      this.deleChildFun(this.list, obj)
      console.log(this.list)
    },
    insertChildren(list, obj){
      list.forEach(item=>{
        if(item.id == obj.parentId){
          const length = item.children.length
          item.children.push({
            id: obj.parentId + '-' + obj.level + '-' + length,
            name: '',
            parentId: obj.parentId,
            level: obj.level,
            children: []
          })
          this.$nextTick(() => {
            const notesDom = document.getElementsByClassName('input' + obj.parentId + '-' + obj.level + '-' + length)[0]
            console.log('input', notesDom)
            this.setRang(notesDom)
          })
        }
        if(item.children && item.children.length > 0){
          this.insertChildren(item.children, obj)
        }
      })
    },
    insert (obj) {
      this.insertChildren(this.list, obj)
      console.log(this.list)
    },
    setRang(notesDom){
      if (window.getSelection) {
          // 兼容 IE11 10 9 ff safari
          // notesDom.focus(); // 解决ff不获取焦点无法定位问题
          let range = window.getSelection(); // 创建range
          range.selectAllChildren(notesDom); // range 选择notesDom下所有子内容
          range.collapseToEnd(); // 光标移至最后
        } else if (document.selection) {
          // 兼容 IE10 9 8 7 6
          let range = document.selection.createRange(); // 创建选择对象
          range.moveToElementText(notesDom); // range定位到notesDom
          range.collapse(false); // 光标移至最后
          range.select();
        }
    }
  }
};
</script>
<style scoped>
.ww {
  margin-left: 20px;
}

.hh {
  font-size: 10px;
}
</style>

 

posted @ 2022-11-15 17:10  不服憋着  阅读(176)  评论(0编辑  收藏  举报