vue仿有赞 魔方插件 源码分享

项目要求封装一个有赞魔方矩阵类型的插件,我当时内心是拒绝的
在这里插入图片描述

费尽周折查阅很多资料才找到靠谱的方法,下图为效果,因为没有几行代码就直接在csdn上分享了
在这里插入图片描述
解决思路为:
1、一共两层底下层添加自定义属性 y x 确定每一块元素的几行几列;
2、知道点击的是几行几列之后计算出单个单元格的宽,上层通过定位实现;
记得在确定的时候做个判断 当前选中是否和其他冲突

上代码

<template>
  <div class="rowncolnParam">
    <div class="decorate-cube" style="margin-left:50px;">
        <ul class="cube-row" v-for="n in densityNum" :key="'ulrow'+n">
            <li 
                :class="['cube-item',{'item-selecting': isSelecting(i,n),'item-selected':isSelected(i,n) }]"
                v-for="i in densityNum" :key="'licol'+i"
                :data-x="i"  :data-y="n"
                :style="{'width':cubeItemWidth+'px','height':cubeItemHeight+'px'}"
                @click="cubeItemClick($event)">
            </li>
        </ul>

        <div class="cube-selected"
          v-for="(item, index) in data.cudeSelected" :key="index"
          :style="{'width':getCubeSelectedWidth(item)+'px','height':getCubeSelectedHeight(item)+'px','top':getCubeSelectedTop(item)+'px','left':getCubeSelectedLeft(item)+'px'}" 
        >
          <p  @click="cubeSelectedDel(index)" class="cube-selected-del">x</p>
          <img :src="item.src" alt="" v-if="item.src" @click="addBanner(index)">
          <div class="cube-selected-text" v-else @click="addBanner(index)">
            <div>
              <i class="el-icon-circle-plus-outline"></i>
              <!-- 像素计算方式保留方便使用 {{ Math.round(cubeWidth/densityNum*((parseInt(item.end.y) - parseInt(item.start.y) + 1))) }} x
              {{ Math.round(cubeHeight/densityNum*((parseInt(item.end.x) - parseInt(item.start.x) + 1))) }} 像素   -->
            </div>
          </div>
        </div>
    </div>
  </div>
</template>

<script>
import  upload  from '@/components/fitmentparam/upload.vue'
export default {
  components:{upload},
  props:{
    data:{
      type:Object,
      default:""
    }
  },
  data(){
    return{
      'cubeWidth':300, //魔方宽度
      'cubeHeight':300, //魔方高度
      'cudeSelecting':{
          'start':null,
          'end':null,
          'data':[]
      },
      // 'cudeSelected':[] //已经生成的单元
    }
  },
  created(){
    console.log(this.data,"数据")
  },
  computed:{
    //密度值 几×几
    densityNum () {
      return 7;
    },
    //单元魔方高度
    cubeItemHeight:function () {
      return this.cubeWidth/this.densityNum;
    },
    //单元魔方宽度
    cubeItemWidth:function () {
      return this.cubeWidth/this.densityNum;
    },
  },
  methods:{

    //魔方点击事件
    cubeItemClick(event) {

      var el = event.currentTarget;
      var x = el.getAttribute('data-x');
      var y = el.getAttribute('data-y');
      var domclass = el.getAttribute('class');
      console.log('['+x+','+y+','+domclass+']执行了点击');

      var cudeSelectingStart = this.cudeSelecting.start;
      var coord = {x:x,y:y};

      if(-1 !== domclass.indexOf('item-selected')){
        alert("已经被占用");
        return;
      }

      if(null == cudeSelectingStart){
        this.cudeSelecting.start = coord;
        this.cudeSelecting.data.push(coord);
      }else{
        this.cudeSelecting.end = coord;
        this.cudeSelecting.data.push(coord);

        //获取开始和结束之间所有魔方单元
        var start = cudeSelectingStart;
        var end = coord;

        var x_start = Math.min(start.x,end.x);
        var x_end = Math.max(start.x,end.x);

        var y_start = Math.min(start.y,end.y);
        var y_end = Math.max(start.y,end.y);

        var real_start = {x:Math.min(start.x,end.x),y:Math.min(start.y,end.y)};
        var real_end = {x:Math.max(start.x,end.x),y:Math.max(start.y,end.y)};

        //找到所有选择范围内的
        this.cudeSelecting.data.splice(0);
        for(var i=x_start;i<=x_end;i++){
            for(var j=y_start;j<=y_end;j++){
              this.cudeSelecting.data.push({x:i,y:j});
            }
        }
        var cudeSelectingData = this.cudeSelecting.data;
        var cudeSelectedArr = [];
        for(var i=0;i<cudeSelectingData.length;i++){
          cudeSelectedArr.push(cudeSelectingData[i])
        }
        console.log(cudeSelectedArr);
        console.log(real_start);
        console.log(real_end);

        //加入选中的
        var cudeSelected = {
            'start':real_start,
            'end':real_end,
            'data':cudeSelectedArr
        }
        this.data.cudeSelected.push(cudeSelected);
        console.log("合并完成数据",this.data.cudeSelected)

        //清除正在选择的
        this.cudeSelecting.start = null;
        this.cudeSelecting.end = null;
        this.cudeSelecting.data.splice(0);

      }

    },
    //判断是否正在选择
    isSelecting:function (x,y) {
      var cudeSelectingData = this.cudeSelecting.data;
      for(var i = 0, len = cudeSelectingData.length; i < len; i++){
          var coord = cudeSelectingData[i];
          if(parseInt(coord.x) === parseInt(x) && parseInt(coord.y) === parseInt(y)){
              return true;
          }
      }
      return false;
    },
    //判断是否已经选择
    isSelected:function (x,y) {
      var list = this.data.cudeSelected;
      for(var i=0;i<list.length;i++){
        var data = list[i].data;
        for(var j=0;j<data.length;j++){
          var coord = data[j];
          if(parseInt(coord.x) === parseInt(x) && parseInt(coord.y) === parseInt(y)){
              return true;
          }
        }
      }
      return false;
    },
    // 删除并分解当前模块
    cubeSelectedDel(index){
      this.$confirm('确认删除?')
      .then(_ => {
        this.data.cudeSelected.splice(index,1);
      })
      .catch(_ => {});
    },
    //计算选中层的宽度
    getCubeSelectedWidth:function (item) {
      return (parseInt(item.end.y) - parseInt(item.start.y) + 1) * this.cubeItemWidth;
    },
    //计算选中层的高度
    getCubeSelectedHeight:function (item) {
      return (parseInt(item.end.x) - parseInt(item.start.x) + 1) * this.cubeItemHeight;
    },
    //计算选中层的右边距离
    getCubeSelectedTop:function (item) {
      return (item.start.x-1) * this.cubeItemHeight;
    },
    //计算选中层的左边距离
    getCubeSelectedLeft:function (item) {
      return (item.start.y-1) * this.cubeItemWidth;
    },
    
  }

}
</script>

