欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

vue模块移动组件的实现示例

程序员文章站 2022-04-09 16:05:29
一直都想实现类似于五百丁中简历填写中模块跟随鼠标移动的组件,最近闲来无事,自己琢磨实现了一个差不多的组件。其中每个模块都是组件调入(项目经验、教育经验、工作经验等),所以这里也用到了动态加载组件方式。...

一直都想实现类似于五百丁中简历填写中模块跟随鼠标移动的组件,最近闲来无事,自己琢磨实现了一个差不多的组件。

vue模块移动组件的实现示例

其中每个模块都是组件调入(项目经验、教育经验、工作经验等),所以这里也用到了动态加载组件方式。

思路:鼠标移入模块,显示相应模块的点击移动按钮,点击a模块移动按钮,此时原先a模块所在的位置上变为拖动到这里绿框模块,同时鼠标下悬浮着a模块,鼠标移动,悬浮的a模块跟随移动,绿框也跟随上下移动。

父组件

1、父组件template中的代码

<div class="component-box" ref="compbox">
 <component
   v-for="(item, index) in comroute"
   :is="item"
   :key="index"
   @getdata="getdata">
</component>
 <div :class="['translate-box', {'move-icon':transtype}]"
    ref="translatebox" v-if="transtype">
  <component :is="transcom"></component>
 </div>
</div>

2、data中定义的属性

comlist: ['educationexp', 'workexp', 'projectexp'], // 模块列表
comlen: 0, // 模块的长度
comtype: '', // 当前移动的模块
transtype: '', // 当前移动的模块
coordinate: { // 鼠标坐标
 mousex: 0,
 mousey: 0,
},
downflag: false, // 当前是否点击模块移动
mouseybefore: 0, // 记录鼠标点击时y坐标以及鼠标每移动30后重新记录鼠标y坐标
mouseylast: 0, // 实时记录鼠标移动时的y坐标
nowcom: '', // 移动模块时,上一个模块或者下一个模块的名称
forflage: false, // foreach遍历结束的标识
comroute: [], // 动态加载组件列表
transcom: null, // 点击后悬浮的组件
compbox: null, // 获取当前组件在页面中的位置信息

3、scrolltop为页面滚动的距顶部的距离,从父组件传过来

props: { scrolltop: number,}

4、watch一些属性

watch: {
 comlist: { 
  handler(val) {
   this.getcom(val); // 模块列表改变时,实时加载组件
  },
  deep: true,
  immediate: true, // 声明了之后会立马执行handler里面的函数
 },
 transtype(val) { // 悬浮模块加载组件
  if (val) {
   this.transcom = () => import(`./default/${val}`);
  }
 },
 scrolltop: { // 监听页面滚动
  handler() {},
  immediate: true,
 },
 comtype(newval) {
  if (newval) {
   this.comlist.foreach((item, index) => {
    if (item === newval) {
     this.comlist[index] = 'movebox'; // 将组建列表中为comtype的元素改为movebox组件
    }
   });
   this.getcom(this.comlist);
  }
 },
 downflag(newval) { // 鼠标已经点击
  const nowthis = this;
  document.onmousemove = function (e) {
   if (newval) { // 鼠标移动赋值
    nowthis.coordinate.mousex = e.clientx;
    nowthis.coordinate.mousey = e.clienty;
   }
  };
  document.onmouseup = function () { // 鼠标松开
   document.onmousemove = null;
   if (newval) {
    nowthis.transtype = ''; // 悬浮组件置空
    nowthis.comlist.foreach((item, index) => {
     if (item === 'movebox') { // 寻找movebox所在位置
      nowthis.comlist[index] = nowthis.comtype; // 还原成点击组件
     }
    });
    nowthis.downflag = false;
    nowthis.comtype = '';
    nowthis.getcom(nowthis.comlist);
   }
  };
 },
 coordinate: {
  handler(newval) { // 悬浮组件位置
   this.$refs.translatebox.style.top = `${newval.mousey + this.scrolltop - 40 - this.compbox.y}px`;
   this.$refs.translatebox.style.left = `${newval.mousex - this.compbox.x - 200}px`;
   this.mouseylast = newval.mousey;
  },
  deep: true,
 },
 mouseylast(newval) { // 鼠标移动y坐标
  this.forflage = false; 
  if (newval - this.mouseybefore > 30) {  // 移动30鼠标向下移,每移动30,movebox移动一次
   this.comlist.foreach((item, index) => {
    if (item === 'movebox' && index < this.comlen - 1 && !this.forflage) {
     this.nowcom = this.comlist[index + 1];
     this.$set(this.comlist, index + 1, 'movebox');
     this.$set(this.comlist, index, this.nowcom);
     this.mouseybefore = newval;
     this.forflage = true;
    }
   });
  } else if (newval - this.mouseybefore < -30) {   // 鼠标向上移
   this.comlist.foreach((item, index) => {
    if (item === 'movebox' && index > 0 && !this.forflage) {
     this.nowcom = this.comlist[index - 1];
     // this.comlist[index - 1] = 'movebox';
     // this.comlist[index] = this.nowcom;
     // this.comlist[index]数组中采用这种方式赋值,vue是不能检测到数组的变动的
     this.$set(this.comlist, index - 1, 'movebox');
     this.$set(this.comlist, index, this.nowcom);
     this.mouseybefore = newval;
     this.forflage = true;
    }
   });
  }
 },
},

其中 forflage的作用是,在foreach中不能使用break这样来结束循环,所以用forflage来表示,当遍历到movebox后, 就结束遍历

5、methods

methods: {
 getcom(val) {
  this.comroute = [];
  val.foreach((item) => {
   this.comroute.push(() => import(`./default/${item}`));
  });
 },
 getdata(data, datay, datax) { // 模块组件点击后,父组件中调用此方法,并传值过来
  this.comtype = data;
  this.transtype = data;  // 目前考虑点击后立即移动,点击不移动的情况后期再考虑
  this.downflag = true;
  this.mouseybefore = datay;
  this.$nexttick(() => {
   this.$refs.translatebox.style.top = `${datay + this.scrolltop - 40 - this.compbox.y}px`;
   this.$refs.translatebox.style.left = `${datax - this.compbox.x - 200}px`;
  });
 },
},

6、mounted

mounted() {
 this.comlen = this.comlist.length;
 this.compbox = this.$refs.compbox.getboundingclientrect();
 const that = this;
 window.onresize = () => (() => {
  that.compbox = this.$refs.compbox.getboundingclientrect();
 })();
},

子组件

1、子组件template代码

<div class="pad-box hover-box name-box">
 <p class="absolute-box">
  <i class="el-icon-rank operation-icon move-icon"    @mousedown="mousedown"></i>
  <i class="el-icon-circle-plus operation-icon"></i>
  <i class="el-icon-s-tools operation-icon"></i>
 </p>
 教育经验
</div>

2、script

export default {
 name: 'educationexp',
 data() {
  return {
   comtype: 'educationexp',
   mouseybefore: 0,
   mousexbefore: 0,
  };
 },
 methods: {
  mousedown(e) {
   this.mouseybefore = e.clienty;
   this.mousexbefore = e.clientx;
   this.$emit('getdata', this.comtype, this.mouseybefore, this.mousexbefore);
  },
 },
};

到此这篇关于vue模块移动组件的实现示例的文章就介绍到这了,更多相关vue模块移动组件内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!