【问题标题】:Javascript 'this' to pass a canvas to function on page loadJavascript 'this' 将画布传递给页面加载功能
【发布时间】:2017-05-31 04:12:34
【问题描述】:

我正在尝试将 canvas HTML 元素作为参数传递,我认为“this”会起作用,但我无法做到。有人可以帮我在页面加载时使用“this”关键字将画布传递给 main() 吗?

不起作用:

<html>
    <head>
    <title>Draw on Canvas</title>
    </head>
    <body onload=main(this.firstChild)><canvas></canvas></body>
    <script>
        function main(canv) {
            cntx = canv.getContext("2d");
            cntx.rect(10, 10, 100, 100);
            cntx.fill();
        }
    </script>
</html>

有效,但想改用“this”关键字:

<html>
    <head>
    <title>Draw on Canvas</title>
    </head>
    <body onload=main(document.body.firstChild)><canvas></canvas></body>
    <script>
        function main(canv) {
            cntx = canv.getContext("2d");
            cntx.rect(10, 10, 100, 100);
            cntx.fill();
        }
    </script>
</html>

不起作用(未为画布元素定义加载):

<html>
    <head>
    <title>Draw on Canvas</title>
    </head>
    <body><canvas onload=main(this)></canvas></body>
    <script>
        function main(canv) {
            cntx = canv.getContext("2d");
            cntx.rect(10, 10, 100, 100);
            cntx.fill();
        }
    </script>
</html>

工作,并使用“this”,但希望代码在不点击的情况下运行:

<html>
    <head>
    <title>Draw on Canvas</title>
    </head>
    <body><canvas onclick=main(this)></canvas></body>
    <script>
        function main(canv) {
            cntx = canv.getContext("2d");
            cntx.rect(10, 10, 100, 100);
            cntx.fill();
        }
    </script>
</html>

