使用lottie_light.js或者lottie_light_min.js,报错RendererClass is not a constructor或者i is not a constructor

项目场景:

项目场景:使用lottie-web动画插件在前端渲染动画。web端使用框架vue+iview,移动端使用uniapp,为了压缩插件体积,所以使用lottie-web项目中的lottie_light.js或者lottie_light.min.js。


问题描述

  1. 使用lottie_light_min.js时,前端报错i is not a constructor;
  2. 使用lottie_light.js时,前端报错RendererClass is not a constructor;

如图:
在这里插入图片描述
两者属于统一类型错误,只不过压缩代码时,用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构造函数,所以报错。


解决方案:

两种方式:

  1. 正常情况,lottie_light.js不应该有canvas参数,所以我们去找在哪里给animType参数赋值canvas,找到代码1802行:
 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';
  1. 上面说到第12552行代码,正常情况下应该是有三个构造renderers的方法的,但是lottie_light.js只保留了svg的方式,所以当传入canvas时报错了,那么我们保证传入canvas时,也使用svg的构造函数就可以了,所以12552行代码改为:
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或者空字符串

猜你喜欢

转载自blog.csdn.net/zjsj_lize/article/details/128715983