zoukankan      html  css  js  c++  java
  • vue自定义指令要点

    vue自定义指令的基础使用这里就不阐述,看官网文档:https://cn.vuejs.org/v2/guide/custom-directive.html

    本文用一个实例描述自定义指令的要点,自定义一个数据上报的指令。

    你可能会这样写demo:

    // 自定义v-datacenter命令埋点,点击节点发送埋点数据
    // demo : <div v-datacenter="{ei: 'learning_center_click'}">进入学习中心</div>
    const dataCenter = function(data){
        // 这里处理数据上报
    }
    Vue.directive('datacenter', {
        bind(el, binding) {
         // 或者使用dataset(要注意兼容性):https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/dataset el._dataCenter
    = function(el) { dataCenter(binding.value); } el.addEventListener('click', el._dataCenter) }, unbind(el) { // 移除监听 el.removeEventListener('click', el._dataCenter); delete el._dataCenter; } })

     这个demo对节点的点击做了响应,处理了数据埋点。有什么问题呢?只处理了初次绑定的数据,如果你的数据是通过ajax异步获取的,就可能出现问题,比如

    <div v-datacenter="{ei: info.dataEvent}">进入学习中心</div>

     其中info.dataEvent最开始是空字符,从后台拉取数据以后info.dataEvent才有值。那么上面的自定义指令中bind中的binding.value的值应当是为空字符。点击上报数据时“ei”的值一直为空字符

    改进:

    // 自定义v-datacenter命令埋点,点击节点发送埋点数据
    // demo : <div v-datacenter="{ei: 'learning_center_click'}">进入学习中心</div>
    Vue.directive('datacenter', {
        bind(el, binding) {
            el._dataCenter = function(el) {
                dataCenter(binding.value);
            }
            el.addEventListener('click', el._dataCenter)
        },
        update(el, binding) {
            // 处理value一开始没有值,后面才有值的情况
            if (binding.value && (JSON.stringify(binding.value) !== JSON.stringify(binding.oldValue))) {
                // 移除之前的监听
                el.removeEventListener('click', el._dataCenter);
                delete el._dataCenter;
    
                // 新增监听
                el._dataCenter = function(el) {
                    dataCenter(binding.value);
                }
                el.addEventListener('click', el._dataCenter)
            }
        },
        unbind(el) {
            // 移除监听
            el.removeEventListener('click', el._dataCenter);
            delete el._dataCenter;
        }
    })

     添加了update(当所在组件的 VNode 更新时调用),由于update时指令的value可能完全没有改动,所以要判断当值有更改且有效时重新绑定click监听。这样和bind配合就满足了同步/异步的所有场景。

    真的就OK了么?显然不是,还有一种异常情况:在特殊情况下(如路由切换),节点既要响应click监听,也要移除节点。unbind就会在响应click监听之前调用。监听在响应之前就被移除,导致失败。

    二次改进:

    // 自定义v-datacenter命令埋点,点击节点发送埋点数据
    // demo : <div v-datacenter="{ei: 'learning_center_click'}">进入学习中心</div>
    Vue.directive('datacenter', {
        bind(el, binding) {
            el._dataCenter = function(el) {
                dataCenter(binding.value);
            }
            el.addEventListener('click', el._dataCenter)
        },
        update(el, binding) {
            // 处理value一开始没有值,后面才有值的情况
            if (binding.value && (JSON.stringify(binding.value) !== JSON.stringify(binding.oldValue))) {
                // 移除之前的监听
                el.removeEventListener('click', el._dataCenter);
                delete el._dataCenter;
    
                // 新增监听
                el._dataCenter = function(el) {
                    dataCenter(binding.value);
                }
                el.addEventListener('click', el._dataCenter)
            }
        },
        unbind(el) {
            // 移除监听
            // 在特殊情况下节点既要响应click,也要移除节点。避免在响应click之前就被移除监听,
            // 所以要延时移除,放到下一个宏任务
            setTimeout(() => {
                el.removeEventListener('click', el._dataCenter);
                delete el._dataCenter;
            })
        }
    })

     要避免在响应监听前监听被移除,所以将移除监听放到下一个宏任务。OK,收工!

  • 相关阅读:
    Flask---框架入门
    续--Flask, Django
    测试开发中Django和Flask框架
    oracle数据库的存储原理
    Oracle 存储过程—为数传递变量
    Oracle scope中 spfile、memory、both 的区别
    数据库性能衡量指标
    raid卷性能测试
    HTTP POST请求报文格式分析与Java实现文件上传
    使用Navicat 导入导出Mysql数据库
  • 原文地址:https://www.cnblogs.com/chuaWeb/p/custom-directive.html
Copyright © 2011-2022 走看看