/*!
 * Vue-Lazyload.js v1.3.5
 * (c) 2023 Awe <hilongjw@gmail.com>
 * Released under the MIT License.
 */

function createCommonjsModule(fn, module) {
	return module = { exports: {} }, fn(module, module.exports), module.exports;
}

var assignSymbols$1 = createCommonjsModule(function (module) {

  var toString = Object.prototype.toString;
  var isEnumerable = Object.prototype.propertyIsEnumerable;
  var getSymbols = Object.getOwnPropertySymbols;

  module.exports = function (target) {
    for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
      args[_key - 1] = arguments[_key];
    }

    if (!isObject(target)) {
      throw new TypeError('expected the first argument to be an object');
    }

    if (args.length === 0 || typeof Symbol !== 'function' || typeof getSymbols !== 'function') {
      return target;
    }

    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;

    try {
      for (var _iterator = args[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
        var arg = _step.value;

        var names = getSymbols(arg);

        var _iteratorNormalCompletion2 = true;
        var _didIteratorError2 = false;
        var _iteratorError2 = undefined;

        try {
          for (var _iterator2 = names[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
            var key = _step2.value;

            if (isEnumerable.call(arg, key)) {
              target[key] = arg[key];
            }
          }
        } catch (err) {
          _didIteratorError2 = true;
          _iteratorError2 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion2 && _iterator2.return) {
              _iterator2.return();
            }
          } finally {
            if (_didIteratorError2) {
              throw _iteratorError2;
            }
          }
        }
      }
    } catch (err) {
      _didIteratorError = true;
      _iteratorError = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion && _iterator.return) {
          _iterator.return();
        }
      } finally {
        if (_didIteratorError) {
          throw _iteratorError;
        }
      }
    }

    return target;
  };

  function isObject(val) {
    return typeof val === 'function' || toString.call(val) === '[object Object]' || Array.isArray(val);
  }
});

var assignSymbols$2 = /*#__PURE__*/Object.freeze({
	__proto__: null,
	'default': assignSymbols$1,
	__moduleExports: assignSymbols$1
});

var assignSymbols = ( assignSymbols$2 && assignSymbols$1 ) || assignSymbols$2;

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
  return typeof obj;
} : function (obj) {
  return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};

var classCallCheck = function (instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
};

var createClass = function () {
  function defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }

  return function (Constructor, protoProps, staticProps) {
    if (protoProps) defineProperties(Constructor.prototype, protoProps);
    if (staticProps) defineProperties(Constructor, staticProps);
    return Constructor;
  };
}();

var assignDeep = createCommonjsModule(function (module) {

  var toString = Object.prototype.toString;

  var isValidKey = function isValidKey(key) {
    return key !== '__proto__' && key !== 'constructor' && key !== 'prototype';
  };

  var assign = module.exports = function (target) {
    for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
      args[_key - 1] = arguments[_key];
    }

    var i = 0;
    if (isPrimitive(target)) target = args[i++];
    if (!target) target = {};
    for (; i < args.length; i++) {
      if (isObject(args[i])) {
        var _iteratorNormalCompletion = true;
        var _didIteratorError = false;
        var _iteratorError = undefined;

        try {
          for (var _iterator = Object.keys(args[i])[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
            var key = _step.value;

            if (isValidKey(key)) {
              if (isObject(target[key]) && isObject(args[i][key])) {
                assign(target[key], args[i][key]);
              } else {
                target[key] = args[i][key];
              }
            }
          }
        } catch (err) {
          _didIteratorError = true;
          _iteratorError = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion && _iterator.return) {
              _iterator.return();
            }
          } finally {
            if (_didIteratorError) {
              throw _iteratorError;
            }
          }
        }

        assignSymbols(target, args[i]);
      }
    }
    return target;
  };

  function isObject(val) {
    return typeof val === 'function' || toString.call(val) === '[object Object]';
  }

  function isPrimitive(val) {
    return (typeof val === 'undefined' ? 'undefined' : _typeof(val)) === 'object' ? val === null : typeof val !== 'function';
  }
});

var inBrowser = typeof window !== 'undefined' && window !== null;

var hasIntersectionObserver = checkIntersectionObserver();

function checkIntersectionObserver() {
  if (inBrowser && 'IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype) {
    // Minimal polyfill for Edge 15's lack of `isIntersecting`
    // See: https://github.com/w3c/IntersectionObserver/issues/211
    if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
      Object.defineProperty(window.IntersectionObserverEntry.prototype, 'isIntersecting', {
        get: function get() {
          return this.intersectionRatio > 0;
        }
      });
    }
    return true;
  }
  return false;
}

var modeType = {
  event: 'event',
  observer: 'observer'

  // CustomEvent polyfill for IE
};var CustomEvent = function () {
  if (!inBrowser) return;
  // not IE
  if (typeof window.CustomEvent === 'function') return window.CustomEvent;
  function CustomEvent(event, params) {
    params = params || { bubbles: false, cancelable: false, detail: undefined };
    var evt = document.createEvent('CustomEvent');
    evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
    return evt;
  }
  CustomEvent.prototype = window.Event.prototype;
  return CustomEvent;
}();

function remove(arr, item) {
  if (!arr.length) return;
  var index = arr.indexOf(item);
  if (index > -1) return arr.splice(index, 1);
}

