FabricJS中loadFromJSON加载视频背景空白问题(Angular6)
解决FabricJS loadFromJSON后视频背景空白的问题
我帮你排查了这个问题,核心原因是FabricJS的JSON序列化不会保存实际的DOM元素(比如video元素),只会记录对象的属性配置。所以当你调用loadFromJSON后,背景里的视频元素并没有被重新实例化,导致画布背景变成空白。下面是具体的修复方案:
关键修复点
- 确保序列化时正确保留视频的自定义属性(你已经做了这一步,但需要在加载时正确读取)
- 在
loadFromJSON的回调函数中,重新创建video DOM元素,并将其设置为画布背景 - 修正回调中的
this指向问题,以及renderAll的调用方式(不能只bind,要实际调用) - 确保视频播放和渲染循环正常启动
修改后的完整代码
<button id="loadfromjson">Load from JSON</button> <canvas id="c" width="600" height="400"></canvas> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.min.js?v1"></script> <script> var removeFromArray = fabric.util.removeFromArray; var custom_attributes = ['customSourceType', 'id', 'scaleMode', 'original_src', 'exclusiveName', 'video_src', 'background_image']; // 扩展Fabric对象的toObject方法,保留视频相关属性 fabric.Object.prototype.toObject = (function(toObject) { return function(propertiesToInclude) { propertiesToInclude = (propertiesToInclude || []).concat([ 'video_src', 'background_image', 'src' ]); return toObject.apply(this, [propertiesToInclude]); }; })(fabric.Object.prototype.toObject); fabric.Object.NUM_FRACTION_DIGITS = 2; fabric.Object.prototype.set({ borderColor: '#00c3f9', cornerColor: '#00c3f9', cornerStrokeColor: '#ffffff', cornerStyle: 'circle', minScaleLimit: 0, lockScalingFlip: true, selectionDashArray: [5, 0], borderDashArray: [5, 5], cornerDashArray: [2, 0], borderScaleFactor: 1, cornerSize: 15, transparentCorners: false, centeredRotation: true }); var canvas = new fabric.Canvas('c', { hoverCursor: 'pointer', selection: true, selectionBorderColor: '#00c3f9', selectionColor: 'rgba(0, 195, 249, 0.2)', preserveObjectStacking: true, originX: 'center', originY: 'center', }); var url_mp4 = 'http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4'; // 封装创建视频元素的函数,方便复用 function getVideoElement(url, width = 400, height = 250) { var videoE = document.createElement('video'); videoE.width = width; videoE.height = height; videoE.muted = true; videoE.crossOrigin = "anonymous"; var source = document.createElement('source'); source.src = url; source.type = 'video/mp4'; videoE.appendChild(source); return videoE; } // 初始化视频背景 function initVideoBackground(url) { var videoE = getVideoElement(url, canvas.width, canvas.height); var fab_video = new fabric.Image(videoE, {left: 0, top: 0}); fab_video.set('video_src', url); fab_video.set('background_image', url); canvas.setBackgroundImage(fab_video); fab_video.getElement().volume = 0; fab_video.getElement().play(); // 启动渲染循环,保证视频帧正常更新 fabric.util.requestAnimFrame(function render() { canvas.renderAll(); fabric.util.requestAnimFrame(render); }); } // 初始化 initVideoBackground(url_mp4); // 保存和加载事件 $(document.body).on('click', '#loadfromjson', function(){ console.clear(); var json = canvas.toJSON(custom_attributes); canvas.loadFromJSON(json, function() { // 加载完成后的回调,恢复视频背景 var canvasBG = canvas.backgroundImage; if(canvasBG && canvasBG.video_src) { initVideoBackground(canvasBG.video_src); } canvas.renderAll(); }); }); </script>
代码说明
- 封装初始化函数:把视频背景的创建逻辑封装成
initVideoBackground,方便初始化和加载后重复调用 - 修复加载回调:在
loadFromJSON的回调中,直接读取背景对象的video_src属性,调用初始化函数重建视频背景 - 修正渲染逻辑:确保渲染循环正确启动,保证视频帧能持续更新到画布上
- 统一尺寸处理:创建视频元素时使用画布的宽高,避免尺寸不匹配
这样修改后,你点击Load from JSON按钮时,视频背景就能正常恢复了。
内容的提问来源于stack exchange,提问作者Umesh Patadiya
相关产品推荐
相关产品推荐

