zoukankan      html  css  js  c++  java
  • 仿禅道拖拽任务列表实现

    实现效果图 目前只适应6栏js操作


    实现功能:实现各个阶段任务随意拖动到任意栏目,栏目宽度按传入数组自适应分布
    html

      <div class="task-wrap">
        <div
          class="list-item"
          v-for="item in taskList"
          :key="item.id"
          :style="index == 0 ? 'background:#fff' : ''"
        >
          <div class="header">
            {{ item.name }}
          </div>
          <div class="list">
            <div
              class="listBx"
              :class="move ? 'move' : ''"
              v-for="child in item.child"
              :key="child.id"
              draggable="true"
              @dragover.prevent
              @dragstart="dragstart($event, child, item.id)"
              @drag="dragmove"
              @dragend="dragend($event, child)"
              @mouseover="enter"
              @mouseleave="leave"
            >
              <div class="top">
                {{ child.title }}
              </div>
              <div class="bottom">
                {{ child.name }}
                <span> {{ child.time }}</span>
              </div>
            </div>
          </div>
        </div>
        <div class="nav-header" v-show="flag">
          <div class="header-item" v-for="item in taskList" :key="item.id">
            {{ item.name }}
          </div>
        </div>
        <el-dialog
          title="任务修改"
          :visible.sync="dialogVisible"
          width="650px"
          center
        >
          <el-form ref="form" :model="form" label-width="80px">
            <el-form-item label="任务名称">
              <el-input v-model="form.name"></el-input>
            </el-form-item>
            <el-form-item label="任务时间">
              <el-input v-model="form.time"></el-input>
            </el-form-item>
            <el-form-item label="任务类型">
              <el-select v-model="form.region" placeholder="任务类型">
                <el-option label="未开始" value="1"></el-option>
                <el-option label="进行中" value="2"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="任务内容">
              <el-input
                type="textarea"
                :rows="2"
                placeholder="请输入内容"
                v-model="form.title"
              >
              </el-input>
            </el-form-item>
          </el-form>
          <span slot="footer" class="dialog-footer">
            <el-button @click="dialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="dialogVisible = false"
              >确 定</el-button
            >
          </span>
        </el-dialog>
      </div>
    

    js

    export default {
      name: "task",
      data() {
        return {
          dialogVisible: false,
          flag: false,
          move: false,
          screenWidth: document.documentElement.clientWidth,
          itemWidth: 0,
          index: 0,
          form: {},
          taskList: [
            {
              id: 1,
              name: "未开始",
              child: [
                {
                  id: 11,
                  title: "成品的价格方面,重新设计",
                  name: "王小虎",
                  time: "1h"
                }
              ]
            },
            {
              id: 2,
              name: "进行中",
              child: [
                // {
                //   id: 21,
                //   title: "成品的价格方面,重新设计",
                //   name: "王小虎",
                //   time: "1h"
                // }
              ]
            },
            {
              id: 3,
              name: "已暂停",
              child: [
                // {
                //   id: 31,
                //   title: "成品的价格方面,重新设计",
                //   name: "王小虎",
                //   time: "1h"
                // }
              ]
            },
            {
              id: 4,
              name: "已完成",
              child: [
                {
                  id: 41,
                  title: "成品的价格方面,重新设计",
                  name: "王小虎",
                  time: "1h"
                }
              ]
            },
            {
              id: 5,
              name: "已取消",
              child: [
                {
                  id: 51,
                  title: "成品的价格方面,重新设计",
                  name: "王小虎",
                  time: "1h"
                }
              ]
            },
            {
              id: 6,
              name: "已关闭",
              child: [
                {
                  id: 61,
                  title: "基础数据客户管理批量导入",
                  name: "已关闭",
                  time: "0h"
                },
                {
                  id: 71,
                  title: "基础数据.客户管理,导入模板",
                  name: "已关闭",
                  time: "0h"
                },
                {
                  id: 81,
                  title: "基础数据成品管理详情的样式",
                  name: "已关闭",
                  time: "0h"
                }
              ]
            }
          ],
        };
      },
      mounted() {
        // 判断传递的子项定义宽度
        let taskList = document.querySelectorAll(".list-item");
        let headerList = document.querySelectorAll(".header-item");
        let width;
        if (taskList.length == 2) {
          width = "50%";
        } else if (taskList.length == 3) {
          width = "33.33%";
        } else if (taskList.length == 4) {
          width = "25%";
        } else if (taskList.length == 5) {
          width = "20%";
        } else if (taskList.length == 6) {
          width = "16.66%";
        }
        for (var i = 0; i < taskList.length; i++) {
          taskList[i].style.width = width;
          headerList[i].style.width = width;
        }
        window.onresize = () => {
          return (() => {
            // 获取到实时的屏幕宽度
            this.screenWidth = document.documentElement.clientWidth;
            let headerList = document.querySelectorAll(".header-item");
            // 实时获取每一栏的宽度
            this.itemWidth = this.screenWidth / headerList.length;
          })();
        };
        window.addEventListener("scroll", this.handleScroll);
      },
      destroyed() {
        document.removeEventListener("scroll", this.handleScroll);
      },
      methods: {
        handleScroll() {
          //获取滚动时的高度
          let scrollTop =
            window.pageYOffset ||
            document.documentElement.scrollTop ||
            document.body.scrollTop;
          if (scrollTop > 50) {
            this.flag = true;
          }
          if (scrollTop < 50) {
            this.flag = false;
          }
        },
        dragstart(event, child, index) {
          this.move = true;
          // 判断移动的是哪一栏 通过传递的参数获得
          let str = child.id + "";
          // 获取当前移动的坐标
          this.index = index;
          // 获取当前宽度
          this.itemWidth = parseInt(this.screenWidth / this.taskList.length);
          // 当前选择的位置
          this.form = child;
        },
        dragmove() {
          let taskList = document.querySelectorAll(".list-item");
          let index = this.index;
          let indexEnd = parseInt(event.clientX / this.itemWidth);
          for (let i = 0; i < taskList.length; i++) {
            taskList[i].style.background = "#fff";
          }
          taskList[indexEnd].style.background = "rgba(0,0,0,.2)";
        },
        dragend(event, child) {
          this.move = false;
          // 获取移动的初始以及之后的坐标
          let index = this.index - 1;
          let indexEnd = parseInt(event.clientX / this.itemWidth);
          // 获取当前子元素坐标
          let i = this.taskList[index].child.indexOf(child);
          this.taskList[index].child.splice(i, 1);
          this.taskList[indexEnd].child.push(child);
          this.dialogVisible = true;
    
          let taskList = document.querySelectorAll(".list-item");
          taskList[0].style.background = "#fff";
        },
        enter(index) {
          this.move = true;
        },
        leave() {
          this.move = false;
        }
      }
    };
    

    css

    body {
      height: 100%;
    }
    .task-wrap {
      min- 1200px;
      overflow-x: hidden;
    }
    .task-wrap .list-item {
      float: left;
       16.66%;
      height: 100%;
    }
    .task-wrap .list-item .header {
       100%;
      height: 44px;
      line-height: 44px;
      text-align: center;
    }
    .task-wrap .list-item .list {
      min-height: 100vh;
      padding: 10px;
      border-right: 2px solid #ccc;
    }
    .task-wrap .list-item .list .listBx {
      box-sizing: border-box;
       100%;
      min-height: 64px;
      padding: 10px;
      border: 1px solid #ccc;
      margin-bottom: 10px;
    }
    .move {
      cursor: move;
    }
    .task-wrap .list-item .list .listBx > div {
      height: 50%;
    }
    .task-wrap .list-item .list .listBx .top {
      line-height: 28px;
      overflow: hidden;
      text-overflow: ellipsis;
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
    }
    .task-wrap .list-item .list .listBx .bottom {
      position: relative;
      padding-left: 32px;
    }
    .task-wrap .list-item .list .listBx .bottom::before {
      position: absolute;
      top: -5px;
      left: 0;
      content: "";
      display: inline-block;
       28px;
      height: 40px;
      background: url("../assets/zx.png") no-repeat;
    }
    .task-wrap .list-item .list .listBx .bottom span {
      position: absolute;
      top: 5px;
      right: 10px;
      color: #999;
    }
    .task-wrap .list-item:nth-child(1) .header,
    .nav-header div:nth-child(1) {
      font-weight: 600;
      border-bottom: 5px solid #92ceff;
    }
    .task-wrap .list-item:nth-child(2) .header,
    .nav-header div:nth-child(2) {
      font-weight: 600;
      border-bottom: 5px solid #0991ff;
    }
    .task-wrap .list-item:nth-child(3) .header,
    .nav-header div:nth-child(3) {
      font-weight: 600;
      border-bottom: 5px solid #fdcb56;
    }
    .task-wrap .list-item:nth-child(4) .header,
    .nav-header div:nth-child(4) {
      font-weight: 600;
      border-bottom: 5px solid #40df98;
    }
    .task-wrap .list-item:nth-child(5) .header,
    .nav-header div:nth-child(5) {
      font-weight: 600;
      border-bottom: 5px solid #cccccc;
    }
    .task-wrap .list-item:nth-child(6) .header,
    .nav-header div:nth-child(6) {
      font-weight: 600;
      border-bottom: 5px solid #7f869a;
    }
    .nav-header {
      position: fixed;
      top: 0;
       100%;
      height: 44px;
      line-height: 44px;
      background: #fff;
      transition: 0.2s;
    }
    .nav-header div {
      float: left;
      text-align: center;
       16.66%;
    }
    .mask {
       100px;
      height: 100px;
      background: pink;
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
    
    愿以往所学皆有所获
  • 相关阅读:
    SQL Server解惑——查询条件IN中能否使用变量
    依赖注入高级玩法——注入接口服务的多个实现类
    最纯净的硬件检测工具箱
    批处理体会hosts文件
    针对m3u8视频的ts文件解密
    HLS协议之m3u8和ts流格式详解
    您的主机不满足在启用Hyper-V或Device/Credential Guard的情况下运行VMwareWorkstation的最低要求
    FFmpeg的安装和使用
    如何下载 blob 地址的视频资源
    Win10系统创建WiFi热点的两种方法
  • 原文地址:https://www.cnblogs.com/Azune/p/14070263.html
Copyright © 2011-2022 走看看