function some(arr, fn) {
  var has = false;
  for (var i = 0, len = arr.length; i < len; i++) {
    if (fn(arr[i])) {
      has = true;
      break;
    }
  }
  return has;
}

function getBestSelectionFromSrcset(el, scale) {
  if (el.tagName !== 'IMG' || !el.getAttribute('data-srcset')) return;

  var options = el.getAttribute('data-srcset');
  var result = [];
  var container = el.parentNode;
  var containerWidth = container.offsetWidth * scale;

  var spaceIndex = void 0;
  var tmpSrc = void 0;
  var tmpWidth = void 0;

  options = options.trim().split(',');

  options.map(function (item) {
    item = item.trim();
    spaceIndex = item.lastIndexOf(' ');
    if (spaceIndex === -1) {
      tmpSrc = item;
      tmpWidth = 999998;
    } else {
      tmpSrc = item.substr(0, spaceIndex);
      tmpWidth = parseInt(item.substr(spaceIndex + 1, item.length - spaceIndex - 2), 10);
    }
    result.push([tmpWidth, tmpSrc]);
  });

  result.sort(function (a, b) {
    if (a[0] < b[0]) {
      return 1;
    }
    if (a[0] > b[0]) {
      return -1;
    }
    if (a[0] === b[0]) {
      if (b[1].indexOf('.webp', b[1].length - 5) !== -1) {
        return 1;
      }
      if (a[1].indexOf('.webp', a[1].length - 5) !== -1) {
        return -1;
      }
    }
    return 0;
  });
  var bestSelectedSrc = '';
  var tmpOption = void 0;

  for (var i = 0; i < result.length; i++) {
    tmpOption = result[i];
    bestSelectedSrc = tmpOption[1];
    var next = result[i + 1];
    if (next && next[0] < containerWidth) {
      bestSelectedSrc = tmpOption[1];
      break;
    } else if (!next) {
      bestSelectedSrc = tmpOption[1];
      break;
    }
  }

  return bestSelectedSrc;
}

function find(arr, fn) {
  var item = void 0;
  for (var i = 0, len = arr.length; i < len; i++) {
    if (fn(arr[i])) {
      item = arr[i];
      break;
    }
  }
  return item;
}

var getDPR = function getDPR() {
  var scale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
  return inBrowser ? window.devicePixelRatio || scale : scale;
};

function supportWebp() {
  if (!inBrowser) return false;

  var support = true;

  try {
    var elem = document.createElement('canvas');

    if (elem.getContext && elem.getContext('2d')) {
      support = elem.toDataURL('image/webp').indexOf('data:image/webp') === 0;
    }
  } catch (err) {
    support = false;
  }

  return support;
}

function throttle(action, delay) {
  var timeout = null;
  var movement = null;
  var lastRun = 0;
  var needRun = false;
  return function () {
    needRun = true;
    if (timeout) {
      return;
    }
    var elapsed = Date.now() - lastRun;
    var context = this;
    var args = arguments;
    var runCallback = function runCallback() {
      lastRun = Date.now();
      timeout = false;
      action.apply(context, args);
    };
    if (elapsed >= delay) {
      runCallback();
    } else {
      timeout = setTimeout(runCallback, delay);
    }
    if (needRun) {
      clearTimeout(movement);
      movement = setTimeout(runCallback, 2 * delay);
    }
  };
}

function testSupportsPassive() {
  if (!inBrowser) return;
  var support = false;
  try {
    var opts = Object.defineProperty({}, 'passive', {
      get: function get() {
        support = true;
      }
    });
    window.addEventListener('test', null, opts);
  } catch (e) {}
  return support;
}

var supportsPassive = testSupportsPassive();

var _ = {
  on: function on(el, type, func) {
    var capture = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;

    if (supportsPassive) {
      el.addEventListener(type, func, {
        capture: capture,
        passive: true
      });
    } else {
      el.addEventListener(type, func, capture);
    }
  },
  off: function off(el, type, func) {
    var capture = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;

    el.removeEventListener(type, func, capture);
  }
};

var loadImageAsync = function loadImageAsync(item, resolve, reject) {
  var image = new Image();
  if (!item || !item.src) {
    var err = new Error('image src is required');
    return reject(err);
  }

  image.src = item.src;
  if (item.cors) {
    image.crossOrigin = item.cors;
  }

  image.onload = function () {
    resolve({
      naturalHeight: image.naturalHeight,
      naturalWidth: image.naturalWidth,
      src: image.src
    });
  };

  image.onerror = function (e) {
    reject(e);
  };
};

var style = function style(el, prop) {
  return typeof getComputedStyle !== 'undefined' ? getComputedStyle(el, null).getPropertyValue(prop) : el.style[prop];
};

var overflow = function overflow(el) {
  return style(el, 'overflow') + style(el, 'overflow-y') + style(el, 'overflow-x');
};

var scrollParent = function scrollParent(el) {
  if (!inBrowser) return;
  if (!(el instanceof HTMLElement)) {
    return window;
  }

  var parent = el;

  while (parent) {
    if (parent === document.body || parent === document.documentElement) {
      break;
    }

    if (!parent.parentNode) {
      break;
    }

    if (/(scroll|auto)/.test(overflow(parent))) {
      return parent;
    }

    parent = parent.parentNode;
  }

  return window;
};

function isObject(obj) {
  return obj !== null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object';
}

function ObjectKeys(obj) {
  if (!(obj instanceof Object)) return [];
  if (Object.keys) {
    return Object.keys(obj);
  } else {
    var keys = [];
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        keys.push(key);
      }
    }
    return keys;
  }
}

function ArrayFrom(arrLike) {
  var len = arrLike.length;
  var list = [];
  for (var i = 0; i < len; i++) {
    list.push(arrLike[i]);
  }
  return list;
}

function noop() {}

var ImageCache = function () {
  function ImageCache(_ref) {
    var max = _ref.max;
    classCallCheck(this, ImageCache);

    this.options = {
      max: max || 100
    };
    this._caches = [];
  }

  createClass(ImageCache, [{
    key: 'has',
    value: function has(key) {
      return this._caches.indexOf(key) > -1;
    }
  }, {
    key: 'add',
    value: function add(key) {
      if (this.has(key)) return;
      this._caches.push(key);
      if (this._caches.length > this.options.max) {
        this.free();
      }
    }
  }, {
    key: 'free',
    value: function free() {
      this._caches.shift();
    }
  }]);
  return ImageCache;
}();

// el: {
//     state,
//     src,
//     error,
//     loading
// }

var ReactiveListener = function () {
  function ReactiveListener(_ref) {
    var el = _ref.el,
        src = _ref.src,
        error = _ref.error,
        loading = _ref.loading,
        bindType = _ref.bindType,
        $parent = _ref.$parent,
        options = _ref.options,
        cors = _ref.cors,
        elRenderer = _ref.elRenderer,
        imageCache = _ref.imageCache;
    classCallCheck(this, ReactiveListener);

    this.el = el;
    this.src = src;
    this.error = error;
    this.loading = loading;
    this.bindType = bindType;
    this.attempt = 0;
    this.cors = cors;

    this.naturalHeight = 0;
    this.naturalWidth = 0;

    this.options = options;

    this.rect = null;

    this.$parent = $parent;
    this.elRenderer = elRenderer;
    this._imageCache = imageCache;
    this.performanceData = {
      init: Date.now(),
      loadStart: 0,
      loadEnd: 0
    };

    this.filter();
    this.initState();
    this.render('loading', false);
  }

  /*
   * init listener state
   * @return
   */


  createClass(ReactiveListener, [{
    key: 'initState',
    value: function initState() {
      if ('dataset' in this.el) {
        this.el.dataset.src = this.src;
      } else {
        this.el.setAttribute('data-src', this.src);
      }

      this.state = {
        loading: false,
        error: false,
        loaded: false,
        rendered: false
      };
    }

    /*
     * record performance
     * @return
     */

  }, {
    key: 'record',
    value: function record(event) {
      this.performanceData[event] = Date.now();
    }

    /*
     * update image listener data
     * @param  {String} image uri
     * @param  {String} loading image uri
     * @param  {String} error image uri
     * @return
     */

  }, {
    key: 'update',
    value: function update(_ref2) {
      var src = _ref2.src,
          loading = _ref2.loading,
          error = _ref2.error;

      var oldSrc = this.src;
      this.src = src;
      this.loading = loading;
      this.error = error;
      this.filter();
      if (oldSrc !== this.src) {
        this.attempt = 0;
        this.initState();
      }
    }

    /*
     * get el node rect
     * @return
     */

  }, {
    key: 'getRect',
    value: function getRect() {
      this.rect = this.el.getBoundingClientRect();
    }

    /*
     *  check el is in view
     * @return {Boolean} el is in view
     */

  }, {
    key: 'checkInView',
    value: function checkInView() {
      this.getRect();
      return this.rect.top < window.innerHeight * this.options.preLoad && this.rect.bottom > this.options.preLoadTop && this.rect.left < window.innerWidth * this.options.preLoad && this.rect.right > 0;
    }

    /*
     * listener filter
     */

  }, {
    key: 'filter',
    value: function filter() {
      var _this = this;

      ObjectKeys(this.options.filter).map(function (key) {
        _this.options.filter[key](_this, _this.options);
      });
    }

    /*
     * render loading first
     * @params cb:Function
     * @return
     */

  }, {
    key: 'renderLoading',
    value: function renderLoading(cb) {
      var _this2 = this;

      this.state.loading = true;
      loadImageAsync({
        src: this.loading,
        cors: this.cors
      }, function (data) {
        _this2.render('loading', false);
        _this2.state.loading = false;
        cb();
      }, function () {
        // handler `loading image` load failed
        cb();
        _this2.state.loading = false;
        if (!_this2.options.silent) console.warn('VueLazyload log: load failed with loading image(' + _this2.loading + ')');
      });
    }

    /*
     * try load image and  render it
     * @return
     */

  }, {
    key: 'load',
    value: function load() {
      var _this3 = this;

      var onFinish = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : noop;

      if (this.attempt > this.options.attempt - 1 && this.state.error) {
        if (!this.options.silent) console.log('VueLazyload log: ' + this.src + ' tried too more than ' + this.options.attempt + ' times');
        onFinish();
        return;
      }
      if (this.state.rendered && this.state.loaded) return;
      if (this._imageCache.has(this.src)) {
        this.state.loaded = true;
        this.render('loaded', true);
        this.state.rendered = true;
        return onFinish();
      }

      this.renderLoading(function () {
        _this3.attempt++;

        _this3.options.adapter['beforeLoad'] && _this3.options.adapter['beforeLoad'](_this3, _this3.options);
        _this3.record('loadStart');

        loadImageAsync({
          src: _this3.src,
          cors: _this3.cors
        }, function (data) {
          _this3.naturalHeight = data.naturalHeight;
          _this3.naturalWidth = data.naturalWidth;
          _this3.state.loaded = true;
          _this3.state.error = false;
          _this3.record('loadEnd');
          _this3.render('loaded', false);
          _this3.state.rendered = true;
          _this3._imageCache.add(_this3.src);
          onFinish();
        }, function (err) {
          !_this3.options.silent && console.error(err);
          _this3.state.error = true;
          _this3.state.loaded = false;
          _this3.render('error', false);
        });
      });
    }

    /*
     * render image
     * @param  {String} state to render // ['loading', 'src', 'error']
     * @param  {String} is form cache
     * @return
     */

  }, {
    key: 'render',
    value: function render(state, cache) {
      this.elRenderer(this, state, cache);
    }

    /*
     * output performance data
     * @return {Object} performance data
     */

  }, {
    key: 'performance',
    value: function performance() {
      var state = 'loading';
      var time = 0;

      if (this.state.loaded) {
        state = 'loaded';
        time = (this.performanceData.loadEnd - this.performanceData.loadStart) / 1000;
      }

      if (this.state.error) state = 'error';

      return {
        src: this.src,
        state: state,
        time: time
      };
    }

    /*
     * $destroy
     * @return
     */

  }, {
    key: '$destroy',
    value: function $destroy() {
      this.el = null;
      this.src = null;
      this.error = null;
      this.loading = null;
      this.bindType = null;
      this.attempt = 0;
    }
  }]);
  return ReactiveListener;
}();

var DEFAULT_URL = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
var DEFAULT_EVENTS = ['scroll', 'wheel', 'mousewheel', 'resize', 'animationend', 'transitionend', 'touchmove'];
var DEFAULT_OBSERVER_OPTIONS = {
  rootMargin: '0px',
  threshold: 0
};

function Lazy(Vue) {
  return function () {
    function Lazy(_ref) {
      var preLoad = _ref.preLoad,
          error = _ref.error,
          throttleWait = _ref.throttleWait,
          preLoadTop = _ref.preLoadTop,
          dispatchEvent = _ref.dispatchEvent,
          loading = _ref.loading,
          attempt = _ref.attempt,
          _ref$silent = _ref.silent,
          silent = _ref$silent === undefined ? true : _ref$silent,
          scale = _ref.scale,
          listenEvents = _ref.listenEvents;
          _ref.hasbind;
          var filter = _ref.filter,
          adapter = _ref.adapter,
          observer = _ref.observer,
          observerOptions = _ref.observerOptions;
      classCallCheck(this, Lazy);

      this.version = '"1.3.5"';
      this.mode = modeType.event;
      this.ListenerQueue = [];
      this.TargetIndex = 0;
      this.TargetQueue = [];
      this.options = {
        silent: silent,
        dispatchEvent: !!dispatchEvent,
        throttleWait: throttleWait || 200,
        preLoad: preLoad || 1.3,
        preLoadTop: preLoadTop || 0,
        error: error || DEFAULT_URL,
        loading: loading || DEFAULT_URL,
        attempt: attempt || 3,
        scale: scale || getDPR(scale),
        ListenEvents: listenEvents || DEFAULT_EVENTS,
        hasbind: false,
        supportWebp: supportWebp(),
        filter: filter || {},
        adapter: adapter || {},
        observer: !!observer,
        observerOptions: observerOptions || DEFAULT_OBSERVER_OPTIONS
      };
      this._initEvent();
      this._imageCache = new ImageCache({ max: 200 });
      this.lazyLoadHandler = throttle(this._lazyLoadHandler.bind(this), this.options.throttleWait);

      this.setMode(this.options.observer ? modeType.observer : modeType.event);
    }

    /**
     * update config
     * @param  {Object} config params
     * @return
     */


    createClass(Lazy, [{
      key: 'config',
      value: function config() {
        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        assignDeep(this.options, options);
      }

      /**
       * output listener's load performance
       * @return {Array}
       */

    }, {
      key: 'performance',
      value: function performance() {
        var list = [];

        this.ListenerQueue.map(function (item) {
          list.push(item.performance());
        });

        return list;
      }

      /*
       * add lazy component to queue
       * @param  {Vue} vm lazy component instance
       * @return
       */

    }, {
      key: 'addLazyBox',
      value: function addLazyBox(vm) {
        this.ListenerQueue.push(vm);
        if (inBrowser) {
          this._addListenerTarget(window);
          this._observer && this._observer.observe(vm.el);
          if (vm.$el && vm.$el.parentNode) {
            this._addListenerTarget(vm.$el.parentNode);
          }
        }
      }

      /*
       * add image listener to queue
       * @param  {DOM} el
       * @param  {object} binding vue directive binding
       * @param  {vnode} vnode vue directive vnode
       * @return
       */

    }, {
      key: 'add',
      value: function add(el, binding, vnode) {
        var _this = this;

        if (some(this.ListenerQueue, function (item) {
          return item.el === el;
        })) {
          this.update(el, binding);
          return Vue.nextTick(this.lazyLoadHandler);
        }

        var _valueFormatter2 = this._valueFormatter(binding.value),
            src = _valueFormatter2.src,
            loading = _valueFormatter2.loading,
            error = _valueFormatter2.error,
            cors = _valueFormatter2.cors;

        Vue.nextTick(function () {
          src = getBestSelectionFromSrcset(el, _this.options.scale) || src;
          _this._observer && _this._observer.observe(el);

          var container = Object.keys(binding.modifiers)[0];
          var $parent = void 0;

          if (container) {
            $parent = vnode.context.$refs[container];
            // if there is container passed in, try ref first, then fallback to getElementById to support the original usage
            $parent = $parent ? $parent.$el || $parent : document.getElementById(container);
          }

          if (!$parent) {
            $parent = scrollParent(el);
          }

          var newListener = new ReactiveListener({
            bindType: binding.arg,
            $parent: $parent,
            el: el,
            loading: loading,
            error: error,
            src: src,
            cors: cors,
            elRenderer: _this._elRenderer.bind(_this),
            options: _this.options,
            imageCache: _this._imageCache
          });

          _this.ListenerQueue.push(newListener);

          if (inBrowser) {
            _this._addListenerTarget(window);
            _this._addListenerTarget($parent);
          }

          _this.lazyLoadHandler();
          Vue.nextTick(function () {
            return _this.lazyLoadHandler();
          });
        });
      }

      /**
      * update image src
      * @param  {DOM} el
      * @param  {object} vue directive binding
      * @return
      */

    }, {
      key: 'update',
      value: function update(el, binding, vnode) {
        var _this2 = this;

        var _valueFormatter3 = this._valueFormatter(binding.value),
            src = _valueFormatter3.src,
            loading = _valueFormatter3.loading,
            error = _valueFormatter3.error;

        src = getBestSelectionFromSrcset(el, this.options.scale) || src;

        var exist = find(this.ListenerQueue, function (item) {
          return item.el === el;
        });
        if (!exist) {
          this.add(el, binding, vnode);
        } else {
          exist.update({
            src: src,
            loading: loading,
            error: error
          });
        }
        if (this._observer) {
          this._observer.unobserve(el);
          this._observer.observe(el);
        }
        this.lazyLoadHandler();
        Vue.nextTick(function () {
          return _this2.lazyLoadHandler();
        });
      }

      /**
      * remove listener form list
      * @param  {DOM} el
      * @return
      */

    }, {
      key: 'remove',
      value: function remove$1(el) {
        if (!el) return;
        this._observer && this._observer.unobserve(el);
        var existItem = find(this.ListenerQueue, function (item) {
          return item.el === el;
        });
        if (existItem) {
          this._removeListenerTarget(existItem.$parent);
          this._removeListenerTarget(window);
          remove(this.ListenerQueue, existItem);
          existItem.$destroy();
        }
      }

      /*
       * remove lazy components form list
       * @param  {Vue} vm Vue instance
       * @return
       */

    }, {
      key: 'removeComponent',
      value: function removeComponent(vm) {
        if (!vm) return;
        remove(this.ListenerQueue, vm);
        this._observer && this._observer.unobserve(vm.el);
        if (vm.$parent && vm.$el.parentNode) {
          this._removeListenerTarget(vm.$el.parentNode);
        }
        this._removeListenerTarget(window);
      }
    }, {
      key: 'setMode',
      value: function setMode(mode) {
        var _this3 = this;

        if (!hasIntersectionObserver && mode === modeType.observer) {
          mode = modeType.event;
        }

        this.mode = mode; // event or observer

        if (mode === modeType.event) {
          if (this._observer) {
            this.ListenerQueue.forEach(function (listener) {
              _this3._observer.unobserve(listener.el);
            });
            this._observer = null;
          }

          this.TargetQueue.forEach(function (target) {
            _this3._initListen(target.el, true);
          });
        } else {
          this.TargetQueue.forEach(function (target) {
            _this3._initListen(target.el, false);
          });
          this._initIntersectionObserver();
        }
      }

      /*
      *** Private functions ***
      */

      /*
       * add listener target
       * @param  {DOM} el listener target
       * @return
       */

    }, {
      key: '_addListenerTarget',
      value: function _addListenerTarget(el) {
        if (!el) return;
        var target = find(this.TargetQueue, function (target) {
          return target.el === el;
        });
        if (!target) {
          target = {
            el: el,
            id: ++this.TargetIndex,
            childrenCount: 1,
            listened: true
          };
          this.mode === modeType.event && this._initListen(target.el, true);
          this.TargetQueue.push(target);
        } else {
          target.childrenCount++;
        }
        return this.TargetIndex;
      }

      /*
       * remove listener target or reduce target childrenCount
       * @param  {DOM} el or window
       * @return
       */

    }, {
      key: '_removeListenerTarget',
      value: function _removeListenerTarget(el) {
        var _this4 = this;

        this.TargetQueue.forEach(function (target, index) {
          if (target.el === el) {
            target.childrenCount--;
            if (!target.childrenCount) {
              _this4._initListen(target.el, false);
              _this4.TargetQueue.splice(index, 1);
              target = null;
            }
          }
        });
      }

      /*
       * add or remove eventlistener
       * @param  {DOM} el DOM or Window
       * @param  {boolean} start flag
       * @return
       */

    }, {
      key: '_initListen',
      value: function _initListen(el, start) {
        var _this5 = this;

        this.options.ListenEvents.forEach(function (evt) {
          return _[start ? 'on' : 'off'](el, evt, _this5.lazyLoadHandler);
        });
      }
    }, {
      key: '_initEvent',
      value: function _initEvent() {
        var _this6 = this;

        this.Event = {
          listeners: {
            loading: [],
            loaded: [],
            error: []
          }
        };

        this.$on = function (event, func) {
          if (!_this6.Event.listeners[event]) _this6.Event.listeners[event] = [];
          _this6.Event.listeners[event].push(func);
        };

        this.$once = function (event, func) {
          var vm = _this6;
          function on() {
            vm.$off(event, on);
            func.apply(vm, arguments);
          }
          _this6.$on(event, on);
        };

        this.$off = function (event, func) {
          if (!func) {
            if (!_this6.Event.listeners[event]) return;
            _this6.Event.listeners[event].length = 0;
            return;
          }
          remove(_this6.Event.listeners[event], func);
        };

        this.$emit = function (event, context, inCache) {
          if (!_this6.Event.listeners[event]) return;
          _this6.Event.listeners[event].forEach(function (func) {
            return func(context, inCache);
          });
        };
      }

      /**
       * find nodes which in viewport and trigger load
       * @return
       */

    }, {
      key: '_lazyLoadHandler',
      value: function _lazyLoadHandler() {
        var _this7 = this;

        var freeList = [];
        this.ListenerQueue.forEach(function (listener, index) {
          if (!listener.el || !listener.el.parentNode) {
            freeList.push(listener);
          }
          var catIn = listener.checkInView();
          if (!catIn) return;
          listener.load();
        });
        freeList.forEach(function (item) {
          remove(_this7.ListenerQueue, item);
          item.$destroy();
        });
      }
      /**
      * init IntersectionObserver
      * set mode to observer
      * @return
      */

    }, {
      key: '_initIntersectionObserver',
      value: function _initIntersectionObserver() {
        var _this8 = this;

        if (!hasIntersectionObserver) return;
        this._observer = new IntersectionObserver(this._observerHandler.bind(this), this.options.observerOptions);
        if (this.ListenerQueue.length) {
          this.ListenerQueue.forEach(function (listener) {
            _this8._observer.observe(listener.el);
          });
        }
      }

      /**
      * init IntersectionObserver
      * @return
      */

    }, {
      key: '_observerHandler',
      value: function _observerHandler(entries, observer) {
        var _this9 = this;

        entries.forEach(function (entry) {
          if (entry.isIntersecting) {
            _this9.ListenerQueue.forEach(function (listener) {
              if (listener.el === entry.target) {
                if (listener.state.loaded) return _this9._observer.unobserve(listener.el);
                listener.load();
              }
            });
          }
        });
      }

      /**
      * set element attribute with image'url and state
      * @param  {object} lazyload listener object
      * @param  {string} state will be rendered
      * @param  {bool} inCache  is rendered from cache
      * @return
      */

    }, {
      key: '_elRenderer',
      value: function _elRenderer(listener, state, cache) {
        if (!listener.el) return;
        var el = listener.el,
            bindType = listener.bindType;


        var src = void 0;
        switch (state) {
          case 'loading':
            src = listener.loading;
            break;
          case 'error':
            src = listener.error;
            break;
          default:
            src = listener.src;
            break;
        }

        if (bindType) {
          el.style[bindType] = 'url("' + src + '")';
        } else if (el.getAttribute('src') !== src) {
          el.setAttribute('src', src);
        }

        el.setAttribute('lazy', state);

        this.$emit(state, listener, cache);
        this.options.adapter[state] && this.options.adapter[state](listener, this.options);

        if (this.options.dispatchEvent) {
          var event = new CustomEvent(state, {
            detail: listener
          });
          el.dispatchEvent(event);
        }
      }

      /**
      * generate loading loaded error image url
      * @param {string} image's src
      * @return {object} image's loading, loaded, error url
      */

    }, {
      key: '_valueFormatter',
      value: function _valueFormatter(value) {
        var src = value;
        var loading = this.options.loading;
        var error = this.options.error;

        // value is object
        if (isObject(value)) {
          if (!value.src && !this.options.silent) console.error('Vue Lazyload warning: miss src with ' + value);
          src = value.src;
          loading = value.loading || this.options.loading;
          error = value.error || this.options.error;
        }
        return {
          src: src,
          loading: loading,
          error: error
        };
      }
    }]);
    return Lazy;
  }();
}

Lazy.install = function (Vue) {
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

  var LazyClass = Lazy(Vue);
  var lazy = new LazyClass(options);

  var isVue2 = Vue.version.split('.')[0] === '2';
  if (isVue2) {
    Vue.directive('lazy', {
      bind: lazy.add.bind(lazy),
      update: lazy.update.bind(lazy),
      componentUpdated: lazy.lazyLoadHandler.bind(lazy),
      unbind: lazy.remove.bind(lazy)
    });
  } else {
    Vue.directive('lazy', {
      bind: lazy.lazyLoadHandler.bind(lazy),
      update: function update(newValue, oldValue) {
        assignDeep(this.vm.$refs, this.vm.$els);
        lazy.add(this.el, {
          modifiers: this.modifiers || {},
          arg: this.arg,
          value: newValue,
          oldValue: oldValue
        }, {
          context: this.vm
        });
      },
      unbind: function unbind() {
        lazy.remove(this.el);
      }
    });
  }
};

var LazyComponent = function LazyComponent(lazy) {
  return {
    props: {
      tag: {
        type: String,
        default: 'div'
      }
    },
    render: function render(h) {
      return h(this.tag, null, this.show ? this.$slots.default : null);
    },
    data: function data() {
      return {
        el: null,
        state: {
          loaded: false
        },
        rect: {},
        show: false
      };
    },
    mounted: function mounted() {
      this.el = this.$el;
      lazy.addLazyBox(this);
      lazy.lazyLoadHandler();
    },
    beforeDestroy: function beforeDestroy() {
      lazy.removeComponent(this);
    },

    methods: {
      getRect: function getRect() {
        this.rect = this.$el.getBoundingClientRect();
      },
      checkInView: function checkInView() {
        this.getRect();
        return inBrowser && this.rect.top < window.innerHeight * lazy.options.preLoad && this.rect.bottom > 0 && this.rect.left < window.innerWidth * lazy.options.preLoad && this.rect.right > 0;
      },
      load: function load() {
        this.show = true;
        this.state.loaded = true;
        this.$emit('show', this);
      },
      destroy: function destroy() {
        return this.$destroy;
      }
    }
  };
};

LazyComponent.install = function (Vue) {
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

  var LazyClass = Lazy(Vue);
  var lazy = new LazyClass(options);
  Vue.component('lazy-component', LazyComponent(lazy));
};

var LazyContainerMananger = function () {
  function LazyContainerMananger(_ref) {
    var lazy = _ref.lazy;
    classCallCheck(this, LazyContainerMananger);

    this.lazy = lazy;
    lazy.lazyContainerMananger = this;
    this._queue = [];
  }

  createClass(LazyContainerMananger, [{
    key: 'bind',
    value: function bind(el, binding, vnode) {
      var container = new LazyContainer({ el: el, binding: binding, vnode: vnode, lazy: this.lazy });
      this._queue.push(container);
    }
  }, {
    key: 'update',
    value: function update(el, binding, vnode) {
      var container = find(this._queue, function (item) {
        return item.el === el;
      });
      if (!container) return;
      container.update({ el: el, binding: binding, vnode: vnode });
    }
  }, {
    key: 'unbind',
    value: function unbind(el, binding, vnode) {
      var container = find(this._queue, function (item) {
        return item.el === el;
      });
      if (!container) return;
      container.clear();
      remove(this._queue, container);
    }
  }]);
  return LazyContainerMananger;
}();


var defaultOptions = {
  selector: 'img'
};

var LazyContainer = function () {
  function LazyContainer(_ref2) {
    var el = _ref2.el,
        binding = _ref2.binding,
        vnode = _ref2.vnode,
        lazy = _ref2.lazy;
    classCallCheck(this, LazyContainer);

    this.el = null;
    this.vnode = vnode;
    this.binding = binding;
    this.options = {};
    this.lazy = lazy;

    this._queue = [];
    this.update({ el: el, binding: binding });
  }

  createClass(LazyContainer, [{
    key: 'update',
    value: function update(_ref3) {
      var _this = this;

      var el = _ref3.el,
          binding = _ref3.binding;

      this.el = el;
      this.options = assignDeep({}, defaultOptions, binding.value);

      var imgs = this.getImgs();
      imgs.forEach(function (el) {
        _this.lazy.add(el, assignDeep({}, _this.binding, {
          value: {
            src: 'dataset' in el ? el.dataset.src : el.getAttribute('data-src'),
            error: ('dataset' in el ? el.dataset.error : el.getAttribute('data-error')) || _this.options.error,
            loading: ('dataset' in el ? el.dataset.loading : el.getAttribute('data-loading')) || _this.options.loading
          }
        }), _this.vnode);
      });
    }
  }, {
    key: 'getImgs',
    value: function getImgs() {
      return ArrayFrom(this.el.querySelectorAll(this.options.selector));
    }
  }, {
    key: 'clear',
    value: function clear() {
      var _this2 = this;

      var imgs = this.getImgs();
      imgs.forEach(function (el) {
        return _this2.lazy.remove(el);
      });

      this.vnode = null;
      this.binding = null;
      this.lazy = null;
    }
  }]);
  return LazyContainer;
}();

LazyContainer.install = function (Vue) {
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

  var LazyClass = Lazy(Vue);
  var lazy = new LazyClass(options);
  var lazyContainer = new LazyContainer({ lazy: lazy });

  var isVue2 = Vue.version.split('.')[0] === '2';
  if (isVue2) {
    Vue.directive('lazy-container', {
      bind: lazyContainer.bind.bind(lazyContainer),
      componentUpdated: lazyContainer.update.bind(lazyContainer),
      unbind: lazyContainer.unbind.bind(lazyContainer)
    });
  } else {
    Vue.directive('lazy-container', {
      update: function update(newValue, oldValue) {
        lazyContainer.update(this.el, {
          modifiers: this.modifiers || {},
          arg: this.arg,
          value: newValue,
          oldValue: oldValue
        }, {
          context: this.vm
        });
      },
      unbind: function unbind() {
        lazyContainer.unbind(this.el);
      }
    });
  }
};

var LazyImage = function LazyImage(lazyManager) {
  return {
    props: {
      src: [String, Object],
      tag: {
        type: String,
        default: 'img'
      }
    },
    render: function render(h) {
      return h(this.tag, {
        attrs: {
          src: this.renderSrc
        }
      }, this.$slots.default);
    },
    data: function data() {
      return {
        el: null,
        options: {
          src: '',
          error: '',
          loading: '',
          attempt: lazyManager.options.attempt
        },
        state: {
          loaded: false,
          error: false,
          attempt: 0
        },
        rect: {},
        renderSrc: ''
      };
    },

    watch: {
      src: function src() {
        this.init();
        lazyManager.addLazyBox(this);
        lazyManager.lazyLoadHandler();
      }
    },
    created: function created() {
      this.init();
      this.renderSrc = this.options.loading;
    },
    mounted: function mounted() {
      this.el = this.$el;
      lazyManager.addLazyBox(this);
      lazyManager.lazyLoadHandler();
    },
    beforeDestroy: function beforeDestroy() {
      lazyManager.removeComponent(this);
    },

    methods: {
      init: function init() {
        var _lazyManager$_valueFo = lazyManager._valueFormatter(this.src),
            src = _lazyManager$_valueFo.src,
            loading = _lazyManager$_valueFo.loading,
            error = _lazyManager$_valueFo.error;

        this.state.loaded = false;
        this.options.src = src;
        this.options.error = error;
        this.options.loading = loading;
        this.renderSrc = this.options.loading;
      },
      getRect: function getRect() {
        this.rect = this.$el.getBoundingClientRect();
      },
      checkInView: function checkInView() {
        this.getRect();
        return inBrowser && this.rect.top < window.innerHeight * lazyManager.options.preLoad && this.rect.bottom > 0 && this.rect.left < window.innerWidth * lazyManager.options.preLoad && this.rect.right > 0;
      },
      load: function load() {
        var _this = this;

        var onFinish = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : noop;

        if (this.state.attempt > this.options.attempt - 1 && this.state.error) {
          if (!lazyManager.options.silent) console.log('VueLazyload log: ' + this.options.src + ' tried too more than ' + this.options.attempt + ' times');
          onFinish();
          return;
        }
        var src = this.options.src;
        loadImageAsync({ src: src }, function (_ref) {
          var src = _ref.src;

          _this.renderSrc = src;
          _this.state.loaded = true;
        }, function (e) {
          _this.state.attempt++;
          _this.renderSrc = _this.options.error;
          _this.state.error = true;
        });
      }
    }
  };
};

LazyImage.install = function (Vue) {
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

  var LazyClass = Lazy(Vue);
  var lazy = new LazyClass(options);
  Vue.component('lazy-image', LazyImage(lazy));
};

var index = {
  /*
  * install function
  * @param  {Vue} Vue
  * @param  {object} options  lazyload options
  */
  install: function install(Vue) {
    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    var LazyClass = Lazy(Vue);
    var lazy = new LazyClass(options);
    var lazyContainer = new LazyContainerMananger({ lazy: lazy });

    var isVue2 = Vue.version.split('.')[0] === '2';

    Vue.prototype.$Lazyload = lazy;

    if (options.lazyComponent) {
      Vue.component('lazy-component', LazyComponent(lazy));
    }

    if (options.lazyImage) {
      Vue.component('lazy-image', LazyImage(lazy));
    }

    if (isVue2) {
      Vue.directive('lazy', {
        bind: lazy.add.bind(lazy),
        update: lazy.update.bind(lazy),
        componentUpdated: lazy.lazyLoadHandler.bind(lazy),
        unbind: lazy.remove.bind(lazy)
      });
      Vue.directive('lazy-container', {
        bind: lazyContainer.bind.bind(lazyContainer),
        componentUpdated: lazyContainer.update.bind(lazyContainer),
        unbind: lazyContainer.unbind.bind(lazyContainer)
      });
    } else {
      Vue.directive('lazy', {
        bind: lazy.lazyLoadHandler.bind(lazy),
        update: function update(newValue, oldValue) {
          assignDeep(this.vm.$refs, this.vm.$els);
          lazy.add(this.el, {
            modifiers: this.modifiers || {},
            arg: this.arg,
            value: newValue,
            oldValue: oldValue
          }, {
            context: this.vm
          });
        },
        unbind: function unbind() {
          lazy.remove(this.el);
        }
      });

      Vue.directive('lazy-container', {
        update: function update(newValue, oldValue) {
          lazyContainer.update(this.el, {
            modifiers: this.modifiers || {},
            arg: this.arg,
            value: newValue,
            oldValue: oldValue
          }, {
            context: this.vm
          });
        },
        unbind: function unbind() {
          lazyContainer.unbind(this.el);
        }
      });
    }
  }
};

export { Lazy, LazyComponent, LazyContainerMananger as LazyContainer, LazyImage, index as default };