国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

自定義類似于jQuery UI Selectable 的Vue指令v-selectable

2019-11-19 15:42:17
字體:
來源:轉載
供稿:網友

話不多說,先看效果。

  其實就是一個可以按住鼠標進行一個區域內條目選擇的功能,相信用過Jquery UI 的都知道這是selectable的功能,然而我們如果用Vue開發的話沒有類似的插件,當然你仍然可以把jquery的拿過來直接用,但是我又不想引入jquery 和 jquery UI在我的項目中,于是我就自己嘗試著實現類似的功能。

  要實現這個功能分兩步。第一步是實現鼠標選擇區域的功能,第步部是把這個區域內被選擇的item添加一個active的類。

  先看如何實現按住鼠標畫虛線框,思路是先把容器元素的定位改為relative 然后判斷當鼠標按下(mousedown)的時候,進行記住這個點擊點的位置(e.layerX , e.layerY),然后鼠標移動(mousemove)的時候,實時的監測鼠標的位置(e.layerX , e.layerY),有了這兩個位置就可以動態的創建一個div,它的定位為absolute,然后把它添加的容器框里,并且每次清空前一個框就可以了。為什么是用e.layerX e.layerY呢,

layerX layerY

         如果元素的position樣式不是默認的static,我們說這個元素具有定位屬性。

         在當前觸發鼠標事件的元素和它的祖先元素中找到最近的具有定位屬性的元素,計算鼠標與其的偏移值,以找到元素的border的左上角的外交點作為相對點。如果找不到具有定位屬性的元素,那么就相對于當前頁面計算偏移,此時等同于pageY。按照這個思路完成以下代碼:

