Vue拖拽组件开发实例

vue是一套用于构建用户界面的渐进式框架。可以用他来封装单文件组件来开发更为复杂的单页应用。 本文主要是通过封装一个拖拽组件的例子,来分析Vue组件化相关知识。

为什么选择Vue?

主要原因:对于前端开发来说,兼容性是我们必须要考虑的问题之一。我们的项目不需要兼容低版本浏览器。项目本身也是一个数据驱动型的。加之,Vue本身具有以下主要特性:

  • 使用虚拟DOM;
  • 轻量级框架;
  • 高效的数据绑定;
  • 灵活的组件系统;
  • 完整的开发生态链。

这就是我们为什么选择Vue框架的一些原因。

为什么要封装成一个Vue组件?

主要目的是可提高代码的复用性和可维护性。

  • 复用性:组件化后,一些样式和逻辑均通过配置参数的方式去差异化体现,所以参数的可配置性提高了组件的复用率和灵活性。
  • 可维护性:组件化后,组件内部的逻辑只对组件负责,外部的逻辑只通过配置参数适配,所以提高了代码的逻辑清晰度,可以快速定位代码出现问题的地方。

组件化搭建页面图示:

上图可看出,在Vue中,所谓组件化搭建页面,简单来说,页面实际上是由一个个功能独立的组件搭建而成。这些组件之间可以组合、嵌套,最终形成了我们的页面。

组件构成

下面是一个完成的组件构成:

// 组件内模板<template></template>// 组件内逻辑代码<script type="text/javascript"></script>// 组件内封装的样式<style lang="scss" scoped></style>

开发Vue移动拖拽组件为例

拖拽原理

手指在移动的过程中,实时改变元素的位置即top和left值,使元素随着手指的移动而移动。

拖拽实现

  • 始拖动时:获取到接触点相对于整个视图区的坐标 clientX,clientY;获取元素距离视图上侧和左侧的距离 initTop, initLeft;计算接触点距离元素上侧和左侧的距离 elTop=clientY-initTopelLeft=clientX-initLeft
  • 拖动过程中:通过 currTop=clientY-elTopcurrLeft=clientX-elLeft 实时获取元素距离视图上侧和左侧的距离值,并赋值给元素,使元素跟着手指的移动而动起来;
  • 拖动结束,定位元素。

Vue中的实现

使用Vue,最大的不同之处是我们几乎不去操作DOM,要充分利用Vue的数据驱动来实现拖拽功能。本例中,我们只需在垂直方向上拖动元素,所以只需考虑垂直方向的移动即可。

上图中,通过data中的dragList渲染拖拽区域列表,代码如下:

template:<div class="drag-title">拖拽可调整顺序</div><ul class="drag-list">  <li class="drag-item" v-for="(item,index) in dragList">   {{item.txt}}  </li></ul>script:export default {    data() {      return {        dragList:null      }    },    created() {      this.dragList = [        {          isDrag: false,          txt: '列表1',          isShow: false        }        ...      ]    },}

假设我们将元素从位置1拖至位置3,本质上是数组的顺序发生了改变。这就有必要提一下Vue的最大特性:数据驱动所谓的数据驱动就是当数据发生变化时,通过修改数据状态,使用户界面发生相应的改变,开发者不需要手动的去修改DOM。 Vue的数据驱动是通过MVVM这种框架来实现的,MVVM框架主要包含3个部分:ModelViewViewmodel

  • Model:数据部分;
  • View:视图部分;
  • Viewmodel:连接视图与数据的中间件。

顺着这个思路走下去,我们知道:

  • oldIndex:元素在数组中的初始索引index;
  • elHeight:单个元素块的高;
  • currTop=clientY-elTop:元素在拖动过程中距离可视区上侧距离;
  • currTop-initTop>0:得知元素是向上拖拽;
  • currTop-initTop<0:得知元素是向下拖拽。

我们以向下拖拽来说:

  • 首先,我们要在拖拽结束事件touchend中判断元素从拖动开始到拖动结束时拖动的距离。若小于某个设定的值,则什么也不做;
  • 然后,在touchmove事件中判断,若 (currTop-initTop)%elHeight>=elHeight/2成立,即当元素拖至另一个元素块等于或超过1/2的位置时,即可将元素插入到最新的位置为 newIndex=(currTop-initTop)/elHeight+oldIndex
  • 最后,若手指离开元素,那么我们在touchend事件中,通过 this.dragList.splice(oldIndex,1), this.dragList.splice(newIndex,0,item)重新调整数组顺序。页面会根据最新的dragList渲染列表。

写到这里,我们俨然已经用Vue实现了移动端的拖拽功能。但是拖拽体验并不好,接下来,我们对它进行优化。

优化点:我们希望,在元素即将可能落到的位置,提前留出一个可以放得下元素的区域,让用户更好的感知拖拽的灵活性。

方案:(方案已被验证是可行的)将li的结构做一下修改,代码如下:

  <li class="drag-item"  v-for="(item,index) in dragList"      @touchstart="touchStart"      @touchmove="touchMove(index, item, $event)"      @touchend="touchEnd">      <div class="leave-block" v-show="item.isShowUp"></div> // 向上拖拽时留空      <div class="">{{item.txt}}</div>      <div v-show="item.isShow" class="leave-block"></div> // 向下拖拽时留空  </li>
  • 拖拽开始:将元素的定位方式由static设置为absolute,z-index设置为一个较大的值,防止元素二次拖拽无效;
  • 拖拽过程中:将元素即将落入新位置的那个li下div的item.isShow设置为true,其他li下div的item.isShow均设置为false;
  • 拖拽结束:将所有li下div的item.isShow 均设置为false,将元素定位方式由absolute设置为static。

