【问题标题】:Trigger an event to call a function that's inside of a closure触发事件以调用闭包内的函数
【发布时间】:2020-09-04 16:40:22
【问题描述】:

我正在根据一个不错的小sample canvas drawing app 开发一个项目,该项目上的其他人已下载并修改了该项目。我们需要允许用户单击页面上其他位置(不是画布的一部分)的按钮,并让它运行示例应用程序附带的功能。但是,该函数位于闭包内部。由于我不能直接调用该函数(对吗?闭包可以防止这种情况发生?我不经常使用闭包),我认为我可以通过在用户单击的位置触发鼠标事件来完成此操作完成同样的事情。它不工作,我不知道为什么不工作。

我在this fiddle 发布了一个大大简化的版本。简单的 HTML 代码:

<div id="canvasDiv"></div>
<div id="buttonDiv">
  <button>why can't I send a click to the canvas?</button>
</div>

以及下载的示例应用的简化版,加上我尝试使用jQuery的.trigger方法来触发事件:

var WM = {};

WM.drawingApp = function(options) {
  "use strict";
  var canvas, context,
    // Add mouse and touch event listeners to the canvas
    createUserEvents = function() {
      var getElementPos = function(element) {
        // straight-forward stuff removed for brevity's sake
        return pos;
      };
      var press = function(e) {
        // Mouse down location
        var sizeHotspotStartX, toolIndex,
          mouseX = (e.changedTouches ? e.changedTouches[0].pageX : e.pageX),
          mouseY = (e.changedTouches ? e.changedTouches[0].pageY : e.pageY);

        var elementPos = getElementPos(document.getElementById(options.canvasElementId || 'canvasDiv'));
        mouseX -= elementPos.x;
        mouseY -= elementPos.y;
        announce(mouseX, mouseY);
      };
      var announce = function(x,y) { alert('press at: ' + x + ', ' + y); }
      // Add mouse event listeners to canvas element
      canvas.addEventListener("mousedown", press, false);
    },
    // Creates a canvas element, etc
    init = function() {
      // Create the canvas 
      canvas = document.createElement('canvas');
      canvas.setAttribute('width', 100);
      canvas.setAttribute('height', 100);
      canvas.setAttribute('id', 'canvas');
      document.getElementById(options.canvasElementId || 'canvasDiv').appendChild(canvas);
      context = canvas.getContext("2d"); // Grab the 2d canvas context
      createUserEvents();
    };
  init();
  return {};
};

jQuery(document).ready(function() {
  jQuery('#buttonDiv').on('click', 'button', function() {
    var down = jQuery.Event("mousedown", {
      pageX: 50,
      pageY: 50
    });
    jQuery('#canvasDiv canvas').trigger(down);
  });
});

正如您通过运行小提琴所看到的,如果您在框内单击,您会收到一个警报,通知您单击的位置。但是,如果您单击该按钮,则不会收到警报。在写这个问题时,我突然想到 jQuery 的 .trigger 方法可能不足以发送点击。它的文档页面特别指出.trigger“不能完美地复制自然发生的事件”。我们对不涉及 jQuery 的解决方案持开放态度。

【问题讨论】:

    标签: javascript closures dom-events


    【解决方案1】:

    您可以在WM 之外、WM 内部定义一个变量var press;,在press 之前删除var 并设置press = function() {}。然后,您应该可以通过点击button 调用press(down)

    var press;
    

    press = function(e) {
              console.log(e);
              // Mouse down location
              var sizeHotspotStartX, toolIndex,
              mouseX = (e.changedTouches ? e.changedTouches[0].pageX : e.pageX),
              mouseY = (e.changedTouches ? e.changedTouches[0].pageY : e.pageY);
    
              var elementPos = getElementPos(
                document.getElementById(options.canvasElementId 
                || 'canvasDiv')
              );
              mouseX -= elementPos.x;
              mouseY -= elementPos.y;
              announce(mouseX, mouseY);
            };
    

    jQuery(document).ready(function() {
      jQuery('#buttonDiv').on('click', 'button', function() {
        var down = jQuery.Event("mousedown", {
          pageX: 50,
          pageY: 50
        });
        press(down); // call `press` at `button` click
        //jQuery('#canvasDiv canvas').trigger(down);
      });
    });
    

    // based on http://www.williammalone.com/projects/html5-canvas-javascript-drawing-app-with-bucket-tool/
    
    var press;
    
    var WM = {};
    
    WM.drawingApp = function(options) {
      "use strict";
      var canvas, context,
        // Add mouse and touch event listeners to the canvas
        createUserEvents = function() {
          var getElementPos = function(element) {
            var parentOffset, pos;
            if (!element) {
              pos = {
                x: 0,
                y: 0
              };
            } else {
              pos = {
                x: element.offsetLeft,
                y: element.offsetTop
              };
              if (element.offsetParent) {
                parentOffset = getElementPos(element.offsetParent);
                pos.x += parentOffset.x;
                pos.y += parentOffset.y;
              }
            }
            return pos;
          };
          press = function(e) {
            console.log(e)
            // Mouse down location
            var sizeHotspotStartX, toolIndex,
              mouseX = (e.changedTouches ? e.changedTouches[0].pageX : e.pageX),
              mouseY = (e.changedTouches ? e.changedTouches[0].pageY : e.pageY);
    
            var elementPos = getElementPos(document.getElementById(options.canvasElementId || 'canvasDiv'));
            mouseX -= elementPos.x;
            mouseY -= elementPos.y;
            announce(mouseX, mouseY);
          };
          var announce = function(x,y) { alert('press at: ' + x + ', ' + y); }
          // Add mouse event listeners to canvas element
          canvas.addEventListener("mousedown", press, false);
        },
        // Creates a canvas element, loads images, adds events, and draws the canvas for the first time.
        init = function() {
          // Create the canvas (Neccessary for IE because it doesn't know what a canvas element is)
          canvas = document.createElement('canvas');
          canvas.setAttribute('width', 100);
          canvas.setAttribute('height', 100);
          canvas.setAttribute('id', 'canvas');
          document.getElementById(options.canvasElementId || 'canvasDiv').appendChild(canvas);
          context = canvas.getContext("2d"); // Grab the 2d canvas context
          createUserEvents();
        };
      init();
      return {};
    };
    
    jQuery(document).ready(function() {
      jQuery('#buttonDiv').on('click', 'button', function() {
        var down = jQuery.Event("mousedown", {
          pageX: 50,
          pageY: 50
        });
        press(down)
        //jQuery('#canvasDiv canvas').trigger(down);
      });
    });
    
    var drawingApp = WM.drawingApp({
      canvasElementId: "canvasDiv"
    });
     #canvasDiv canvas {
       border: solid black 1px;
     }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
    </script>
    <div id="canvasDiv"></div>
    <div id="buttonDiv">
      <button>why can't I send a click to the canvas?</button>
    </div>

    jsfiddle https://jsfiddle.net/gkvdha3h/5/

    【讨论】:

    • 这解决了我们的问题!谢谢!我仍然很好奇为什么发送点击不起作用,但我越来越怀疑这是jQuery的触发方法和“自然发生的事件”之间的区别。
    猜你喜欢
    • 2014-09-13
    • 1970-01-01
    • 2018-03-17
    • 2023-04-09
    • 1970-01-01
    • 2013-05-31
    • 1970-01-01
    • 2014-12-20
    • 2012-10-01
    相关资源
    最近更新 更多