Vue 写一个在一个dom上任意一点随意点击触发新增事件,弹窗。并且生成新的子dom节点,携带托拉拽删除编辑等功能。

前一段时间遇到一个需求是在要求前端页面写出,随意点击任意一点,会生成新增弹窗,再弹窗中选择要新增的类型。保存后生成新的子dom元素节点,并且新增的每一个新的元素,都可以托拉拽任意更改位置,可以实现编辑修改删除等操作。

思路:1.首先想到的就是画布canvas,需要很多的数据计算所以我暂时先没考虑。

           2.先确定需求,任意点击触发事件,新的元素支持修改编辑删除,支持托拉拽功能

           3.确定方向,需要考虑的是获取鼠标的坐标,并且生成的节点为动态的坐标,脱离文档流布局,动态 left top ,每次托拉拽后的动态 left top

话不多说,代码搞上:

<template>
  <div class="canvas">
    <div class="operation">
      <div class="increase"
           @click="operClick(1)"
           :class="[this.lampType !== 1 ? 'oper' : 'opers']">新增</div>
      <div class="delete"
           @click="operClick(2)"
           :class="[this.lampType !== 2 ? 'oper' : 'opers']">删除</div>
      <div class="drag_drop"
           @click="operClick(3)"
           :class="[this.lampType !== 3 ? 'oper' : 'opers']">拖拽</div>
      <div class="editor"
           @click="operClick(4)"
           :class="[this.lampType !== 4 ? 'oper' : 'opers']">编辑</div>
      <div class="view"
           @click="operClick(5)"
           :class="[this.lampType !== 5 ? 'oper' : 'opers']">查看</div>
    </div>
    <div class="contentsss">
      <div class="canvas_con"
           @click="getmous($event)">
        <div class="dingwei">
          <div v-for="(item,index) in lists"
               :key="index"
               style="position: absolute">
            <div :class="['tub'+index]"
                 :style="{width:item.width,height:item.height,position:'absolute',border:item.border,top:item.top,left:item.left,textAlign:'center',lineHeight:'100px'}"
                 @click="domClick(index)"
                 @mousedown="move"
                 :data-song='index'
                 ref="demodiv">
              {{item.name}}
              <img :src="item.img"
                   style="width:20px;height:20px;">
            </div>
          </div>
        </div>
      </div>
    </div>

    <el-dialog title=""
               :visible.sync="dialogFormVisible">
      <el-form :model="form">
        <el-form-item label="设施类型"
                      label-width="120px">
          <el-select v-model="form.region"
                     placeholder="请选择设施类型"
                     style="width:100%">
            <el-option label="灯"
                       value="1"></el-option>
            <el-option label="空调"
                       value="2"></el-option>
            <el-option label="桌子"
                       value="3"></el-option>
            <el-option label="椅子"
                       value="4"></el-option>
            <el-option label="消防栓箱子"
                       value="5"></el-option>
            <el-option label="垃圾桶"
                       value="6"></el-option>
            <el-option label="饮水机"
                       value="7"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="设施区组号"
                      label-width="120px">
          <el-input v-model="form.name"
                    autocomplete="off"></el-input>
        </el-form-item>

      </el-form>
      <div slot="footer"
           class="dialog-footer">
        <el-button @click="clearClick()">取 消</el-button>
        <el-button type="primary"
                   @click="saveClick()">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data () {
    return {
      domtop: '',
      domleft: '',
      lists: [],
      dialogFormVisible: false,
      form: {
        name: '',
        region: ''
      },
      images: '',
      clickDomeType: false,
      lampType: 0,
      viewType: 0,
      editorType: 0,
      dragType: 0,
      deleteType: 0,
      increaseType: 0,
      tub: null
    }
  },
  components: {
  },
  watch: {
    lists () {
      // this.tub
    }

  },
  methods: {
    //点击选项
    operClick (index) {
      if (index === 1) {
        this.lampType = 1
      }
      if (index === 2) {
        this.lampType = 2
      }
      if (index === 3) {
        this.lampType = 3
      }
      if (index === 4) {
        this.lampType = 4
      }
      if (index === 5) {
        this.lampType = 5
      }
    },
    //拖拽设施
    move (e) {
      if (this.lampType === 3) {
        console.log(e.srcElement.dataset.song, '/')
        // e.preventDefault()//取消一系列点击事件
        var content = document.querySelector('.canvas_con')
        var tub = document.querySelector('.tub' + e.srcElement.dataset.song)

        console.log(content, 'content')
        console.log(tub, 'tub')
        var x = e.clientX - tub.offsetLeft
        var y = e.clientY - tub.offsetTop
        content.addEventListener('mousemove', move)
      }
      function move (e) {
        tub.style.left = e.pageX - x + 'px'
        tub.style.top = e.pageY - y + 'px'
      }
      // 添加鼠标抬起事件,鼠标抬起,将事件移除
      tub.addEventListener('mouseup', function () {
        content.removeEventListener('mousemove', move)
      })
      // 鼠标离开父级元素,把事件移除
      content.addEventListener('mouseout', function () {
        content.removeEventListener('mousemove', move)
      })


    },
    //点击dome删除操作
    domClick (index) {
      this.clickDomeType = true
      if (this.lampType === 2) {

        console.log(index, 'index')
        this.$confirm('此操作将永久删除该文件, 是否继续?  注意此demo没有加编辑功能,后期项目加!!!', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.lists.splice(index, 1)
          this.clickDomeType = false
          this.$message({
            type: 'success',
            message: '删除成功!'
          });
        }).catch(() => {
          this.clickDomeType = false
          this.$message({
            type: 'info',
            message: '已取消删除'
          });
        });
      }

    },
    // 点击取消
    clearClick () {
      this.dialogFormVisible = false
    },
    // 点击确定提交
    saveClick () {

      this.images = ''
      if (this.form.region === '1') {
        this.images = require('@/assets/img/liang.png')
      } else if (this.form.region === '2') {
        this.images = require('@/assets/img/loading.png')
      } else if (this.form.region === '3') {
        this.images = require('@/assets/img/touying.png')
      } else if (this.form.region === '4') {
        this.images = require('@/assets/img/11.jpg')
      } else if (this.form.region === '5') {
        this.images = require('@/assets/img/111.jpg')
      }
      this.lists.push({
        name: this.form.name,
        type: this.form.region,
        height: '100px',
        width: '100px',
        position: 'absolute',
        border: '1px solid #000',
        top: this.domtop,
        left: this.domleft,
        img: this.images
      })
      // this.lists.forEach((item) => {
      //   this.tub = 
      // })
      console.log(this.lists, 'lists')
      this.dialogFormVisible = false
    },
    //点击全屏
    getmous (e) {
      this.clickDomeType = false
      // debugger
      if (this.lampType === 1) {
        this.form = {
          name: '',
          region: ''
        }
        this.domleft = e.clientX - 50 + 'px'
        this.domtop = e.clientY - 150 + 'px'
        if (this.clickDomeType === true) {
          this.dialogFormVisible = false
        } else {
          this.dialogFormVisible = true
        }
        console.log(e, 'es')
      }

    }
  }
}
</script>
<style  lang="scss">
.canvas_con {
  width: 1000px;
  height: 700px;
  // position: relative;
  border: 1px solid #000;
  .dingwei {
    position: absolute;
  }
}
.operation {
  .pointer {
    float: right;
    width: 100px;
    height: 40px;
    border: 1px solid #000;
    margin-left: 10px;
    margin-top: 10px;
    text-align: center;
    line-height: 40px;
    background: rgb(9, 103, 243);
    color: #fff;
    font-weight: 600;
    cursor: pointer;
  }
  .move {
    float: right;
    width: 100px;
    height: 40px;
    border: 1px solid #000;
    margin-left: 10px;
    margin-top: 10px;
    text-align: center;
    line-height: 40px;
    background: rgb(9, 103, 243);
    color: #fff;
    font-weight: 600;
    cursor: move;
  }
  .opers {
    float: right;
    width: 100px;
    height: 40px;
    border: 3px solid #000;
    margin-left: 10px;
    margin-top: 10px;
    text-align: center;
    line-height: 40px;
    background: rgb(9, 103, 243);
    color: #fff;
    font-weight: 600;
    cursor: pointer;
  }
  .oper {
    float: right;
    width: 100px;
    height: 40px;
    border: 3px solid #000;
    margin-left: 10px;
    margin-top: 10px;
    text-align: center;
    line-height: 40px;
    cursor: pointer;
  }
}
.xiaoshou {
  cursor: pointer;
}
.yidong {
  cursor: move;
}
</style>

代码就这么多,数据交互没有写,这需要阅读者自己操作一下啦。

存储每次点击确定生成新的dom的信息和坐标信息,存储每次托拉拽后的位置坐标信息。

有看不明白的地方可以留言一下

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值