<style lang="scss">
.rowncolnParam {
  // text-align: center;
  h4 {
    color: #444;
  }
}

.decorate-cube {
  width: 375px;
  height: 375px;
  position: relative;
}
.decorate-cube .cube-row:last-of-type .cube-item {
  border-right: 1px solid #e5e5e5;
}
.decorate-cube .cube-selected {
  position: absolute;
  background-color: #fff;
  border: 1px solid #ebedf0;
  text-align: center;
  color: #7d7e80;
  cursor: pointer;
  box-sizing: border-box;
  overflow: hidden;
}
// 添加的图片
.cube-selected img{
  width: 100%;
}
.decorate-cube .cube-selected.cube-selected-click {
  background: #e0edff;
  border: 1px solid #155bd4;
  color: #155bd4;
  z-index: 2;
  cursor: auto;
}
.decorate-cube .cube-selected-text {
  font-size: 20px;
  width: 100%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translateX(-50%) translateY(-50%);
}

// 删除
.cube-selected-del{
  text-align: center;
  width: 12px;
  height: 12px;
  color: #f3704b;
  line-height: 9px;
  font-size: 2px;
  border-radius: 50%;
  border: 0.5px solid #f3704b;
  position: absolute;
  top: 0px;
  right: 5px;
  display: none;
}
.cube-selected:hover  .cube-selected-del{
  display: block;
}


.decorate-cube .cube-row {
  float: left;
  list-style: none;
  padding: 0;
  margin: 0;
}
.decorate-cube .cube-item:first-child {
  border-top: 1px solid #e5e5e5;
}
.decorate-cube .cube-item {
  background: #f8f8f8;
  border-left: 1px solid #e5e5e5;
  border-bottom: 1px solid #e5e5e5;
  cursor: pointer;
  text-align: center;
  box-sizing: border-box;
}
.decorate-cube .cube-item.item-selecting {
  background: #e0edff;
}
.decorate-cube .cube-item.item-selecting .van-icon {
  display: none;
}
.decorate-cube .cube-item.item-selected {
  background: #e0edff;
  visibility: hidden;
}
.decorate-cube .cube-item.item-selected .van-icon {
  display: none;
}
</style>

上述资料是多人分享出的基础上更改的

其他小插件后续我会打包分享出来的,有问题的朋友也可私信我

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值