ホームページ  >  記事  >  ウェブフロントエンド  >  jQuery UI Selectable と同様のカスタム Vue 命令 v-selectable の詳細な説明

jQuery UI Selectable と同様のカスタム Vue 命令 v-selectable の詳細な説明

小云云
小云云オリジナル
2018-05-17 16:37:032500ブラウズ

この記事では主に、jQuery UI Selectable と同様の Vue 命令 v-selectable のカスタマイズに関する関連情報を紹介します。必要な方は参考にしていただければ幸いです。

早速、まず結果を見てみましょう。

実は、Jquery UIを使ったことがある人は、マウスを押したままにして項目を選択できる機能だと思いますが、Vueで開発すると。もちろん、同様のプラグインはありません。jquery を直接使用することもできますが、jquery と jquery UI をプロジェクトに導入したくないので、同様の機能を自分で実装しようとしました。

この機能を実装するには 2 つの手順があります。最初のステップはマウス選択領域の機能を実装することであり、2 番目のステップはこの領域で選択された項目にアクティブ クラスを追加することです。

まず、マウスを押したままにして点線のフレームを描画する方法を見てみましょう。そのアイデアは、まずコンテナ要素の位置を相対的な位置に変更し、次にマウスが押されたとき (マウスダウンしたとき) を判断し、クリックされた位置を記憶することです。ポイント (e.layerX、e.layerY) を指定し、マウスが移動すると (mousemove)、マウスの位置 (e.layerX、e.layerY) がリアルタイムで監視され、これら 2 つの位置を使用して p を動的に作成できます。その位置は絶対的であり、それをコンテナボックスに追加し、毎回前のボックスをクリアするだけです。 e.layerX e.layerY、

layerX、layerY

を使用する理由 要素の位置スタイルがデフォルトの静的でない場合、この要素には位置決め属性があると言います。

現在マウスイベントをトリガーしている要素とその祖先要素の中から位置属性を持つ最も近い要素を見つけ、それに対するマウスのオフセット値を計算し、要素の境界線の左上隅の外交ポイントを相対位置として見つけます。ポイント。位置決め属性を持つ要素が見つからない場合、オフセットは現在のページを基準にして計算されます。これは 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('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
  })
}

この時点で、点線のボックスを描画する効果を実現できます

次のステップは、各項目を選択状態に設定する方法です。アイデアは、このコンテナ 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('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
 })
}

完成したら、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 を使用する必要があることに注意してください。 it

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

ul liにスタイルを追加します。選択したアイテムがアクティブなクラスで追加されることに注意してください。これを使用して、選択したアイテムのスタイルを変更します

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

この方法で、最初の効果を実現できます。実際、コードの実行プロセスにはまだ多くの小さなバグがあります。この記事では簡単なアイデアとコードのみを提供します。コードを変更して機能を追加することもできます。このカスタム命令がこのように書かれている理由がわからない場合は、遅延読み込みイメージ プラグイン v-lazyload のカスタマイズに関する私の他の記事を参照してください。

関連する推奨事項:

Yii フレームワーク開発チュートリアル Zii コンポーネント選択可能な例_PHP チュートリアル

Yii フレームワーク開発チュートリアル Zii コンポーネント選択可能な例

選択可能

以上がjQuery UI Selectable と同様のカスタム Vue 命令 v-selectable の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。