ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树形可拖拽排序配置组件

2021-10-30 13:38:23  阅读:210  来源: 互联网

标签:center width id item 树形 parentId 组件 data 拖拽


效果

在这里插入图片描述

使用场景

vue2下自定义表格表头配置: 列排序,显示/隐藏等。确保表头以配置项的形式加载,这样表格才能对修改后的配置作响应

思路

1、表格使用render函数加载(如有疑问可私信),通过类似如下的columns配置表头

columns: [
          { label: '姓名', prop: 'name', width: '160', fixed: true },
          { label: '性别', prop: 'sex', align: 'center', width: '160', fixed: false },
          { label: '证件类别', prop: 'cardType', align: 'center', width: '160', fixed: false },
          { label: '证件号', prop: 'idCard', align: 'center', width: '260', fixed: false },
          { label: '手机号', prop: 'mobile', align: 'center', width: '160', fixed: false },
          { label: '标签', prop: 'tag', align: 'center', width: '160', fixed: false },
          { label: '操作', prop: 'manage', align: 'center', disControl: true },
]

2、通过element-ui 的 el-dropdown 组件完成配置项的展示动作

<el-dropdown trigger="click" :hide-on-click="false">
      <span class="el-icon-setting" style="font-size: 25px"></span>
      <template slot="dropdown">
        <el-dropdown-menu>
          <JSelectionItem :arr.sync="rows" @item-click="itemClickHandle">
            <template v-slot:default="{item,level}">
              <div class="item-custom">
                {{item.id}}
              </div>
            </template>
            <template v-slot:tool="{item,level}">
              <span class="el-icon-check"
                    v-if="item.visible"
                    style="size: 20px;margin-top: 5px">
              </span>
            </template>
          </JSelectionItem>
        </el-dropdown-menu>
      </template>
    </el-dropdown>

3、使用vue.draggable 组件完成拖拽效果,具体应用可参考draggable
4、树形结构往往需要递归加载,我选择使用组件递归而非在render中通过js递归去完成配置组件的加载,因为使用render过程中碰到拖拽动画失效的问题,没有思路去解决。

代码

使用树形配置项的组件

<template>
  <div>
    <el-dropdown trigger="click" :hide-on-click="false">
      <span class="el-icon-setting" style="font-size: 25px"></span>
      <template slot="dropdown">
        <el-dropdown-menu>
          <JSelectionItem :arr.sync="rows" @item-click="itemClickHandle">
            <template v-slot:default="{item,level}">
              <div class="item-custom">
                {{item.id}}
              </div>
            </template>
            <template v-slot:tool="{item,level}">
              <span class="el-icon-check"
                    v-if="item.visible"
                    style="size: 20px;margin-top: 5px">
              </span>
            </template>
          </JSelectionItem>
        </el-dropdown-menu>
      </template>
    </el-dropdown>

  </div>
</template>

<script>
import JSelectionItem from "./JSelectionItem";

