画布的getContext("2d")返回null。

44

我已经尝试过几种不同的方法,但每次都卡在同一个错误上。以前我已经加载过一张图片到画布上了,但自从几天前更新了Safari之后,我就一直遇到错误。

我会发布我目前所拥有的代码,但我已经试着用 jQuery、html 的 onLoad 属性等方式来解决问题。

var cvs, ctx, img;
function init() {
   cvs = document.getElementById("profilecanvas");
   ctx = cvs.getContext("2d"); /* Error in getContext("2d") */
   img = document.getElementById("profileImg");
   drawImg();
}

function drawImg() {
   ctx.drawImage(img, 0, 0);
}

window.onload = init();
IDs是正确的,对应了适当的canvas和img标签。然而,我一直收到"TypeError: 'null' is not an object (evaluating 'cvs.getContext')"这个错误,并且似乎没有进展。我确定这是某种错误,但我希望有人能给我一些提示是什么导致了这个问题?谢谢。
编辑:好吧,现在使用似乎可以解决这个问题了。然而,它只偶尔显示,如果我尝试从$(document).ready()或document.onload运行init(),我仍然没有运气,并且会收到错误。有想法吗?
7个回答

136

对于那些在搜索getContext返回null的人,如果您已经请求了不同类型的上下文,它可能会发生。

例如:

var canvas = ...;
var ctx2d = canvas.getContext('2d');
var ctx3d = canvas.getContext('webgl'); // will always be null

如果你颠倒调用的顺序,同样的道理也是适用的。


6
那我已经请求了其他类型的上下文,现在该怎么做才能获得所需的上下文呢? - TSR
@TSR,我有一种感觉这是不可能的,但我不是权威。这个链接可能会有所帮助:https://html.spec.whatwg.org/multipage/scripting.html#the-canvas-element - Drew Noakes
1
如果您需要在画布中同时显示2D和3D,请考虑堆叠两个画布元素,并使最上层具有透明背景。 - Drew Noakes
1
谢谢,很多其他的线程都没有这个答案。我正在使用JeeLiz Face Filters库,它实际上是使用WebGL,而我之前是使用getContext("2d")来进行滤镜处理的。 - OG Sean
正如我所想,对于所有有相同后续问题的人:https://dev59.com/MVrUa4cB1Zd3GeqPoezI(目前的答案是:不行)。 - LuckyLuke Skywalker

35

当你这样做时:

window.onload = init();

函数init()将立即执行(这会导致错误,因为getContext()被过早调用,即在DOM加载之前),并且init()的返回值将存储到window.onload中。

所以你实际上想要做的是:

window.onload = init;
注意缺少了()

1
我和@stslavik一样的问题,在Safari中也是如此。看起来我无法让它工作;即使没有init方法或不同的方法,始终会遇到上下文为空的问题。有什么想法吗? :/ - trainoasis

25

这与实际问题无关,但由于这个问题在谷歌搜索时是第一个结果,我会提供一个解决方法:

请确保使用 getContext("2d") 而不是 getContext("2D") - 注意小写 d


9
只需将JavaScript放在页面的末尾,就能解决问题。我尝试过很多方法,但这是最合理和简单的解决方案。因为JS只会在其他部分(即上半部分)加载后运行。希望这可以帮到你。

1
这是实现无错误JS的基本实践之一,它确实有效。因此,任何投-1的人请重新考虑你的立场,或者至少对此发表评论...如果可以,请纠正我。 - Kunal0615
2
我没有给你点踩,但我怀疑点踩者的原因是,虽然你的问题在某些情况下是最佳实践,但问题包含了一个特定的错误,这个建议并不能解决。换句话说,这可能是善意的建议,但与这个问题无关。 - John
工作了,但仍需要了解在哪些情况下它不起作用。 - Amit Dwivedi

8

需要注意的是,上下文并不总是2d。据我所知,可能的所有值如下:

'2d'
'webgl'
'webgl2'
'experimental-webgl'
'bitmaprenderer'

MDN getContext(): https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext#parameters

从上述MDN文档中:

返回值

一个渲染上下文,它可以是以下类型之一:

如果contextType与可能的绘图上下文不匹配,或者与第一个请求的contextType不同,则返回 null


1
我怎么知道哪个是正确的上下文而不必尝试所有上下文呢?(以及将来可能添加的任何其他上下文) - jumpjack
@jumpjack 如果你第一次在画布上创建上下文,那么你的返回值通常应该与你在getContext()中给出的第一个参数相匹配。如果在只支持webgl(1)的设备上请求webgl2将导致返回值为null。如果你没有先创建上下文,我想不到其他方法,除了猜测和检查。但是,我不是WebGL专家。据我所知,你也可以使用其他方法来检查WebGL2的支持情况。 - Chris Hayes
1
我找到了一个关于“黑客”getContext()函数的答案,以便在创建时保存所选上下文;通过在任何CesiumJS代码之前放置此代码,可以确定CesiumJS使用哪个上下文。https://dev59.com/q4Xca4cB1Zd3GeqPF0Md#26983095。我还发现,我可以将另一个带有2D上下文的画布覆盖到Cesium使用的WebGL上下文上。 - jumpjack

1

确保javascript在canvas HTML元素运行

这是不好的

<body>
    <script src="Canvas.js"></script>
    <canvas id="canvas"></canvas>
</body>

这是好的。
<body>
    <canvas id="canvas"></canvas>
    <script src="Canvas.js"></script>'
</body>

这基本上就是我解决问题的方法


这难道不会导致另一个错误吗?也就是说,无法在空画布元素上调用getContext(),而不是画布元素非空但仍从canvas.getContext("2d")返回null? - ggorlen

0
我曾经遇到同样的问题,现在通过使用var canvas=document.querySelector("canvas");代替var canvas=document.getElementById("canvas");来解决了。
区别在于: var canvas=document.querySelector("canvas");是通过标签名canvas获取元素。 var canvas=document.getElementById("canvas");是通过id名称为canvas获取元素。
你可以试一试。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接