Bootstrap

vue实现目录的curd

引用

PascalCase (首字母大写命名)组件,<my-component-name><MyComponentName> 都是可接受
直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case是有效的,比如 text/x-template场景下,只能用后者

知识点

  • class 样式对象写法,CSS伪元素 ::before 用法
  • vue 指令v-model,内联模板x-template
  • 事件 dblclick blur, 防止事件传播修饰符 stop
  • 引用父实例属性 $parent, 全局方法 Vue.set Vue.delete,子组件类型校验props

树形curd

  • tree.js
// 树形原始数据结构
var data = {
  name: 'home',
  children: [
    { name: 'hello.js' },
    {
      name: 'child folder',
      children: [
        {
          name: 'code folder',
          children: [
            { name: 'php' },
            { name: 'golang' }
          ]
        },
      ]
    },
    { name: 'wat.py' }
  ]
}

// 注册全局子组件
Vue.component('item', {
  template: '#item-template',
  // 类型校验,接收父组件传递过来的数据(只读) 
  props: {
    model: Object,
  },

  // 当前子组件私有的响应数据
  data() {
    return {
      open: false,              // 展开标志
      name: this.model.name,    // 显示文本
      show: true                // 是否使用编辑
    }
  },

  computed: {
    // 子节点判断标志
    isFolder() {
      return this.model.children && this.model.children.length
    }
  },

  methods: {
    toggle() {
      if (this.isFolder) {
        this.open = !this.open
      }
    },

    changeType() {
      // 将文件变为文件夹
      if (!this.isFolder) {
        // 向响应式对象中添加一个新属性,需确保这个新属性同样是响应式的,以触发视图更新
        Vue.set(this.model, 'children', [])
        this.addChild()
        this.open = true
      }
    },
    addChild() {
      this.model.children.push({
        name: 'new file'
      })
    },
    // 清除文件夹下子节点
    delChild() {
      if (this.isFolder) {
        Vue.delete(this.model, 'children')
      }
    },
    delFile() {
      // 通过父节点删除当前节点
      if (this.$parent.model === undefined) {
        console.log('根节点不能删除!!!')
        this.name = '根节点不能删除!'
        return
      }
      var parent = this.$parent.model.children
      if (parent && Array.isArray(parent) && parent.length) {
        // 清除当前节点
        parent.splice(parent.indexOf(this.model), 1)
      }
    },

    // 编辑开关
    editToggle() {
      this.show = !this.show
    },
    doneEdit(name) {
      this.old = name
      this.name = name
      this.show = false
    },

    cancelEdit() {
      this.name = this.old
      this.show = false
    }
  }
})

var demo = new Vue({
  el: '#demo',
  data: {
    treeData: data
  }
})

视图

  • tree.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vuejs树形结构curd</title>
    <style>
        body {
            font-family: Menlo, Consolas, monospace;
            color: #444;
        }
        .item {
            cursor: pointer;
        }
        .bold {
            font-weight: bold;
        }
        ul {
            padding-left: 1em;
            line-height: 1.5em;
            list-style-type: dot;
        }
        .folderc::before {
            content: '?  '
        }
        .foldero::before {
            content: '?  '
        }
        .file::before {
            content: '?  '
        }
        p {
            line-height: 7px;
            font-size:7px;
        }
    </style>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
</head>
<body>
    <script type="text/x-template" id="item-template">
    <li>
        <div :class="{foldero:isFolder && open ,folderc: !(isFolder && open),file:!isFolder}" 
        	@click="toggle" @dblclick="changeType">
            <span v-show="show">{{ name }}</span>
            <input type="text" class="edit" v-model="name"
                        @blur="doneEdit(name)" @keyup.enter="doneEdit(name)" 
                        @keyup.esc="cancelEdit()" v-show="!show" @click.stop @dblclick.stop >
            <span @click.stop='editToggle'>[e]</span>
            <span @click.stop='delChild' v-show="isFolder">[c]</span>
            <span @click.stop='delFile' v-show="!isFolder">[x]</span>
            <span v-if="isFolder">[{{ open ? '-':'+'}}]</span>
        </div>
        <ul v-show="open" v-if="isFolder">
            <item class="item" v-for="(treeData,index) in this.model.children" :model="treeData" :key="index"/>
            <li><span class="add" @click.stop="addChild">[append] </span></li>
        </ul>
    </li>
    </script>
    <p>[+]展开 [-]折叠 [e]编辑 </p>
    <p>[x]删除文件 [c]清空文件夹</p>
    <p>[append]追加节点文件</p>
    <p>文件夹递归删除转为文件</p>
    <p>双击文件转为含新文件的文件夹</p>
    <ul id="demo">
        <item class="item" :model="treeData" />
    </ul>
    <script src="tree.js"></script>
</body>
</html>
;