export default {
  name: "JHeadManage",
  components: {  JSelectionItem },
  data() {
    return {
      rows: []
    }
  },
  created() {
    this.getResource()
  },
  methods: {
    itemClickHandle(item) {
      item.visible = !item.visible
      console.log(item)
    },
    getResource() {
      const vm = this
      //测试用数据只有一个根节点 "0" 方便构建测试用数据树
      const data = [
        { id: '1', parentId: '0' },
        { id: '2', parentId: '0' },
        { id: '2-0', parentId: '2' },
        { id: '1-0', parentId: '1' },
        { id: '1-1', parentId: '1' },
        { id: '1-1-0', parentId: '1-1' },
        { id: '1-1-0-0', parentId: '1-1-0' },
        { id: '1-1-0-1', parentId: '1-1-0' },
        { id: '1-2', parentId: '1' },
        { id: '1-2-0', parentId: '1-2' },
        { id: '1-2-1', parentId: '1-2' },
      ]
      //1) 简单处理数据用于自定义渲染; checked:  indeterminate:
      data.forEach((d, index) => {
        d.visible = true //是否选中
        d.isIndeterminate = false//是否是半选状态
        d.a = 'a' + index
      })
      vm.rows = vm.makeTree(data, 'id', 'parentId', '0')
      // vm.rows = data
    },
    /**
     * 构建树,与复选逻辑无关
     * @param data
     * @param idMark
     * @param pIdMark
     * @param rootId
     * @returns {*}
     */
    makeTree(data, idMark, pIdMark, rootId) {
      //转化为字典,id为键值,并添加根节点对象
      let nodeDict = {};
      (nodeDict[rootId] = { children: [] })[idMark] = rootId;
      data.forEach(n => (nodeDict[n[idMark]] = n).children = []);
      data.forEach(d => nodeDict[d[pIdMark]]?.children?.push(d))
      return nodeDict[rootId].children;
    }
  }
}
</script>

<style scoped>

  .item-custom {
    display: inline-flex;
    padding: 10px 0;
    margin-right: auto;
  }

</style>

树型配置项组件

定义了两个插槽,一个用来显示主要内容一个用来放置对选项的操作

<template>
  <ul class="list" :style="{paddingLeft:level==0?'10px':'0'}">
    <draggable v-model="locArr"
               :animation="100"
               handle=".tip"
               @start="onStart"
               @end="onEnd">
      <transition-group>
        <li class="item" v-for="(c,i) in locArr" :key="i">
          <div class="item-inner" :style="{paddingLeft:level*20+'px'}" @click.stop="itemClick(c)">
            <span class="tip el-icon-more-outline"></span>
            <slot v-bind:item="c" v-bind:level="level"></slot>
            <div class="item-tool">
              <slot name="tool" v-bind:item="c" v-bind:level="level"></slot>
            </div>
          </div>
          <template v-if="c.children&&c.children.length>0">
            <JSelectionItem :arr.sync="c.children" :level="level+1" @item-click="itemClick">
              <template v-slot:default="{item,level}">
                <slot v-bind:item="item" v-bind:level="level"></slot>
              </template>
              <template v-slot:tool="{item,level}">
                <slot name="tool" v-bind:item="item" v-bind:level="level"></slot>
              </template>
            </JSelectionItem>
          </template>
        </li>
      </transition-group>
    </draggable>
  </ul>
</template>

<script>
import draggable from 'vuedraggable'
import JSelectionItem from "@/views/demo/JSelectionItem";

export default {
  name: "JSelectionItem",
  components: {
    JSelectionItem, draggable
  },
  data() {
    return {}
  },
  computed: {
    locArr: {
      get() {
        return this.arr
      },
      set(val) {
        this.$emit('update:arr', val)
      }
    },
  },
  props: {
    arr: {
      type: Array,
      default: () => []
    },
    level: {
      type: Number,
      default: 0,
    }
  },
  methods: {
    onStart() {

    },
    onEnd() {

    },
    itemClick(item) {
      this.$emit('item-click', item)
    }
  }
}
</script>

<style scoped>
  .list {
    width: 100%;
    margin: 0;
    padding: 0;
  }

  .item {
    padding: 0;
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
  }

  .item-inner {
    display: flex;
    width: 100%;
    position: relative;
    justify-content: space-between;
    border-bottom: 1px solid #e5e5e5;
    user-select: none;
  }

  .item-inner:hover {
    /*font-weight: bold;*/
  }

  .item-tool {
    display: flex;
    position: absolute;
    align-items: center;
    right: 10px;
  }

  .tip {
    transform: rotate(-90deg);
    cursor: move;
    font-size: 20px;
    user-select: none;
  }

</style>

标签:center,width,id,item,树形,parentId,组件,data,拖拽
来源: https://blog.csdn.net/weixin_43954962/article/details/121049536

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有