项目场景:使用lottie-web动画插件在前端渲染动画。web端使用框架vue+iview,移动端使用uniapp,为了压缩插件体积,所以使用lottie-web项目中的lottie_light.js或者lottie_light.min.js。
如图:
两者属于统一类型错误,只不过压缩代码时,用i代替RendererClass,所以可以合并解决。
不想深究的同学可以跳过此节,直接查看解决方案。
查看lottie_light.js源码,找到关键几个代码片段:
先搜RendererClass,发现代码报错位置为1740行,附近代码块为:
var animType = 'svg';
if (params.animType) {
animType = params.animType;
} else if (params.renderer) {
animType = params.renderer;
}
var RendererClass = getRenderer(animType);
this.renderer = new RendererClass(this, params.rendererSettings);
我们在new RendererClass前打印此构造函数和对应animType:
console.log(animType)
console.log(RendererClass)
发现最后有一次执行实例化对象时,传入了参数canvas,而此时RendererClass为undefined,这也是可以理解的,因为lottie_light.js之所以更精简,就是去掉了canvas部分的代码。
所以我们寻找getRenderer方法定义的代码,找到代码1674行,构造renderers对象:
var renderers = {};
var registerRenderer = function registerRenderer(key, value) {
renderers[key] = value;
};
function getRenderer(key) {
return renderers[key];
}
如果传入canvas参数时,返回了undefined,说明registerRenderer方法构造的renderers对象就有问题,所以查找在哪里调用了registerRenderer方法,这是构造renderers对象的方法。
找到了代码12552行,如下:
registerRenderer('svg', SVGRenderer); // Registering shape modifiers
我们和lottie.js对应的代码做对比,发现lottie.js中代码如下:
registerRenderer('canvas', CanvasRenderer);
registerRenderer('html', HybridRenderer);
registerRenderer('svg', SVGRenderer); // Registering shape modifiers
也就是说lottie.js不会报错是因为不论animType参数是什么,都有对应的方法构造正确的renderers对象,而现在传入了canvas参数,却没有对应的CanvasRenderer构造函数,所以报错。
两种方式:
params.animType = wrapperAttributes.getNamedItem('data-anim-type') // eslint-disable-line no-nested-ternary
? wrapperAttributes.getNamedItem('data-anim-type').value : wrapperAttributes.getNamedItem('data-bm-type') // eslint-disable-line no-nested-ternary
? wrapperAttributes.getNamedItem('data-bm-type').value : wrapperAttributes.getNamedItem('bm-type') // eslint-disable-line no-nested-ternary
? wrapperAttributes.getNamedItem('bm-type').value : wrapperAttributes.getNamedItem('data-bm-renderer') // eslint-disable-line no-nested-ternary
? wrapperAttributes.getNamedItem('data-bm-renderer').value : wrapperAttributes.getNamedItem('bm-renderer') ? wrapperAttributes.getNamedItem('bm-renderer').value : 'canvas';
这段代码在用三元判断一直判断各种情况下如何给params.animType赋值,最后如果都不符合,就赋值canvas。我们把canvas改成svg就不会报错了。如下:
params.animType = wrapperAttributes.getNamedItem('data-anim-type') // eslint-disable-line no-nested-ternary
? wrapperAttributes.getNamedItem('data-anim-type').value : wrapperAttributes.getNamedItem('data-bm-type') // eslint-disable-line no-nested-ternary
? wrapperAttributes.getNamedItem('data-bm-type').value : wrapperAttributes.getNamedItem('bm-type') // eslint-disable-line no-nested-ternary
? wrapperAttributes.getNamedItem('bm-type').value : wrapperAttributes.getNamedItem('data-bm-renderer') // eslint-disable-line no-nested-ternary
? wrapperAttributes.getNamedItem('data-bm-renderer').value : wrapperAttributes.getNamedItem('bm-renderer') ? wrapperAttributes.getNamedItem('bm-renderer').value : 'svg';
registerRenderer('canvas', SVGRenderer) //这里只能使用SVGRenderer
registerRenderer('svg', SVGRenderer)
上面这两种修改方法我也不知道哪个影响会更大,因为我并没有看懂作者把 params.animType 设置成canvas默认的意图,如果在使用lottie时,renderer参数不设置,默认是渲染成svg的,我在页面也没有找到任何canvas相关元素,那么这里的canvas究竟是在渲染什么呢?
我目前采用的第一种解决方案。lottie_light_min.js代码修改方式同理。
修改lottie_light_min.js可以简单点搜"bm-renderer",最后一个后面那个canvas改成svg或者空字符串