简体   繁体   中英

Javascript 'this' to pass a canvas to function on page load

I am trying to pass the canvas HTML element as a parameter, and I thought 'this' would work but I can't quite get it to. Could someone help me use the 'this' keyword to pass the canvas to main() upon page-load, please?

Doesn't work:

<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>

Works, but would like to use the 'this' keyword instead:

<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>

Doesn't work (onload not defined for canvas element):

<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>

Works, and uses 'this', but want the code to run without clicking:

<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>

I suggest you consider a different approach as you risk complicating the expressiveness of your overall scripting logic if you're mixing it into your HTML tags. More to your point, while you can't use onload in an HTML tag context to get any this beyond the window, you can create JS functions that are defined to execute after window.onload in any fashion you want.

You're already using JavaScript to define your canvas attributes, why not create the canvas in JS at the same time!

You can also see how this could be extended to open up your options on creating/appending more canvasses on the fly.

If this doesn't work for you, let me know if this was an abstracted question for an issue that I might be able to help with more directly.

 <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> 

Try this. I put javascript out from HTML for more cleaner code.

 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> 

Your problem is with the use of onload .

Typically, a listener attached in-line is called as if wrapped in an outer function with it's this set to the element on which the listener is called. However, that's not the case for onload listeners attached to the body element . Their execution is delayed and they are called with the global / window object set to this .

So you can't use this the way you're trying to do it.

The following demonstrates that a the body's load listener is called with this as the global object, but the div's click listener is called with the div element as 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> 

Well so many ways to do things.

Element referencing in Javascript

To access a DOM element you need to id it by giving it a unique id .

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

Note id Must be unique, if another element has the same id the browser will enter quirks mode (see below)

You can then access it directly using its id as a variable name.

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

There are some that prefer to use the slower and more painful.

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

Or others use

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

Get it in order

All these methods have one problem. When a browser parses a page it adds elements to the DOM one at a time from the top down.

If you add some script above the elements you want to use, the script will not find the elements as they have not yet been created

<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>

So to make sure you add the script after the elements (and before the closing body tag see quirks mode below)

Sometimes its just plain inconvenient for you to put the script after the content. That is when you would put the code inside a function you call on the load event. The code in the function will not run until all the elements have been added to the page.

How you listen to that event is up to you, see below

Organizing an event

It is considered bad form to assign an event handler directly

 myCanvas.onclick = function(){};

and even worse if you do

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

with the road of enlightenment packed with those that say the following way is the way

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

All the above methods work, none of them are right or wrong, there are a few other ways as well. What method you use is up to you, I always recommend that you use the method you find easiest to remember and use.

Careful of the quirks

But there are some things you should not do. The reason is that some layouts make the browser think its back in the late 90's early 2000's, and you have not followed the rules (rules that nobody actually knew), to stop it's self looking stupid next to its peers it will switch to quirks mode which is not good and will generally slow everything down.

One of the things that can trigger quirks mode is placing a script tag where it should not be.

So NEVER put a script tag outside the body or head tags

The path to world peace is always put script tags where they belong.

<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>

The way to darkness. Putting a script tag anywhere as follows

<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 -->

One way

How I would do depends on the tide so currently

<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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM