Some practical examples of custom directives

Remember to import Vue from ‘Vue’.

1. El-dialog can be dragged

/ / directive code
Vue.directive('el-drag-dialog', {
    bind(el, binding, vnode) {
        const dialogHeaderEl = el.querySelector('.el-dialog__header')
        const dragDom = el.querySelector('.el-dialog')
        dialogHeaderEl.style.cssText+ = '; cursor:move; ' dragDom.style.cssText+ = '; top:0px; 'CurrentStyle Firefox Google Window.getComputedStyle (DOM element, null);
        const getStyle = (function() {
          if (window.document.currentStyle) {
            return (dom, attr) => dom.currentStyle[attr]
          } else {
            return (dom, attr) => getComputedStyle(dom, false)[attr]
          }
        })()
    
        dialogHeaderEl.onmousedown = (e) => {
          // Hold down the mouse to calculate the current element distance from the viewable area
          const disX = e.clientX - dialogHeaderEl.offsetLeft
          const disY = e.clientY - dialogHeaderEl.offsetTop
    
          const dragDomWidth = dragDom.offsetWidth
          const dragDomHeight = dragDom.offsetHeight
    
          const screenWidth = document.body.clientWidth
          const screenHeight = document.body.clientHeight
    
          const minDragDomLeft = dragDom.offsetLeft
          const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth
    
          const minDragDomTop = dragDom.offsetTop
          const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight
    
          // The obtained value is replaced with a PX regular match
          let styL = getStyle(dragDom, 'left')
          let styT = getStyle(dragDom, 'top')
    
          if (styL.includes('%')) {
            styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100)
            styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100)}else {
            styL = +styL.replace(/\px/g, '')
            styT = +styT.replace(/\px/g, '')
          }
    
          document.onmousemove = function(e) {
            // Calculate the distance moved by the event delegate
            let left = e.clientX - disX
            let top = e.clientY - disY
    
            // boundary processing
            if (-(left) > minDragDomLeft) {
              left = -minDragDomLeft
            } else if (left > maxDragDomLeft) {
              left = maxDragDomLeft
            }
    
            if (-(top) > minDragDomTop) {
              top = -minDragDomTop
            } else if (top > maxDragDomTop) {
              top = maxDragDomTop
            }
    
            // Move the current element
            dragDom.style.cssText+ =`; left:${left + styL}px; top:${top + styT}px; `
    
            // emit onDrag event
            vnode.child.$emit('dragDialog')
          }
    
          document.onmouseup = function(e) {
            document.onmousemove = null
            document.onmouseup = null}}}})Copy the code

Used in vue files

<el-dialog
  v-el-drag-dialog
  :visible.sync="dialogTableVisible"
  title="Shipping address"
  @dragDialog="handleDrag"> <h1> Draggable dialog</h1> </el-dialog>Copy the code

2. V-clipboard Copies text

The NPM plug-in Clipboard is required. First install the plugin NPM I Clipboard-s. Then register the global Directive and remember to introduce clipBoard. Finally used in vue files. A successfully copied callback can be written with or without.

// Register clipboard globally
const Clipboard = require('clipboard');
Vue.directive('clipboard', {
  bind(el, binding) {
    if (binding.arg === 'success') {
      el._v_clipboard_success = binding.value
    } else if (binding.arg === 'error') {
      el._v_clipboard_error = binding.value
    } else {
      const clipboard = new Clipboard(el, {
        text() { return binding.value },
        action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
      })
      clipboard.on('success', e => {
        const callback = el._v_clipboard_success
        callback && callback(e) // eslint-disable-line
      })
      clipboard.on('error', e => {
        const callback = el._v_clipboard_error
        callback && callback(e) // eslint-disable-line
      })
      el._v_clipboard = clipboard
    }
  },
  update(el, binding) {
    if (binding.arg === 'success') {
      el._v_clipboard_success = binding.value
    } else if (binding.arg === 'error') {
      el._v_clipboard_error = binding.value
    } else {
      el._v_clipboard.text = function() { return binding.value }
      el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
    }
  },
  unbind(el, binding) {
    if (binding.arg === 'success') {
      delete el._v_clipboard_success
    } else if (binding.arg === 'error') {
      delete el._v_clipboard_error
    } else {
      el._v_clipboard.destroy()
      delete el._v_clipboard
    }
  }
})
Copy the code

Used in.vue files

<template>
  <div class="app-container">
    <el-button
      v-clipboard="testVal"
      v-clipboard:success="clipboardSuccess"
      type="primary"
      icon="el-icon-document"</el-button> </div> </template> <script>export default {
  data() {
    return{testVal: 'O (studying_}}, methods: {clipboardSuccess(val) {this.$message({
        message: 'Content (${val.text}) copied successfully',
        type: 'success'
      })
    }
  }
}
</script>
Copy the code

3. El-input registration of prices

Requirement: price related input. Placeholder by default, placeholder by default. Modify on the left after focus. Only a maximum of 2 decimals can be entered. After input out of focus to the right to display the thousandth digit.

Difficulty: out of focus after the right display thousandth digit. V-model does not support filter, so the idea for this example is to create a new input and hide the previous input. Update hooks must also write logic, otherwise an error is reported.

Vue.directive('price', {
  bind: function(el, { value = 2 }) {
    el = el.nodeName === "INPUT" ? el : el.children[0];
    el.placeholder = "Please enter";
    el.style.textAlign = "right";
    var RegStr = value === 0? ` ^ / \ \ + \ \ -? \\d+\\d{0.0} ` : ` ^ / \ \ + \ \ -? \\d+\\.? \\d{0,${value}}`;
    el.addEventListener('keyup', function() {
      el.value = el.value.match(new RegExp(RegStr, 'g'));
      el.dispatchEvent(new Event('input'))
    })
    el.addEventListener('focus', function() {
      const newAddIpt = el.parentNode.querySelector('.thousand-ipt');
      if (newAddIpt) {
        el.parentNode.removeChild(newAddIpt);
      }
      el.style.textAlign = "left";
      el.style.opacity = 1;
      el.style.position = "'; }) el.addEventListener('blur', function() {
      if (el.value === '') { el.value = '0.00 ';
      } else {
        el.value = Number(el.value).toFixed(2);
      }
      el.style.opacity = 0;
      el.style.position = 'absolute';
      el.dispatchEvent(new Event('input'))
      const newIpt = document.createElement("input"); // Create a new input node
      newIpt.value = parseFloat(el.value).toFixed(2).replace(/\d(? = (? :\d{3})+\b)/g, `$&,`)
      newIpt.className = 'el-input__inner thousand-ipt';
      newIpt.style.textAlign = "right";
      el.parentNode.appendChild(newIpt);
    })
  },
  update: function(el) {
    if (el.children[1] && el.children[1].value === undefined) {
      const newAddIpt = el.parentNode.querySelector('.thousand-ipt');
      if (newAddIpt) {
        el.removeChild(newAddIpt);
        el.children[0].style.textAlign = "left";
        el.children[0].style.opacity = 1;
        el.children[0].style.position = "'; }}}})Copy the code

4. El-input automatic focus

/** * auto focus */
Vue.directive("focus", {
  // Gets the cursor in the INSERTED node, where the element has already been inserted into the parent node
  inserted(el) {
    el = el.nodeName === "INPUT" ? el : el.children[0];
    el.focus();
  },
  bind(el) {
    el = el.nodeName === "INPUT" ? el : el.children[0]; el.focus(); }});Copy the code