成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

vue實(shí)現(xiàn)移動(dòng)端touch拖拽排序

3403771864 / 1090人閱讀

  在vue中實(shí)現(xiàn)移動(dòng)端touch拖拽排序的具體代碼,如下內(nèi)容:

  功能介紹:

  在移動(dòng)端開發(fā)中,希望實(shí)現(xiàn)類似支付寶應(yīng)用管理頁(yè)面的可拖拽排序交互。

  大致需求:

  1、卡片按照一定順序排序,超出橫向范圍換行顯示;

  2、手指長(zhǎng)按卡片,可進(jìn)行拖拽控制,卡片追隨手指移動(dòng);

  3、卡片移動(dòng)到相應(yīng)位置,該位置上的卡片向后或向前更換位置,當(dāng)前位置空出;

  4、松開手指,卡片可回到原位置或新位置進(jìn)行展示;

  整體思路:

  1、卡片實(shí)行flex彈性布局,通過(guò)數(shù)組的遍歷可自動(dòng)顯示在相應(yīng)位置;

  2、手指長(zhǎng)按可使用定時(shí)器來(lái)判斷,若手指松開,則關(guān)閉定時(shí)器,等待下次操作再啟用;

  3、跟隨手指移動(dòng)的卡片可使用absolute定位控制,同時(shí)根據(jù)手指位置判斷當(dāng)前所在位置;

  4、位置發(fā)生改變時(shí),控制數(shù)組添加或刪除相應(yīng)元素,從而實(shí)現(xiàn)換位效果;

  簡(jiǎn)單效果展示:

  具體實(shí)現(xiàn):

  一、display:flex+v-for布局:

  使用彈性布局實(shí)現(xiàn)

  <!-- 外層ul控制卡片范圍 -->
  <ul>
  <li class="libox" v-for="(item, ind) in list" :key="ind">
  <div>
  <!-- div顯示數(shù)組內(nèi)容 -->
  {{item.name}}
  </div>
  </li>
  </ul>


  data() {
  return {
  list: [
  { name: '1' }, // 卡片內(nèi)容
  { name: '2' },
  { name: '3' }
  ]
  }
  },


  ul {
  width: 100%;
  height: 100%;
  display: flex; // 彈性布局
  flex-wrap: wrap;
  overflow: hidden; // 超出部分隱藏,目的阻止橫向滾動(dòng)
  .libox {
  width: 25%; // 這里以4列為例
  height: 70px;
  >div {
  background-color:#eee;
  width: calc(100% - 10px);
  height: 36px;
  border-radius: 18px;
  }
  }
  }

  二、touch事件綁定:

  應(yīng)用到touchstart,touchmove,touchend事件,使用定時(shí)器實(shí)現(xiàn)長(zhǎng)按效果:

  <div
  @touchstart="touchstart($event, item)"
  @touchmove="touchMove($event, item)"
  @touchend="touchEnd($event, item)"
  >
  {{item.name}}
  </div>

 

 

 data() {
  return {
  timeOutEvent: 0
  };
  },
  methods: {
  // 手指觸摸事件
  touchstart(ev, item) {
  // 定時(shí)器控制長(zhǎng)按時(shí)間,超過(guò)500毫秒開始進(jìn)行拖拽
  this.timeOutEvent = setTimeout(() => {
  this.longClick = 1;
  }, 500);
  },
  // 手指在屏幕上移動(dòng)
  touchMove(ev) {
  // 未達(dá)到500毫秒就移動(dòng)則不觸發(fā)長(zhǎng)按,清空定時(shí)器
  clearTimeout(this.timeOutEvent);
  },
  // 手指離開屏幕
  touchEnd() {
  clearTimeout(this.timeOutEvent);
  }
  }

  三、卡片移動(dòng):

  在ul中增加一個(gè)獨(dú)立的不在循環(huán)中的li標(biāo)簽,改為absolute定位,通過(guò)動(dòng)態(tài)修改li標(biāo)簽top、left屬性實(shí)現(xiàn)跟隨手指移動(dòng)效果。

  <ul>
  <li v-show="selectItem.name" class="selectBox" ref="selectBox">
  {{selectItem.name}}
  </li>
  </ul>


  ul {
  position: relative;
  // 此li標(biāo)簽的樣式與循環(huán)li標(biāo)簽內(nèi)的div樣式保持一致
  // 背景色加深,代表被手指選中
  .selectBox {
  position: absolute;
  width: calc(25% - 10px);
  height: 36px;
  border-radius: 18px;
  background-color:#6981c8;
  color:white;
  }
  }

  當(dāng)卡片被選中,將卡片內(nèi)容賦值給全局變量,判斷卡片顯示隱藏(v-show判斷,隱藏但占位),實(shí)現(xiàn)選中元素位置空出效果:

  手指位置通過(guò)touchmove獲?。?/p>

  <div
  @touchstart="touchstart($event, item)"
  @touchmove="touchMove($event, item)"
  @touchend="touchEnd($event, item)"
  @click="listClickHandler(item)"
  v-show="item.name !== selectItem.name"
  >
  {{item.name}}
  </div>


  touchstart(ev, item) {
  this.timeOutEvent = setTimeout(() => {
  this.longClick = 1;
  this.selectItem = item; // 將卡片內(nèi)容賦值給全局變量
  const selectDom = ev.target; // li元素
  // 元素初始位置
  this.oldNodePos = {
  x: selectDom.offsetLeft,
  y: selectDom.offsetTop
  };
  // 鼠標(biāo)原始位置
  this.oldMousePos = {
  x: ev.touches[0].pageX,
  y: ev.touches[0].pageY
  };
  const lefts = this.oldMousePos.x - this.oldNodePos.x; // x軸偏移量
  const tops = this.oldMousePos.y - this.oldNodePos.y; // y軸偏移量
  const { pageX, pageY } = ev.touches[0]; // 手指位置
  this.$refs.selectBox.style.left = `${pageX - lefts}px`;
  this.$refs.selectBox.style.top = `${pageY - tops}px`;
  }, 500);
  },
  touchMove(ev) {
  clearTimeout(this.timeOutEvent);
  // this.longClick === 1判斷是否長(zhǎng)按
  if (this.longClick === 1) {
  const selectDom = ev.target.parentNode; // li元素
  const lefts = this.oldMousePos.x - this.oldNodePos.x; // x軸偏移量
  const tops = this.oldMousePos.y - this.oldNodePos.y; // y軸偏移量
  const { pageX, pageY } = ev.touches[0]; // 手指位置
  this.$refs.selectBox.style.left = `${pageX - lefts}px`;
  this.$refs.selectBox.style.top = `${pageY - tops}px`;
  }
  }

  四、獲取手指所在位置:


  cardIndex(selDom, moveleft, movetop) {
  const liWid = selDom.clientWidth; // li寬度
  const liHei = selDom.clientHeight; // li高度
  const newWidNum = Math.ceil((moveleft / liWid)); // 手指所在列
  const newHeiNum = Math.ceil((movetop / liHei)); // 手指所在行
  const newPosNum = (newHeiNum - 1) * 4 + newWidNum; // 手指所在位置
  // 判斷是否是新位置并且沒(méi)有超出列表數(shù)量范圍
  if (this.oldIndex !== newPosNum &&
  newPosNum <= this.list.length) {
  // 將新的位置賦值給全局變量oldIndex
  this.oldIndex = newPosNum;
  }
  }

  五、操作數(shù)組(刪除或插入元素):

  監(jiān)聽oldIndex的值,若發(fā)生改變則執(zhí)行操作數(shù)組函數(shù)

  watch: {
  oldIndex(newVal) {
  const oldIndex = this.list.indexOf(this.selectItem);
  this.list.splice(oldIndex, 1);
  this.list.splice(newVal - 1, 0, this.selectItem);
  }
  },

  六、手指離開屏幕:

  手指離開屏幕,清空選中的元素selectItem,跟隨手指移動(dòng)的卡片(li.selectBox)自動(dòng)隱藏,在循環(huán)中隱藏的卡片(li)則會(huì)顯示,實(shí)現(xiàn)換位效果。

  touchEnd() {
  clearTimeout(this.timeOutEvent);
  this.selectItem = {};
  }

  七、備注:

  上面的代碼是基于div容器內(nèi)只有文字沒(méi)有其他dom元素實(shí)現(xiàn),后發(fā)現(xiàn)若div中存在dom元素例如svg,則【$event】選中的值會(huì)變成其子元素,且拖拽排序出現(xiàn)問(wèn)題,希望知道原因的小伙伴可以評(píng)論或私信告訴我一下,非常感謝。

  粗暴的解決方式:

  div容器增加after蒙版,可設(shè)置為透明色:


  div
  position: relative;
  &::after {
  content: '';
  width: 100%;
  height: 100%;
  background: rgba(255, 177, 177, 0.3); // 背景色
  position: absolute;
  top: 0;
  left: 0;
  }
  }

  八、完整代碼:

  <template>
  <div>
  <ul>
  <li
  class="libox"
  v-for="(item, index) in list"
  :key="index"
  :id="'card' + (index + 1)"
  >
  <div
  @touchstart="touchstart($event, item)"
  @touchmove="touchMove($event, item)"
  @touchend="touchEnd($event, item)"
  v-show="item.name !== selectItem.name"
  >
  {{item.name}}
  <svg class="icon svg-icon" aria-hidden="true">
  <use :xlink:href="item.icon" rel="external nofollow" ></use>
  </svg>
  </div>
  </li>
  <li v-show="selectItem.name" class="selectBox" ref="selectBox">
  {{selectItem.name}}
  <svg class="icon svg-icon" aria-hidden="true">
  <use :xlink:href="selectItem.icon" rel="external nofollow" ></use>
  </svg>
  </li>
  </ul>
  </div>
  </template>
  <script>
  export default {
  data() {
  return {
  // 列表數(shù)據(jù)
  list: [
  { name: '1', selected: true, icon: '#icon-mianxingbenzivg' },
  { name: '2', selected: true, icon: '#icon-mianxingchizi' },
  { name: '3', selected: true, icon: '#icon-mianxingdiannao' },
  { name: '4', selected: true, icon: '#icon-mianxingdayinji' },
  { name: '5', selected: true, icon: '#icon-mianxingdingshuqi' },
  { name: '6', selected: true, icon: '#icon-mianxingheiban' },
  { name: '7', selected: true, icon: '#icon-mianxinggangbi' },
  { name: '8', selected: true, icon: '#icon-mianxingboshimao' },
  { name: '9', selected: true, icon: '#icon-mianxingjisuanqi' },
  { name: '10', selected: true, icon: '#icon-mianxinghuaxue' },
  { name: '11', selected: true, icon: '#icon-mianxingqianbi' },
  { name: '12', selected: true, icon: '#icon-mianxingshubao' },
  { name: '13', selected: true, icon: '#icon-mianxingshuicaibi' },
  { name: '14', selected: true, icon: '#icon-mianxingtushu' },
  ],
  // 選中元素內(nèi)容
  selectItem: {},
  timeOutEvent: 0,
  oldNodePos: {
  x: 0,
  y: 0,
  },
  oldMousePos: {
  x: 0,
  y: 0
  },
  oldIndex: 0,
  // 長(zhǎng)按標(biāo)識(shí)
  longClick: 0
  };
  },
  watch: {
  oldIndex(newVal) {
  const oldIndex = this.list.findIndex(r=> r.name === this.selectItem.name);
  this.list.splice(oldIndex, 1);
  this.list.splice(newVal, 0, this.selectItem);
  }
  },
  methods: {
  touchstart(ev, item) {
  this.longClick = 0;
  const that = this;
  const selectDom = ev.currentTarget; // div元素
  this.timeOutEvent = setTimeout(() => {
  that.longClick = 1;
  that.selectItem = item;
  // 元素初始位置
  that.oldNodePos = {
  x: selectDom.offsetLeft,
  y: selectDom.offsetTop
  };
  // 鼠標(biāo)原始位置
  that.oldMousePos = {
  x: ev.touches[0].pageX,
  y: ev.touches[0].pageY
  };
  const lefts = that.oldMousePos.x - that.oldNodePos.x; // x軸偏移量
  const tops = that.oldMousePos.y - that.oldNodePos.y; // y軸偏移量
  const { pageX, pageY } = ev.touches[0]; // 手指位置
  that.$refs.selectBox.style.left = `${pageX - lefts}px`;
  that.$refs.selectBox.style.top = `${pageY - tops}px`;
  }, 500);
  },
  touchMove(ev) {
  clearTimeout(this.timeOutEvent);
  const selectDom = ev.currentTarget.parentNode; // li元素
  if (this.longClick === 1) {
  const lefts = this.oldMousePos.x - this.oldNodePos.x; // x軸偏移量
  const tops = this.oldMousePos.y - this.oldNodePos.y; // y軸偏移量
  const { pageX, pageY } = ev.touches[0]; // 手指位置
  this.$refs.selectBox.style.left = `${pageX - lefts}px`;
  this.$refs.selectBox.style.top = `${pageY - tops}px`;
  this.cardIndex(selectDom, pageX, pageY);
  }
  },
  touchEnd() {
  clearTimeout(this.timeOutEvent);
  this.selectItem = {};
  },
  /**
  * 計(jì)算當(dāng)前移動(dòng)卡片位于卡片的哪一行哪一列
  */
  cardIndex(selDom, moveleft, movetop) {
  const liWid = selDom.clientWidth;
  const liHei = selDom.clientHeight;
  const newWidthNum = Math.ceil((moveleft / liWid)); // 哪一列
  const newHeightNum = Math.ceil((movetop / liHei)); // 哪一行
  const newPositionNum = (newHeightNum - 1) * 4 + newWidthNum;
  if (this.oldIndex !== newPositionNum - 1) {
  if (newPositionNum <= this.list.length) {
  this.oldIndex = newPositionNum - 1;
  } else {
  this.oldIndex = this.list.length - 1;
  }
  }
  }
  }
  }
  </script>
  <style scoped>
  @mixin myFlexCenter{
  display: flex;
  justify-content: center;
  align-items: center;
  }
  ul {
  width: 100%;
  height: 100%;
  display: flex;
  flex-wrap: wrap;
  position: relative;
  overflow: hidden;
  .libox {
  width: 25%;
  height: 100px;
  border-right: 1px dashed #cccccc;
  border-bottom: 1px dashed #cccccc;
  box-sizing: border-box;
  @include myFlexCenter;
  >div {
  width: calc(100% - 10px);
  height: 75px;
  border-radius: 18px;
  @include myFlexCenter;
  position: relative;
  &::after {
  content: '';
  width: 100%;
  height: 100%;
  background: rgba(255, 177, 177, 0.3);
  position: absolute;
  top: 0;
  left: 0;
  }
  >svg {
  width: 75px;
  height: 75px;
  }
  }
  }
  .selectBox{
  position: absolute;
  width: calc(25% - 10px);
  height: 75px;
  border-radius: 18px;
  >svg {
  width: 75px;
  height: 75px;
  }
  background-color: rgba(0, 0, 0, 0.1);
  color:white;
  @include myFlexCenter;
  -moz-user-select:none; /*火狐*/
  -webkit-user-select:none; /*webkit瀏覽器*/
  -ms-user-select:none; /*IE10*/
  -khtml-user-select:none; /*早期瀏覽器*/
  user-select:none;
  }
  }
  </style>

      以上是相關(guān)內(nèi)容,請(qǐng)大家多多關(guān)注。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/127703.html

