如何实现动态克隆的Canvas对象移出屏幕后自动隐藏?
问题分析与解决方案
首先,你的代码里有一个核心问题:所有克隆出来的Canvas元素都共用了同一个id="test",但HTML规范中id必须是唯一的。这就导致jQuery选择器$('#test')永远只会选中第一个带这个id的元素,后续的克隆、更新和移除逻辑全都会因为这个重复id的问题出现混乱。
接下来我们一步步修复代码,实现“Canvas移出屏幕后自动消失”的需求:
1. 修正HTML结构,移除重复id
把原Canvas的id替换成class,避免后续克隆产生重复标识:
<html> <body> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script type="text/javascript" charset="utf-8" src="cordova-1.7.0.js"></script> <br><br> <script src="myjs1.js"></script> <canvas class="canvas-item"></canvas> </body> </html>
2. 重写JavaScript逻辑,实现正确的克隆与移除
我们需要调整这几个关键点:
- 给每个Canvas设置动态位置,模拟“移出屏幕”的效果
- 定期检查所有Canvas的位置,移除超出屏幕范围的元素
- 合并重复的定时器,避免逻辑不同步
修改后的myjs1.js代码:
$(document).ready(function(){ // 初始化第一个Canvas initCanvas($(".canvas-item:first")); let i = 0; // 合并定时器:每5秒创建新Canvas + 检查移除过期元素 setInterval(function() { i++; // 克隆最新的Canvas模板 const $newCanvas = $(".canvas-item:last").clone(true); // 清空克隆画布的旧内容(重置画布尺寸会自动清空) $newCanvas[0].width = $newCanvas[0].width; // 设置新Canvas的绝对定位与偏移(模拟向右移动,每次偏移200px) $newCanvas.css({ "position": "absolute", "left": `${20 + i * 200}px` }); // 添加到页面中 $("body").append($newCanvas); // 初始化新Canvas的内容 initCanvas($newCanvas, i); // 遍历所有Canvas,移除超出屏幕左侧的元素 $(".canvas-item").each(function() { const $this = $(this); // 计算元素右侧的位置,判断是否完全移出屏幕左边界 const elementRightPos = $this.offset().left + $this.width(); if (elementRightPos < 0) { $this.remove(); } }); }, 5000); // 封装Canvas初始化函数,复用绘制逻辑 function initCanvas($canvas, num = 0) { const c = $canvas[0]; const ctx = c.getContext("2d"); ctx.fillStyle = 'hsl(' + 360 * Math.random() + ', 50%, 50%)'; ctx.fillRect(20, 20, 150, 100); ctx.font="30px Arial"; ctx.fillText(num, 250, 75); ctx.stroke(); } });
3. 关键修复点解释
- 唯一标识问题:用class
.canvas-item代替id,确保所有Canvas都能被正确选中和遍历,不会因为重复id导致选择器失效。 - 位置跟踪与移除:通过
position:absolute和动态left值模拟移动效果,用offset().left计算元素位置,判断是否完全移出屏幕左边界,符合“移出后消失”的需求。 - 画布重置:克隆后的Canvas会继承旧画布内容,通过重置画布尺寸的方式快速清空,再重新绘制新内容。
- 定时器合并:把创建新Canvas和检查移除的逻辑放在同一个定时器里,避免多个定时器导致的执行不同步问题。
针对你原代码问题的补充说明
你之前用$('#test:first').remove()时出现“停止创建”的问题,本质是因为所有克隆元素的id都是test,当你移除第一个#test后,后续的$("#test")会选中下一个带testid的元素,但克隆操作el.before(newone)会在它前面插入新元素,而i>10的判断会持续移除第一个#test,最终导致没有可克隆的元素,看起来像“停止创建”。现在用class管理所有Canvas,就能正确识别每个元素,实现预期的移除效果了。
内容的提问来源于stack exchange,提问作者Panda P
相关产品推荐
相关产品推荐