贴一段伪代码:

touchStart(e){    // 获取元素距离视口顶部的初始距离    initTop = e.currentTarget.offsetTop;    // 开始拖动时,获取鼠标距离视口顶部的距离    initClientY = e.touches[0].clientY;    // 计算出接触点距离元素顶部的距离    elTop = e.touches[0].clientY - initTop;},touchMove(index, item, e){    // 将拖拽结束时,给元素设置的static定位方式移除,防止元素二次拖拽无效    e.target.classList.remove('static');    // 给拖拽的元素设置绝对定位方式    e.target.classList.add('ab');    // 获取元素在拖拽过程中距离视口顶部距离    currTop = e.touches[0].clientY - elTop;    // 元素在拖拽过程中距离视口顶部距离赋给元素    e.target.style.top = currTop ;    // 获取元素初始位置    oldIndex = index;    // 获取拖拽元素    currItem = item;    // 若元素已经拖至区域外    if(e.touches[0].clientY > (this.dragList.length) * elHeight){      // 将元素距离上侧的距离设置为拖动区视图的高      currTop = (this.dragList.length) * elHeight;      return;    }    // 向下拖拽    if(currTop > initTop ){      // 若拖拽到大于等于元素的一半时,即可将元素插入到最新的位置      if((currTop - initTop) % elHeight>= elHeight / 2){        // 计算出元素拖到的最新位置        newIndex = Math.round((currTop - initTop) / elHeight) + index;        // 确保新元素的索引不能大于等于列表的长度        if(newIndex < this.dragList.length){          // 将所有列表留空处隐藏          for(var i = 0;i< this.dragList.length;i++){            this.dragList[i].isShow = false;          }          // 将元素即将拖到的新位置的留空展示          this.dragList[newIndex].isShow = true;        }        else {          return;        }      }    }    // 向上拖拽,原理同上    if(currTop < initTop){      ...    }},touchEnd(e){    // 若拖动距离大于某个设定的值,则按照上述,执行相关代码    if(Math.abs(e.changedTouches[0].clientY - initClientY ) > customVal){      this.dragList.splice(oldIndex, 1);      this.dragList.splice(newIndex, 0, currItem);      for(var i = 0;i< this.dragList.length;i++){        this.dragList[i].isShow = false;        this.dragList[i].isShowUp = false;      }    }    e.target.classList.remove('ab');    e.target.classList.add('static');}

优化后,如下图所示:

以上便是用Vue实现移动端拖拽组件的过程。我们知道,有些项目是需要在PC端用Vue实现此功能。这里简单提一下PC与移动端的区别如下:

  • PC端可以使用的事件组有两种:第一种:H5新特性 draggable, dragstart,drag,dragend;第二种: mousedown,mousemove,mouseup;
  • PC端获取鼠标坐标是通过 e.clientX, clientY,区别于移动端的 e.touches[0].clientX, e.touches[0].clientY

小结

本文从Vue拖拽组件开发为例,剖析Vue组件的结构、开发思路、Vue的数据驱动等,对Vue组件化的原理,进行了更深入的理解。 并将Vue实现拖拽的方案提供给大家学习研究。

P.S. 牢记一点,切勿在Vue中过多得操作DOM,要能深入理解Vue数据驱动的核心思想。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏积累沉淀

JavaScript事件

JavaScript事件 对于事件来讲,首先,我们需要了解这样几个概念:事件;事件处理程序;事件类型;事件流;事件冒泡;事件捕获;事件对象;事件模拟,事件方面的...

2566
来自专栏腾讯NEXT学位

小程序iOS客户端框架——控件事件逻辑框架与控件原生化(下)

? 小程序自发布以来,为开发者和用户提供了一种轻量级的App。作为一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或者搜一下即可打...

1604
来自专栏刘望舒

React Native入门(三)组件的Props(属性)和State(状态)

前言 在Android或者iOS开发中我们会用到很多控件,这些控件会有很多的属性、样式等等。同样的,React Native中的组件也有属性、样式和状态。 1...

20010
来自专栏知晓程序

如何「掏空」小程序的五层页面限制? | 技术宝典

1253
来自专栏Java成神之路

博客园_01_为博客园添加目录的方法总结

本文转自:作者:妙音天女    地址:http://www.cnblogs.com/xuehaoyue/p/6650533.html

1152
来自专栏hotqin888的专栏

ppt(Powerpoint)中插入swf(flash)动画方式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

1262
来自专栏从零开始学 Web 前端

从零开始学 Web 之 移动Web(五)touch事件的缺陷,移动端常用插件

我们在上面《页面分类》的项目中,对 tap 事件的处理使用的是 touch 事件处理的,因为如果使用 click 事件的话,总会有延时。

1392
来自专栏JavaEE

jQuery进阶前言

在《jQuery入门》一文中,记录了jQuery选择器、属性与样式和DOM操作等内容,本文将对jQuery的事件以及Ajax相关知识点进行讲解。接下来就一起来学...

1742
来自专栏Google Dart

AngularDart Material Design 记分卡 顶

(adsbygoogle = window.adsbygoogle || []).push({}); fun...

1414
来自专栏木头编程 - moTzxx

wx.navigateTo 跳转页面失败?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011415782/article/de...

4481

扫码关注云+社区

领取腾讯云代金券