【问题讨论】:

    标签: javascript html canvas this


    【解决方案1】:

    我建议您考虑一种不同的方法,因为如果您将其混合到 HTML 标记中,则可能会使整体脚本逻辑的表现力复杂化。更重要的是,虽然您不能在 HTML 标记上下文中使用 onload 来获取窗口之外的任何 this,但您可以创建定义为在 window.onload 之后以任何您想要的方式执行的 JS 函数。

    你已经在使用 JavaScript 来定义你的画布属性,为什么不同时在 JS 中创建画布呢!

    您还可以查看如何扩展此功能,以打开您在动态创建/附加更多画布方面的选项。

    如果这对您不起作用,请告诉我这是否是一个抽象问题,我可能能够更直接地帮助解决这个问题。

    <html>
        <head>
            <title>Draw on Canvas</title>
        </head>
        <body>
    
            <script>
                function createCanvasRect(x, y, width, height) {
                    var canv = document.createElement('canvas'),
                        cntx = canv.getContext('2d');
    
                    cntx.rect(x, y, width, height);
                    cntx.fill();
    
                    return canv;
                }
    
                function load() {
                    var canvas = createCanvasRect(10, 10, 100, 100);
    
                    document.body.appendChild(canvas);
                }
    
                window.onload = load;
            </script>
        </body>
        
    </html>

    【讨论】:

    • 我完全同意,尤其是对于画布元素,没有理由将它放在标记中。画布元素不提供任何有意义的信息,如果不使用 javascript,它是完全无用的。 +1。 但是请将您的脚本元素放在&lt;body&gt; 标记内。 html 元素只能有一个&lt;head&gt; 和一个&lt;body&gt; 作为子元素,不能少不能多,按这个顺序。
    • 我试图尽可能少地改变以保持示例的可识别性,但你是对的。我应该把它扔进身体里。固定。
    • 谢谢,非常感谢...作为一个新的 javascript 用户,当我的程序员希望正文部分只定义正文时,
    【解决方案2】:

    您的问题在于 onload 的使用。

    通常,调用内联的侦听器,就像包装在外部函数中一样,它的 this 设置为调用侦听器的元素。但是,对于 onload 监听器附加到 body 元素,情况并非如此。它们的执行被延迟,并在 global / window 对象设置为 this 的情况下调用它们。

    所以你不能以你尝试的方式使用 this

    以下演示了body的load监听器是用this作为全局对象调用的,而div的click监听器是用this作为全局对象调用的div 元素为 this.

    <script>
      // Reference to global/window object
      var global = this;
    </script>
      
    <body onload="console.log(this === global)">
    <div onclick="console.log(this.tagName)">clickable div</div>
    </body>

    【讨论】:

    • 关于"onload listeners"的注释仅适用于&lt;body&gt;元素,此事件和其他一些事件实际上是Window对象的事件,已暴露在 body 元素上。 html.spec.whatwg.org/multipage/… 任何其他拥有自己的onload 属性的元素都会将this 设置为自己。
    • 谢谢!您弄清楚了我真正遇到的问题... onload 这不起作用,而 onclick 起作用。谢谢!
    【解决方案3】:

    试试这个。为了更简洁的代码,我从 HTML 中删除了 javascript。

    function main() {
        console.log(this);
        var cntx = this.getContext("2d");
        cntx.rect(10, 10, 100, 100);
        cntx.fill();
    }
    
    window.onload = function() {
        main.call(document.getElementById('main'));
    }
    <html>
        <head>
            <title>Draw on Canvas</title>
        </head>
        <body>
            <canvas id="main"></canvas>
        </body>
    </html>

    【讨论】:

    • @KitangaNday 为什么在什么情况下?
    • 你为什么要使用this。为什么不给画布一个 id 并获取它的参考?
    • OP 询问我如何提供一个。也许 OP 只是对更复杂的代码库进行简短描述。如何在功能过程中使用“this”是一个有效的问题,对吧?
    • 无论如何,它还是 JavaScript。找到解决方案的途径有很多。
    • 顺便说一句,OP 是什么意思?
    【解决方案4】:

    嗯,做事的方法有很多。

    Javascript 中的元素引用

    要访问一个 DOM 元素,您需要通过给它一个唯一的id 来对其进行标识。

    <canvas id="myCanvas"></canvas>
    

    注意 id 必须是唯一的,如果另一个元素具有相同的 id,浏览器将进入 quirks 模式(见下文)

    然后您可以使用它的 id 作为变量名直接访问它。

     var ctx = myCanvas.getContext("2d");
    

    有些人更喜欢使用更慢更痛苦的。

     var ctx = document.getElementById("myCanvas").getContext("2d");
    

    或其他人使用

     var ctx = document.querySelector("#myCanvas").getContext("2d");
    

    按顺序搞定

    所有这些方法都有一个问题。当浏览器解析一个页面时,它会从上到下一次一个地向 DOM 添加元素。

    如果您在要使用的元素上方添加一些脚本,脚本将无法找到尚未创建的元素

    <canvas id="topCan"></canvas>
    <script> // this code is run when the browser finds it
        var ctx = topCan.getContext("2d"); // works as the element has been created
        var ctx1 = botCan.getContext("2d"); // no work as the element does not yet exist
    </script>
    <canvas id="botCan"></canvas>
    

    所以要确保在元素之后添加脚本(以及在结束正文标记之前,请参阅下面的怪癖模式)

    有时将脚本放在内容之后很不方便。那就是您将代码放入您在加载事件中调用的函数中的时候。在将所有元素添加到页面之前,函数中的代码不会运行。

    如何收听该事件取决于您,见下文

    组织活动

    直接分配事件处理程序被认为是错误的形式

     myCanvas.onclick = function(){};
    

    如果你这样做会更糟

     <canvas onclick = "myFuction(this)"></canvas>
    

    启蒙之路挤满了那些说以下方式就是方式的人

     const canvas = document.querySelector("#myCanvas");   
     canvas.addEventListener("click",myFunction);
     function myFunction(){ /* code */}
    

    上述所有方法都有效,它们都没有对错,还有一些其他的方法。使用什么方法取决于您,我始终建议您使用您认为最容易记住和使用的方法。

    小心怪癖

    但是有些事情你不应该做。原因是某些布局使浏览器认为它回到了 90 年代末 2000 年代初,而你没有遵守规则(实际上没有人知道的规则),为了阻止它在同行旁边看起来很愚蠢,它会切换到 @987654321 @ 这不好,通常会减慢一切。

    可以触发怪癖模式的其中一件事是将脚本标记放置在不应该放置的位置。

    所以永远不要在 body 或 head 标签之外放置脚本标签

    通往世界和平的道路总是把脚本标签放在它们所属的地方。

    <html>
       <head>
          <script></script> <!-- browser is your friend -->
       </head>
       <body>
          <script></script> <!-- browser thinks your great -->
          <p> some content </p>
          <script></script> <!-- and you know everything-->
       </body>
    </html>
    

    通往黑暗的道路。将脚本标签放在任何地方,如下所示

    <script></script> <!-- wrong -->
    <html>
       <script></script> <!-- wrong -->
       <head>
    
       </head>
       <script></script> <!-- oh so bad -->
       <body>
       </body>
       <script></script> <!-- oh so bad -->
    </html>
    <script></script> <!-- just playing with fire -->
    

    一种方式

    我会怎么做取决于当前的潮流

    <html>
        <head>
        <title>Draw on Canvas</title>
        </head>
        <body>
            <!-- id the canvas with a unique id -->
            <canvas id = myCanvas></canvas>
            <script>  // script after the element you are accessing
                const ctx = myCanvas.getContext("2d");
                ctx.rect(10, 10, 100, 100);
                ctx.fill();
             </script> <!-- ensure the script is inside the body tag -->
         </body>
    </html>
    

    【讨论】:

    • 是什么让您认为 getElementById 比 hackish window.namedElement 慢?你知道即使specs 说不要使用它吗?你可能有一个look at this
    • 当标签在 body 或 head 之外时,哪些浏览器会切换到 Quirks?只要有&lt;!DOCTYPE html&gt;,他们就应该遵循无效文档恢复的规范并遵守标准。
    • 非常感谢!这对我来说都是非常有价值的信息。我非常感谢您对 部分的放置位置的见解,对我来说,将它放在身体之外更合乎逻辑,但我看到的是美元惯例。谢谢!
    猜你喜欢
    • 2013-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 2015-10-14
    相关资源
    最近更新 更多