export default (Vue, options = {}) =>{  const listener = (ele, binding) =>{    let reactArea = {      startX: 0,      startY: 0,      endX: 0,      endY: 0    }    //是否一直按下鼠標    let isMouseDown = false    let areaSelect = {}    //將元素定位改為relative    ele.style.position = 'relative'    ele.addEventListener('mousedown', function(e) {      reactArea.startX = e.layerX;      reactArea.startY = e.layerY;      isMouseDown = true    })    ele.addEventListener('mousemove', function(e) {      if(isMouseDown){        let preArea = ele.getElementsByClassName('v-selected-area')        if(preArea.length){          ele.removeChild(preArea[0])        }        reactArea.endX = e.layerX        reactArea.endY = e.layerY        let leftValue = 0        let topValue = 0        let widthValue = Math.abs(reactArea.startX - reactArea.endX)        let heightValue = Math.abs(reactArea.startY - reactArea.endY)        if(reactArea.startX >= reactArea.endX){          leftValue = reactArea.endX        }else{          leftValue = reactArea.startX        }        if(reactArea.startY > reactArea.endY ){          topValue = reactArea.endY        }else{          topValue = reactArea.startY        }        //判斷同時有寬高才開始畫虛線框        if(reactArea.startX != reactArea.endX && reactArea.startY !=reactArea.endY){          areaSelect = document.createElement('div')          areaSelect.classList.add("v-selected-area")          areaSelect.style.position = "absolute";          areaSelect.style.left = leftValue + 'px'          areaSelect.style.top = topValue + 'px'          areaSelect.style.width = widthValue + 'px'          areaSelect.style.height = heightValue + 'px'          areaSelect.style.border = "1px dashed grey"          ele.append(areaSelect)        }      }    })    ele.addEventListener('mouseup', function(e) {      isMouseDown = false      //每次鼠標點擊完了areaSelect      if(areaSelect && areaSelect.childNodes && ele.contains(areaSelect)){        ele.removeChild(areaSelect)      }      areaSelect = null    })  }   Vue.directive('selectable',{    inserted:listener,    updated:listener  })}

  這個時就可以實現畫虛線框的效果

  下一步是如何把每個item置為選中狀態。思路是遍歷這個容器ul 的所有子元素li ,然后判斷每個li是否在選中的框內部。然后看每個元素的offsetLeft 和 offsetTop 計算元素相對于父元素的位置,然后通過getBoundingClientRect().height 和 getBoundingClientRect().width 確定子元素的寬高。這些就可以計算出元素的位置和大小了,然后如何判斷這個元素是否在選擇區域內呢?我的規則是這個元素的四個角位置有任何一個在選擇區域內或者選擇區域就在這個區域的內部,就算是這個元素被選中了(這個判斷方式感覺不是很完美)。按照這個思路,繼續完成我們的代碼:

export default (Vue, options = {}) =>{ const listener = (ele, binding) =>{ let reactArea = {  startX: 0,  startY: 0,  endX: 0,  endY: 0 } //是否一直按下鼠標 let isMouseDown = false let areaSelect = {} //將元素定位改為relative ele.style.position = 'relative' ele.addEventListener('mousedown', function(e) {  reactArea.startX = e.layerX;  reactArea.startY = e.layerY;  isMouseDown = true }) ele.addEventListener('mousemove', function(e) {  if(isMouseDown){   let preArea = ele.getElementsByClassName('v-selected-area')  if(preArea.length){   ele.removeChild(preArea[0])  }  reactArea.endX = e.layerX  reactArea.endY = e.layerY  let leftValue = 0  let topValue = 0  let widthValue = Math.abs(reactArea.startX - reactArea.endX)  let heightValue = Math.abs(reactArea.startY - reactArea.endY)  if(reactArea.startX >= reactArea.endX){   leftValue = reactArea.endX  }else{   leftValue = reactArea.startX  }  if(reactArea.startY > reactArea.endY ){   topValue = reactArea.endY  }else{   topValue = reactArea.startY  }  //判斷同時有寬高才開始畫虛線框  if(reactArea.startX != reactArea.endX && reactArea.startY !=reactArea.endY){   areaSelect = document.createElement('div')   areaSelect.classList.add("v-selected-area")   areaSelect.style.position = "absolute";   areaSelect.style.left = leftValue + 'px'   areaSelect.style.top = topValue + 'px'   areaSelect.style.width = widthValue + 'px'   areaSelect.style.height = heightValue + 'px'   areaSelect.style.border = "1px dashed grey"   ele.append(areaSelect)  }  let children = ele.getElementsByTagName('li')  for(let i =0 ; i < children.length ; i ++ ){   let childrenHeight = children[i].getBoundingClientRect().height   let childrenWidth = children[i].getBoundingClientRect().width   //每個li元素的位置   let offsetLeft = children[i].offsetLeft   let offsetTop = children[i].offsetTop   //每個li元素的寬高   let endPositionH = childrenHeight + offsetTop   let endPositionW = childrenWidth + offsetLeft   //五個條件滿足一個就可以判斷被選擇   //一是右下角在選擇區域內   let require1 = endPositionH > topValue && endPositionW > leftValue && endPositionH < topValue + heightValue && endPositionW < leftValue + widthValue   //二是左上角在選擇區域內   let require2 = offsetTop > topValue && offsetLeft > leftValue && offsetTop < topValue + heightValue && offsetLeft < leftValue + widthValue   //三是右上角在選擇區域內   let require3 = offsetTop > topValue && offsetLeft + childrenWidth > leftValue && offsetTop < topValue + heightValue && offsetLeft + childrenWidth< leftValue + widthValue   //四是左下角在選擇區域內   let require4 = offsetTop + childrenHeight > topValue && offsetLeft > leftValue && offsetTop + childrenHeight < topValue + heightValue && offsetLeft < leftValue + widthValue   //五選擇區域在元素體內   let require5 = offsetTop < topValue && offsetLeft < leftValue && offsetTop + childrenHeight > topValue + heightValue && offsetLeft + childrenWidth > leftValue + widthValue   if(require1 || require2 || require3 || require4 || require5){   children[i].classList.add('active')   }else{   children[i].classList.remove('active')   }  }  } }) ele.addEventListener('mouseup', function(e) {  isMouseDown = false  if(areaSelect && areaSelect.childNodes && ele.contains(areaSelect)){  ele.removeChild(areaSelect)  }  areaSelect = null }) } Vue.directive('selectable',{ inserted:listener, updated:listener })}

完成之后再看看如何使用,html 結構:

<ul v-selectable >  <li class="square"> item1  </li>  <li class="oval"> item2  </li>  <li class="triangle"> item3  </li>  <li class="triangle-topleft"> item4  </li>  <li class="curvedarrow"> item5  </li>  <li class="triangle-topleft"> item6  </li></ul>

  注意ul的這個v-selectable就是我們自定義的指令,但是使用之前必須 Vue.use

import Vue from 'vue'import Selectable from '@/components/vue-selectable/vue-selectable.js' //這個修改為你的js路徑Vue.use(Selectable); 

  再給我們的ul li 加點樣式,注意我們的被選擇項會被添加一個active的class,通過這個來改變選中項樣式

<style scoped> ul{ margin: 40px 40px 40px 40px; border: 1px solid red; width: 300px; padding-bottom: 20px; } ul li { width: 200px; height: 30px; list-style: none; border: 1px solid black; margin-left: 10px; margin-top: 30px; text-align: center; line-height: 30px; user-select:none; } ul li.active{ background-color: red; }</style>

  這樣就可以達到開頭的效果了。實際上代碼運行過程中還是有許多小bug的,本文只是提供了一個簡單的思路和代碼,更多功能可以自己修改代碼進行添加。如果不明白這個自定義指令為什么是這樣的寫法,可以參考我的另一篇文章自定義懶加載圖片插件v-lazyload。

//m.survivalescaperooms.com/article/112355.htm

總結

以上所述是小編給大家介紹的自定義類似于jQuery UI Selectable 的Vue指令v-selectable,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 文昌市| 东乡| 东乌珠穆沁旗| 石柱| 怀化市| 永和县| 雅江县| 敖汉旗| 石家庄市| 灌云县| 南昌市| 明溪县| 庆安县| 邓州市| 哈尔滨市| 大兴区| 恭城| 绵竹市| 襄樊市| 讷河市| 屯门区| 通城县| 张北县| 安顺市| 霍邱县| 岳池县| 察哈| 南城县| 剑阁县| 铜梁县| 阳曲县| 曲周县| 涟水县| 太谷县| 贵德县| 北碚区| 姜堰市| 石泉县| 襄樊市| 武隆县| 澄江县|