• 技术文章 >web前端 >Vue.js

    分享一些Vuejs中常用的自定义指令(总结)

    青灯夜游青灯夜游2021-07-08 10:56:19转载357
    在Vuejs中,自定义一些指令对底层DOM进行操作。下面本篇文章总结分享一些常用的自定义指令代码,可以直接使用,提高开发效率!

    【相关推荐:《vue.js教程》】

    1、元素点击范围扩展指令 v-expandClick

    使用该指令可以隐式的扩展元素的点击范围,由于借用伪元素实现,故不会影响元素在页面上的排列布局。

    可传入的参数为:上右下左扩展的范围,单位 px,默认向外扩展 10px。指令的代码如下:

    export default function (el, binding) {
        const s = document.styleSheets[document.styleSheets.length - 1]
        const DEFAULT = -10 // 默认向外扩展10px
        const ruleStr = `content:"";position:absolute;top:-${top || DEFAULT}px;bottom:-${bottom || DEFAULT}px;right:-${right || DEFAULT}px;left:-${left || DEFAULT}px;`
        const [top, right, bottom, left] = binding.expression && binding.expression.split(',') || []
        const classNameList = el.className.split(' ')
        el.className = classNameList.includes('expand_click_range') ? classNameList.join(' ') : [...classNameList, 'expand_click_range'].join(' ')
        el.style.position = el.style.position || "relative"
        if (s.insertRule) {
            s.insertRule('.expand_click_range::before' + '{' + ruleStr + '}', s.cssRules.length)
        } else { /* IE */
            s.addRule('.expand_click_range::before', ruleStr, -1)
        }
    }

    参数 Attributes:

    1.png

    然后你可以在模板中任何元素上使用新的 v-expandClick property,如下:

    <div v-expandClick="20,30,40,50" @click="glabClickoutside"> 点击范围扩大</div>

    2、文本内容复制指令 v-copy

    使用该指令可以复制元素的文本内容(指令支持单击复制 v-copy、双击复制 v-copy.dblclick、点击icon复制 v-copy.icon 三种模式),不传参数时,默认使用单击复制。

    指令的代码如下:

    export default {
      bind (el, binding) {
        // 双击触发复制
        if (binding.modifiers.dblclick) {
          el.addEventListener('dblclick', () => handleClick(el.innerText))
          el.style.cursor = 'copy'
        }
        // 点击icon触发复制
        else if (binding.modifiers.icon) {
          if (el.hasIcon) return
          const iconElement = document.createElement('i')
          iconElement.setAttribute('class', 'el-icon-document-copy')
          iconElement.setAttribute('style', 'margin-left:5px')
          el.appendChild(iconElement)
          el.hasIcon = true
          iconElement.addEventListener('click', () => handleClick(el.innerText))
          iconElement.style.cursor = 'copy'
        }
        // 单击触发复制
        else {
          el.addEventListener('click', () => handleClick(el.innerText))
          el.style.cursor = 'copy'
        }
      }
    }
    
    function handleClick (text) {
      // 创建元素
      if (!document.getElementById('copyTarget')) {
        const copyTarget = document.createElement('input')
        copyTarget.setAttribute('style', 'position:fixed;top:0;left:0;opacity:0;z-index:-1000;')
        copyTarget.setAttribute('id', 'copyTarget')
        document.body.appendChild(copyTarget)
      }
    
      // 复制内容
      const input = document.getElementById('copyTarget')
      input.value = text
      input.select()
      document.execCommand('copy')
      // alert('复制成功')
    }

    参数 Attributes:

    2.png

    然后你可以在模板中任何元素上使用新的 v-copy property,如下:

    <div v-copy> 单击复制 </div>
    <div v-copy.dblclick> 双击复制 </div>
    <div v-copy.icon> icon复制 </div>

    3、元素全屏指令 v-screenfull
    全屏指令,点击元素进行全屏/退出全屏的操作。支持元素后面是否插入 element-ui 的全屏图标 el-icon-full-screen。

    指令的代码如下:

    import screenfull from 'screenfull'
    
    export default {
      bind (el, binding) {
        if (binding.modifiers.icon) {
          if (el.hasIcon) return
          // 创建全屏图标
          const iconElement = document.createElement('i')
          iconElement.setAttribute('class', 'el-icon-full-screen')
          iconElement.setAttribute('style', 'margin-left:5px')
          el.appendChild(iconElement)
          el.hasIcon = true
      }
        el.style.cursor = el.style.cursor || 'pointer'
        // 监听点击全屏事件
        el.addEventListener('click', () => handleClick())
      }
    }
    
    function handleClick () {
      if (!screenfull.isEnabled) {
        alert('浏览器不支持全屏')
        return
      }
      screenfull.toggle()
    }

    参数 Attributes:

    3.png

    然后你可以在模板中任何元素上使用新的 v-screenfull property,如下:

    <div v-screenfull.icon> 全屏 </div>

    4、元素说明指令 v-tooltip

    为元素添加说明,如同 element-ui 的 el-tooltip(问号 icon 在鼠标覆盖后,展示说明文字)。

    4.png

    指令的代码如下:

    import Vue from 'vue'
    export default function (el, binding) {
        if (el.hasIcon) return
        const iconElement = structureIcon(binding.arg, binding.value)
        el.appendChild(iconElement)
        el.hasIcon = true
    }
    
    function structureIcon (content, attrs) {
        // 拼接绑定属性
        let attrStr = ''
        for (let key in attrs) {
            attrStr += `${key}=${attrs[key]} `
        }
        const a = `<el-tooltip content=${content} ${attrStr}><i class="el-icon-question" style="margin:0 10px"></i></el-tooltip>`
        // 创建构造器
        const tooltip = Vue.extend({
            template: a
        })
        // 创建一个 tooltip 实例并返回 dom 节点
        const component = new tooltip().$mount()
        return component.$el
    }

    参数 Attributes:

    5.png

    然后你可以在模板中任何元素上使用新的 v-tooltip property,如下:

    <div v-tooltip:content='tootipParams'> 提示 </div>

    举例:

    <div v-tooltip:提示内容为XXX1> 提示1</div>
    <div v-tooltip:提示内容为XXX='tootipParams'> 提示2 </div>

    为指令传入 element-ui 支持的参数:

    data() {
        return {
            tootipParams: {
                placement: 'top',
                effect: 'light',
            }
        }
    }

    5、文字超出省略指令 v-ellipsis

    使用该指令当文字内容超出宽度(默认 100 px)时自动变为省略形式。等同于使用 css:

    width: 100px;
    whiteSpace: nowrap
    overflow: hidden;
    textOverflow: ellipsis;

    使用指令效果:

    6.png

    指令的代码如下:

    export default function (el, binding) {
        el.style.width = binding.arg || 100 + 'px'
        el.style.whiteSpace = 'nowrap'
        el.style.overflow = 'hidden';
        el.style.textOverflow = 'ellipsis';
    }

    参数 Attributes:

    7.png

    然后你可以在模板中任何元素上使用新的 v-ellipsis property,如下:

    <div v-ellipsis:100> 需要省略的文字是阿萨的副本阿萨的副本阿萨的副本阿萨的副本</div>

    6、回到顶部指令 v-backtop
    使用该指令可以让页面或指定元素回到顶部。

    可选指定元素,如果不指定则全局页面回到顶部。可选在元素偏移多少 px 后显示 backtop 元素,例如在滚动 400px 后显示回到顶部按钮。

    8.png

    指令的代码如下:

    export default {
      bind (el, binding, vnode) {
        // 响应点击后滚动到元素顶部
        el.addEventListener('click', () => {
        const target = binding.arg ? document.getElementById(binding.arg) : window
        target.scrollTo({
          top: 0,
          behavior: 'smooth'
          })
        })
      },
      update (el, binding, vnode) {
        // 滚动到达参数值才出现绑定指令的元素
        const target = binding.arg ? document.getElementById(binding.arg) : window
        if (binding.value) {
          target.addEventListener('scroll', (e) => {
            if (e.srcElement.scrollTop > binding.value) {
              el.style.visibility = 'unset'
            } else {
              el.style.visibility = 'hidden'
            }
          })
        }
        // 判断初始化状态
        if (target.scrollTop < binding.value) {
          el.style.visibility = 'hidden'
        }
      },
      unbind (el) {
        const target = binding.arg ? document.getElementById(binding.arg) : window
        target.removeEventListener('scroll')
        el.removeEventListener('click')
      }
    }

    参数 Attributes:

    9.png

    然后你可以在模板中任何元素上使用新的 v-backtop property,如下表示在 id 为 app 的元素滚动 400px 后显示绑定指令的元素:

    <div  v-backtop:app="400"> 回到顶部 </div>

    也可以这样使用,表示为一直显示绑定指令的元素,并且是全局页面回到顶部:

    <div  v-backtop> 回到顶部 </div>

    7、空状态指令 v-empty

    使用该指令可以显示缺省的空状态。可以传入默认图片(可选,默认无图片)、默认文字内容(可选,默认为暂无数据)、以及标示是否显示空状态(必选)。

    10.png

    指令的代码如下:

    import Vue from "vue";
    export default {
      update (el, binding, vnode) {
        el.style.position = el.style.position || 'relative'
        const { offsetHeight, offsetWidth } = el
        const { visible, content, img } = binding.value
        const image = img ? `<img src="${img}" height="30%" width="30%"></img>` : ''
        const defaultStyle = "position:absolute;top:0;left:0;z-index:9999;background:#fff;display:flex;justify-content: center;align-items: center;"
        const empty = Vue.extend({
        template: `<div style="height:${offsetHeight}px;width:${offsetWidth}px;${defaultStyle}">
          <div style="text-align:center">
            <div>${image}</div>
            <div>${content || '暂无数据'}</div>
          </div>
        </div>`
        })
        const component = new empty().$mount().$el
        if (visible) {
          el.appendChild(component)
        } else {
          el.removeChild(el.lastChild)
        }
      },
    }

    参数 Attributes:

    11.png

    然后你可以在模板中任何元素上使用新的 v-empty property,如下传入对象 emptyValue:

    <div style="height:500px;width:500px" v-empty="emptyValue"> 原本内容

    需要传入一个参数对象,例如显示文字为:暂无列表,图片路径为 ../../assets/images/blue_big.png,控制标示 visible:

    emptyValue = {
      content: '暂无列表',
      img: require('../../assets/images/blue_big.png'),
      visible: true,
    },

    8、徽标指令 v-badge

    使用该指令在元素右上角显示徽标。

    支持配置徽标的背景颜色、徽标形状;支持传入徽标上显示的数字。

    12.png

    指令的代码如下:

    import Vue from 'vue'
    
    const SUCCESS = '#72c140'
    const ERROR = '#ed5b56'
    const WARNING = '#f0af41'
    const INFO = '#4091f7'
    const HEIGHT = 20
    let flag = false
    export default {
      update (el, binding, vnode) {
        const { modifiers, value } = binding
        const modifiersKey = Object.keys(modifiers)
        let isDot = modifiersKey.includes('dot')
        let backgroundColor = ''
        if (modifiersKey.includes('success')) {
          backgroundColor = SUCCESS
        } else if (modifiersKey.includes('warning')) {
          backgroundColor = WARNING
        } else if (modifiersKey.includes('info')) {
          backgroundColor = INFO
        } else {
          backgroundColor = ERROR
        }
    
        const targetTemplate = isDot 
            ? `<div style="position:absolute;top:-5px;right:-5px;height:10px;width:10px;border-radius:50%;background:${backgroundColor}"></div>` 
            : `<div style="background:${backgroundColor};position:absolute;top:-${HEIGHT / 2}px;right:-${HEIGHT / 2}px;height:${HEIGHT}px;min-width:${HEIGHT}px;border-radius:${HEIGHT / 2}px;text-align:center;line-height:${HEIGHT}px;color:#fff;padding:0 5px;">${value}</div>`
            
        el.style.position = el.style.position || 'relative'
        const badge = Vue.extend({
          template: targetTemplate
        })
        const component = new badge().$mount().$el
        if (flag) {
          el.removeChild(el.lastChild)
        }
        el.appendChild(component)
        flag = true
      }
    }

    参数 Attributes:

    13.png

    然后你可以在模板中任何元素上使用新的 v-badge property,如下:

    <div v-badge.dot.info="badgeCount" style="height:50px;width:50px;background:#999"> </div>

    9、拖拽指令 v-drag

    使用该指令可以对元素进行拖拽。

    指令的代码如下:

    export default {
      let _el = el
      document.onselectstart = function() {
        return false  //禁止选择网页上的文字
      }
      
      _el.onmousedown = e => {
        let disX = e.clientX - _el.offsetLeft //鼠标按下,计算当前元素距离可视区的距离
        let disY = e.clientY - _el.offsetTop
        document.onmousemove = function(e){     
          let l = e.clientX - disX
          let t = e.clientY - disY;
          _el.style.left = l + "px"
          _el.style.top = t + "px"
        }
        document.onmouseup = e => {
          document.onmousemove = document.onmouseup = null
        }
        return false
      }
    }

    然后你可以在模板中任何元素上使用新的 v-drag property,如下:

    <div v-drag> 支持拖拽的元素 </div>

    10、响应缩放指令 v-resize

    使用该指令可以响应元素宽高改变时执行的方法。

    指令的代码如下:

    export default {
      bind(el, binding) {
        let width = '', height = '';
        function isReize() {
          const style = document.defaultView.getComputedStyle(el);
          if (width !== style.width || height !== style.height) {
            binding.value();  // 执行传入的方法
          }
          width = style.width;
          height = style.height;
         }
         el.__timer__ = setInterval(isReize, 300); // 周期性监听元素是否改变
      },
      unbind(el) {
        clearInterval(el.__timer__);
      }
    }

    参数 Attributes:

    14.png

    然后你可以在模板中任何元素上使用新的 v-resize property,如下:

    // 传入 resize() 方法
    <div v-resize="resize"></div>

    11、字符串整形指令 v-format

    使用该指令可以修改字符串,如使用 v-format.toFixed 保留两位小数、 v-format.price 将内容变成金额(每三位逗号分隔),可以同时使用,如 v-format.toFixed.price。

    例如将数字 243112.331 变成 243112.33,或 243,112.33。

    指令的代码如下:

    export default {
      update (el, binding, vnode) {
        const { value, modifiers } = binding
        if (!value) return
        let formatValue = value
        if (modifiers.toFixed) {
          formatValue = value.toFixed(2)
        }
        console.log(formatValue)
        if (modifiers.price) {
          formatValue = formatNumber(formatValue)
        }
        el.innerText = formatValue
      },
    }
    
    
    
    function formatNumber (num) {
      num += '';
      let strs = num.split('.');
      let x1 = strs[0];
      let x2 = strs.length > 1 ? '.' + strs[1] : '';
      var rgx = /(\d+)(\d{3})/;
      while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
      }
      return x1 + x2
    }

    参数 Attributes:

    15.png

    然后你可以在模板中任何元素上使用新的 v-format property,如下:

    <div v-format.toFixed.price="123333"> 123 </div>

    如何使用这些指令?

    为了便于管理指令,我们将每个指令都存在于单独的 js 文件中。在项目的 src 下建一个 directives 目录,目录下新建 index.js 文件用于引入并注册指令。

    ├── src
    |  ├── directive
    |  |  ├── index.js
    |  |  ├── backtop.js
    |  |  ├── badge.js
    |  |  ├── copy.js
    |  |  ├── ellipsis.js
    |  |  ├── empty.js
    |  |  ├── expandClick.js
    |  |  ├── screenfull.js
    |  |  └── tooltips.js
    |  ├── main.js

    举个例子:

    directives 目录下新建 ellipsis.js 文件:

    export default function (el, binding) {
        el.style.width = binding.arg || 100 + 'px'
        el.style.whiteSpace = 'nowrap'
        el.style.overflow = 'hidden';
        el.style.textOverflow = 'ellipsis';
    }

    directives 的 index.js 文件中引入 ellipsis 指令并注册:

    import Vue from 'vue'
    import ellipsis from './ellipsis' // 引入指令
    // import other directives
    
    const directives = {
      ellipsis
      // other directives
    }
    
    Object.keys(directives).forEach(name => Vue.directive(name, directives[name]))

    最后在 mian.js 中引入 index.js 文件:

    import '@/directives/index'

    这样就可以正常使用这些指令了:

    import '@/directives/index'

    更多编程相关知识,请访问:编程入门!!

    以上就是分享一些Vuejs中常用的自定义指令(总结)的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:segmentfault,如有侵犯,请联系admin@php.cn删除
    专题推荐:vue.js 自定义指令
    上一篇:vue路由跳转的三种方式是什么 下一篇:$nextTick VS setTimeout,看看它们的差异
    线上培训班

    相关文章推荐

    • 关于vue-cli4+laravel8使用JWT登录及token验证• Vue如何进行事件处理?相关基础知识介绍• 深入浅析Vuejs中的key值• 深入了解vue.js的3种安装方法• 宝塔部署vue项目时,访问首页正常,但其他页面无法访问404的解决办法• 介绍laravel+vue前后端分离之服务器端配置

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网