Maison  >  Article  >  interface Web  >  Explication détaillée de l'instruction Vue personnalisée v-selectable similaire à jQuery UI Selectable

Explication détaillée de l'instruction Vue personnalisée v-selectable similaire à jQuery UI Selectable

小云云
小云云original
2018-05-17 16:37:032499parcourir

Cet article présente principalement les informations pertinentes sur la personnalisation de l'instruction Vue v-selectable similaire à jQuery UI Selectable. Les amis dans le besoin peuvent s'y référer. J'espère que cela pourra aider tout le monde.

Sans plus tarder, regardons d’abord l’effet.

En fait, c'est une fonction qui vous permet de maintenir la souris enfoncée pour sélectionner des éléments dans une zone. Je crois que tous ceux qui ont utilisé Jquery UI savent qu'il s'agit d'un. fonction sélectionnable.Cependant, si nous utilisons Vue, il n'y a pas de plug-in similaire pour le développement. Bien sûr, vous pouvez toujours utiliser jquery directement, mais je ne veux pas introduire jquery et jquery UI dans mon projet, j'ai donc essayé de l'implémenter. fonctions similaires moi-même.

Il y a deux étapes pour mettre en œuvre cette fonction. La première étape consiste à implémenter la fonction de zone de sélection de la souris, et la deuxième étape consiste à ajouter une classe active à l'élément sélectionné dans cette zone.

Voyons d'abord comment dessiner un cadre en pointillés en maintenant la souris enfoncée. L'idée est d'abord de changer le positionnement de l'élément conteneur en relatif, puis de déterminer quand la souris est enfoncée (mousedown) pour mémoriser le. position du point de clic (e .layerX, e.layerY), puis surveillez la position de la souris (e.layerX, e.layerY) en temps réel lorsque la souris bouge (mousemove). Avec ces deux positions, vous pouvez créer dynamiquement. a p et son positionnement Pour absolu, puis ajoutez-le à la boîte conteneur et effacez la boîte précédente à chaque fois. Pourquoi utiliser e.layerX e.layerY,

layerX layerY

Si le style de position de l'élément n'est pas le statique par défaut, nous disons ces éléments ont des attributs de positionnement.

Trouvez l'élément le plus proche avec l'attribut de positionnement parmi l'élément qui déclenche actuellement l'événement de souris et son élément ancêtre, calculez la valeur de décalage de la souris par rapport à lui et trouvez le point diplomatique du coin supérieur gauche de la bordure de l'élément comme point relatif. Si un élément avec un attribut de positionnement n'est pas trouvé, le décalage est calculé par rapport à la page actuelle, ce qui équivaut à pageY. Suivez cette idée pour compléter le code suivant :

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('p')
          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
  })
}

A ce moment, vous pouvez obtenir l'effet de dessiner un cadre en pointillés

L'étape suivante est la façon de définir chaque élément est sélectionné. L'idée est de parcourir tous les éléments enfants li de ce conteneur ul, puis de déterminer si chaque li se trouve à l'intérieur de la boîte sélectionnée. Regardez ensuite offsetLeft et offsetTop de chaque élément pour calculer la position de l'élément par rapport à l'élément parent, puis déterminez la largeur et la hauteur de l'élément enfant via getBoundingClientRect().height et getBoundingClientRect().width. Ceux-ci peuvent calculer la position et la taille de l'élément, puis comment déterminer si l'élément se trouve dans la zone de sélection ? Ma règle est que si l'un des quatre coins de cet élément se trouve dans la zone de sélection ou si la zone de sélection se trouve à l'intérieur de cette zone, l'élément est considéré comme sélectionné (cette méthode de jugement ne semble pas parfaite). En suivant cette idée, continuez à compléter notre code :

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('p')
   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(&#39;active&#39;)
   }else{
   children[i].classList.remove(&#39;active&#39;)
   }
  }
  }
 })
 ele.addEventListener(&#39;mouseup&#39;, function(e) {
  isMouseDown = false
  if(areaSelect && areaSelect.childNodes && ele.contains(areaSelect)){
  ele.removeChild(areaSelect)
  }
  areaSelect = null
 })
 }
 Vue.directive(&#39;selectable&#39;,{
 inserted:listener,
 updated:listener
 })
}

Une fois terminé, voyons comment l'utiliser la structure 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>

Notez que le v-selectable de ul est. notre commande personnalisée, mais vous devez Vue.use

import Vue from &#39;vue&#39;
import Selectable from &#39;@/components/vue-selectable/vue-selectable.js&#39; //这个修改为你的js路径
Vue.use(Selectable);

avant de l'utiliser. Ajoutez du style à notre ul li Notez que notre élément sélectionné sera ajouté avec une classe active, à travers laquelle nous pouvons changer. le style de l'article sélectionné

<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>

De cette façon, l'effet du début peut être obtenu. En fait, il y a encore de nombreux petits bugs dans le processus d'exécution du code. Cet article ne fournit qu'une idée et un code simples. Vous pouvez modifier le code et ajouter plus de fonctions par vous-même. Si vous ne comprenez pas pourquoi cette instruction personnalisée est écrite ainsi, vous pouvez vous référer à mon autre article sur la personnalisation du plug-in d'image à chargement différé v-lazyload.

Recommandations associées :

Tutoriel de développement du framework Yii Composant Zii - Exemple sélectionnable_Tutoriel PHP

Tutoriel de développement du framework Yii Composant Zii - Exemple sélectionnable

sélectionnable

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn