zoukankan      html  css  js  c++  java
  • 兼职答题第一道被采纳的题

    这道题来自CSDN,最近接了一个兼职在CSND做答题服务。

    这道题是网友提出来了的,题干如下:

    请问有没有办法用vue或者原生JS将多个页面统一进行防止重复执行点击事件(在不侵入源事件方法的前提下,因为页面太多是在改不过来),或者进行统一节流处理

    我给出的第一个答案:

    如果点击事件都有axios请求,你防止的是重复的后端请求,如果是vue单页面项目可以考虑如下的方案: 取消重复请求,具体方法如下,基本思路是缓存,请求结束之后清空缓存

    /**
     * 全部请求拦截器处理
     */
    const pendingRequests = new Map()
    myAjax.interceptors.request.use(function (config) {
      const params = config.params || config.data
      const requestKey = `${config.url}/${JSON.stringify(params)}&request_type=${config.method}`
      if (pendingRequests.has(requestKey)) {
        config.cancelToken = new axios.CancelToken((cancel) => {
          // cancel 函数的参数会作为 promise 的 error 被捕获
          cancel(`重复的请求被主动拦截: ${requestKey}`)
        })
      } else {
        pendingRequests.set(requestKey, config)
        config.requestKey = requestKey
      }
      return config
    },
    function (error) {
      pendingRequests.clear()
      return Promise.reject(error)
    }
    )
    /**
     * 响应拦截器
     */
    myAjax.interceptors.response.use(response => {
      const requestKey = response.config.requestKey
      pendingRequests.delete(requestKey)
      return response
    }, error => {
      pendingRequests.clear()
      return Promise.reject(error)
    })

    或者将问题阐述具体一些。

    之所以这样是他的题干信息不具体,而且当是我正在优化全局响应拦截器这部分。我很自然的想到是不是他也做一层拦截就可以了。然后我给出全局拦截的前提还有解决方案。

    后来,他回复了,回复内容:

    不是单页面项目,后台请求基本都是普通的ajax(应该是不像axios有拦截器的..)。主要是对每个页面的nav标签里的请求按钮进行统一的防重复点击、请求。

    然后我就知道他要做什么了,是想对所有类似的按钮做一层防抖。于是我给出了我的第二个答案:

    可以利用css的选择器拿到按钮, 然后拿到按钮绑定事件的引用, 然后重新给按钮绑定事件, 重写事件的方法,加上防抖。

    <body>
        <button id="btn" onclick="alert('hi~')">我是按钮</button>
        <script>
            const btn = document.getElementById('btn')
            const clickfn = btn.onclick // 获取onclik的方法
            btn.onclick = null //解除事件
            console.log(clickfn, 'click')
            let timer = null
            // 利用addEventListener重新绑定事件 顺便加上防抖
            btn.addEventListener('click', ()=>{
                timer && clearTimeout(timer)
                timer = setTimeout(() => {
                    clickfn()
                }, 300);
            })
        </script>
    </body>

    将上面写成一个单独的JavaScript文件,引入到各个html文件中。 当然前提是你是利用onclick绑定的事件,如果是利用addEventListener绑定的事件:也可以参照这个思路,但前提是能够拿到addEventListener绑定的事件。目前我没找到合适的方法拿到。

    给出这个方案也是基于《设计模式》里面有提到的装饰者模式,尽可能少的减少原来代码的情况下,解决问题。

    但是题主随后表示和我一样不能拿到addEventListener绑定事件的引用。

    最后我又想到了一个方案,于是再度回复:

    (function() { 
        Element.prototype._addEventListener = Element.prototype.addEventListener; 
        Element.prototype.addEventListener = function(a, b, c) { 
         this._addEventListener(a, b, c); 
         if (a == "click") { 
          this._addEventListener("touchstart", b, c); 
         } 
        }; 
    })();

    试试复写addEventListener这个思路。

    我相信这个思路一定是可以解决的。然后我耐心等待题主的回复。可题主就像不在线了一样,一直到我快下班了都没回复。我因为着急别的事情就不在关注。

    第二天没想到的是题主回复通过借鉴第一个回复解决了问题。并且表示多谢我,我于是在他的回复下面麻烦他采纳我的答案,没想到他真的采纳了。

    我心里一阵高兴。

    总结:就解决题主的问题而言,防止重复请求的可以用全局拦截器,也可以用防抖。就题主的场景而言,我最后的答案是可以解决他的问题的。实质是对事件绑定过程进行拦截。而利用拿到onclick的方法,虽然没有解决题主的问题,但涉及到一种设计模式:装饰者模式,以不浸入源代码的方式实现开发目的。

    我站在山顶看风景!下面是我的家乡!
  • 相关阅读:
    C++ Primer 读书笔记 第六章
    C++ Primer 读书笔记 第十章
    面试题笔记
    C++ Primer 读书笔记 第八章
    ZedGraph源码学习(三)
    一个简单的代码生成器XML与XLST的应用测试。
    信息导到Execl上.
    SQL相关功能实现.
    ZedGraph源码学习(二)
    EXECL导入(检查服务器版本.包括NPOI方式导入.可以通过配置文件信息导入EXECL)代码记录下.
  • 原文地址:https://www.cnblogs.com/zhensg123/p/15450451.html
Copyright © 2011-2022 走看看