Vue.jsカスタムコマンド、ドラッグ可能なサスペンションを実現

5108 ワード

Vueは、内蔵命令(v-show、v-forなど)のようなカスタム命令を独自に開発することをサポートしています.通常、最下位のDOM操作の場所で使用されます.本稿では,カスタム命令の基本的な使い方を簡単に紹介し,命令v−dragによるサスペンションドラッグ機能を実現する.
一、基本用法
1)登録
同様のコンポーネントでは、コマンドの登録は、グローバル登録とローカル登録に分けることもできます.名前の通り、グローバル登録はプロジェクトの下のすべてのVueコンポーネントで使用でき、ローカル登録は現在のVueコンポーネントでのみ使用できます.カスタムコンポーネント登録には、コマンド名、コマンドオプションの2つのパラメータが必要です.
簡単なfocusコマンドを例に挙げます.
//     
Vue.directive('focus', {
  inserted: function (el) {
    el.focus()
  }
})
//     
var vm = new Vue({
  el: '#app',
  directives: {
    focus: {
      //     
      inserted: function (el) {
        el.focus()
      }
    }
  }
})

上記の例は、コマンドバインドの要素がdomに挿入されたときに自動的にフォーカスを取得するカスタムコマンドです.
コマンド名は「focus」、コマンドオプションはオブジェクトで、組み込みコマンドと同様に接頭辞「v-」を付ける必要があります.

次に、コマンド構成オプションについて詳しく説明します.
2)指令配置オプション
命令構成オプションは、実際にはいくつかのフック関数を含むオブジェクトであり、各オプションはフック関数であり、オプションのフックであり、前例focus命令の「inserted」はフック関数である.オプションのフック関数は次のとおりです(Vue公式サイトより抜粋).
 
  • bind:1回のみ呼び出し、命令が初めてエレメントにバインドされたときに呼び出されます.ここでは、一度に初期化設定を行うことができます.
  • inserted:バインドされた要素が親ノードに挿入されたときに呼び出されます(親ノードのみが存在しますが、ドキュメントに挿入されたとは限りません).
  • update:あるコンポーネントのVNode更新時に呼び出されますが、そのサブVNode更新の前に発生する場合があります.命令の値が変わったかもしれないし、なかったかもしれない.ただし、更新前後の値を比較することで、不要なテンプレート更新を無視できます(詳細なフック関数パラメータは下を参照).
  • componentUpdated:命令が存在するコンポーネントのVNodeおよびそのサブVNodeが全て更新されて呼び出される.
  • unbind:1回のみ呼び出し、命令と要素の結合解除時に呼び出す.

  • 各フック関数には、「focus」コマンドでelが使用されるなど、同じパラメータ(すなわちelbindingvnode・)が使用できます.これらの意味は以下の通りです(Vue公式サイトより抜粋).
     
  • oldVnode:コマンドにバインドされた要素は、DOMを直接操作するために使用できます.
  • el:次の属性を持つオブジェクト:
  • binding:命令名、含まないname接頭辞.
  • v-:命令のバインド値、例えば:valueで、バインド値はv-my-directive="1 + 1"です.
  • 2:命令バインドの前の値は、oldValueおよびupdateフックのみで使用可能です.値が変更されるかどうかにかかわらず使用できます.
  • componentUpdated:文字列形式の命令式.例えばexpressionでは、式はv-my-directive="1 + 1"です.
  • "1 + 1":命令に渡すパラメータは、オプションです.例えばargでパラメータはv-my-directive:fooです.
  • "foo":修飾子を含むオブジェクト.例えば、modifiersのうち、修飾子の対象はv-my-directive.foo.barである.

  • { foo: true, bar: true }:Vueコンパイルにより生成された仮想ノード.
  • vnode:前の仮想ノードは、oldVnodeおよびupdateフックのみで使用可能です.

  • 二、ドラッグ可能なサスペンションを実現する
    1)実現効果(ここで体験できる):
    2)指令配置項目コードは大体以下の通りである:
    function inserted (el, binding, vNode) {
      el.setAttribute('style', 'position: fixed; z-index: 9999')
    }
    
    function bind (el, bindding, vNode) {
      el.setAttribute('draggable', true)
      let left, top, width, height
      el._dragstart = function (event) {
        event.stopPropagation()
        left = event.clientX - el.offsetLeft
        top = event.clientY - el.offsetTop
        width = el.offsetWidth
        height = el.offsetHeight
      }
      el._checkPosition = function () { //        
        let width = el.offsetWidth
        let height = el.offsetHeight
        let left = Math.min(el.offsetLeft, document.body.clientWidth - width)
        left = Math.max(0, left)
        let top = Math.min(el.offsetTop, document.body.clientHeight - height)
        top = Math.max(0, top)
        el.style.left = left + 'px'
        el.style.top = top + 'px'
        el.style.width = width + 'px'
        el.style.height = height + 'px'
      }
      el._dragEnd = function (event) {
        event.stopPropagation()
        left = event.clientX - left
        top = event.clientY - top
        el.style.left = left + 'px'
        el.style.top = top + 'px'
        el.style.width = width + 'px'
        el.style.height = height + 'px'
        el._checkPosition()
      }
      el._documentAllowDraop = function (event) {
        event.preventDefault()
      }
      document.body.addEventListener('dragover', el._documentAllowDraop)
      el.addEventListener('dragstart', el._dragstart)
      el.addEventListener('dragend', el._dragEnd)
      window.addEventListener('resize', el._checkPosition)
    }
    
    function unbind (el, bindding, vNode) {
      document.body.removeEventListener('dragover', el._documentAllowDraop)
      el.removeEventListener('dragstart', el._dragstart)
      el.removeEventListener('dragend', el._dragEnd)
      window.removeEventListener('resize', el._checkPosition)
      delete el._documentAllowDraop
      delete el._dragstart
      delete el._dragEnd
      delete el._checkPosition
    }
    
    export default {
      bind,
      unbind,
      inserted
    }
    

     
    3)使用(事前登録が必要):
     
    
    
    
    export default {
    }