相關(guān)文章

  • Vue2.0全家桶仿騰訊體育APP(Web版)

    摘要:全家桶仿騰訊體育一年一度的總決賽,相信球迷用的最多的就是騰訊體育這款,剛好上手,當(dāng)練手就把這個(gè)仿下來(lái)。這樣剛進(jìn)去的時(shí)候頁(yè)面加載時(shí)間明顯減短。可以包含任意異步操作。 Vue2.0全家桶仿騰訊體育APP 一年一度的NBA總決賽,相信球迷用的最多的就是騰訊體育這款A(yù)PP,剛好上手Vue,當(dāng)練手就把這個(gè)APP仿下來(lái)。 showImg(https://segmentfault.com/img/r...

    fnngj 評(píng)論0 收藏0
  • h5實(shí)現(xiàn)移動(dòng)圖片預(yù)覽器(一)

    摘要:最近接觸移動(dòng)端開發(fā)。自己寫一個(gè)類似微博的圖片預(yù)覽器來(lái)學(xué)習(xí)一下移動(dòng)端手勢(shì)的實(shí)現(xiàn)和的屬性的使用。在發(fā)生時(shí)將坐標(biāo)位置向減得到位移量。雙手勢(shì)單手勢(shì)雙手勢(shì)單手勢(shì)觸發(fā)移動(dòng)事件圖片放大功能的實(shí)現(xiàn)我采用了的屬性進(jìn)行縮放,并且設(shè)置來(lái)設(shè)置縮放中心位置。 最近接觸vue.js移動(dòng)端開發(fā)。自己寫一個(gè)類似微博的圖片預(yù)覽器來(lái)學(xué)習(xí)一下移動(dòng)端手勢(shì)的實(shí)現(xiàn)和css3的屬性的使用。 目標(biāo)分析 首先分析圖片預(yù)覽器的功能: 1...

    Shonim 評(píng)論0 收藏0
  • vue實(shí)現(xiàn)移動(dòng)拖拽懸浮按鈕

      移動(dòng)端拖拽懸浮按鈕如何用vue實(shí)現(xiàn),下面看看具體內(nèi)容:  功能介紹:  開發(fā)中,要考慮用戶體驗(yàn),懸浮按鈕不僅要顯示在側(cè)邊,更是可以允許隨意拖拽換位。  需求描述:  1、按鈕懸浮顯示在頁(yè)面?zhèn)冗?; ?、當(dāng)手指長(zhǎng)按左鍵按鈕,即可允許拖拽改變位置;  3、按鈕移動(dòng)結(jié)束,手指松開,計(jì)算距離左右兩側(cè)距離并自動(dòng)移動(dòng)至側(cè)邊顯示;  4、移動(dòng)至側(cè)邊后,按鈕根據(jù)具體左右兩次位置判斷改變現(xiàn)實(shí)樣式;  整體思路:...

    3403771864 評(píng)論0 收藏0
  • vue + any-touch實(shí)現(xiàn)一個(gè)iscroll ? - (1) 實(shí)現(xiàn)拖拽和滑動(dòng)動(dòng)畫

    摘要:先看本次文章先實(shí)現(xiàn)內(nèi)容拖拽和滑動(dòng)動(dòng)畫后續(xù)文章一步一步增加功能比如滾動(dòng)條下拉加載等功能說(shuō)點(diǎn)濕的其實(shí)代碼量挺大的近行還有另一個(gè)類似的庫(kù)他的代碼量和差不多因?yàn)樵矶际且粯拥拈喿x他們的代碼發(fā)現(xiàn)里面很多邏輯其實(shí)都是在做手勢(shì)判斷比如拖拽和劃還有部分元 showImg(https://segmentfault.com/img/remote/1460000018779771?w=914&h=129);...

    張紅新 評(píng)論0 收藏0
  • 使用 Drag and Drop 給Web應(yīng)用提升交互體驗(yàn)

    摘要:注意點(diǎn)在鼠標(biāo)操作拖放期間,有一些事件可能觸發(fā)多次,比如和??赏献г兀ㄗh使用,設(shè)定可拖拽元素的鼠標(biāo)游標(biāo),提升交互。在中使用拖拽中使用可以直接綁定到組件上。 什么是 Drag and Drop (拖放)? 簡(jiǎn)單來(lái)說(shuō),HTML5 提供了 Drag and Drop API,允許用戶用鼠標(biāo)選中一個(gè)可拖動(dòng)元素,移動(dòng)鼠標(biāo)拖放到一個(gè)可放置到元素的過(guò)程。 我相信每個(gè)人都或多或少接觸過(guò)拖放,比如瀏覽...

    legendmohe 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<