<template>

    <div :class="bem('', {loaded: loaded})">
        <img
            ref="img"
            :src="img"
            :alt="alt"
            @load="e => beginLoad ? onLoad() : null"
            @error="e => beginLoad ? onError(e) : null"
        >
        <div :class="bem('bg')" :style="{ background: color }"/>
    </div>

</template>

<script>
// 兼容浏览器
import { componentMixin, createComponentName } from '../_utils/component';
import { isSSR } from '../_utils/constant';

if (!isSSR()) {
    require('intersection-observer');
}

let intersectionObservers = {};


export default {
    name: createComponentName('lazy-image'),
    mixins: [componentMixin],
    props: {
        // 图片地址
        src: {
            type: String,
        },
        // 说明
        alt: {
            type: String,
        },
        color: {
            type: String,
        },
        // 超出多少比例开始加载图片
        ratio: {
            // 可选值 0 / 0.25 / 0.5 / 0.75 / 1
            type: Number,
            default: 0.5,
        },
        // 持续时长
        time: {
            type: Number,
            default: 0
        },
        // 计算交叉时添加到根(viewport)边界盒bounding box的矩形偏移量
        margin: {
            type: String,
            default: '0px 0px 0px 0px',
        }
    },
    data() {
        return {
            loaded: false,
            beginLoad: false,
        };
    },
    computed: {
        img() {
            return this.beginLoad ? this.src : '';
        },
        // FIXME: 图片多会导致卡顿
        colorImage() {
            const color = this.color || '#F0F3F4';
            return `data:image/svg+xml;utf8,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" height="1" width="1"><rect fill="${color}" width="1" height="1"/></svg>`)}`;
        }
    },
    mounted() {
        if (this.$isServer) return;

        if (!intersectionObservers[this.margin]) {
            const io = new IntersectionObserver(entries => {
                entries.forEach(e => {
                    if (e.intersectionRatio >= e.target.$$lazyImage.ratio) {
                        if (e.target.$$lazyImage.time > 0) {
                            e.target.$$lazyImage.timer = setTimeout(() => {
                                e.target.$$lazyImage.beginLoad = true;
                                io.unobserve(e.target);
                            }, e.target.$$lazyImage.time);
                        }
                        else {
                            e.target.$$lazyImage.beginLoad = true;
                            io.unobserve(e.target);
                        }
                    }
                    else {
                        if (e.target.$$lazyImage.timer) clearTimeout(e.target.$$lazyImage.timer);
                    }
                });
            }, {
                threshold: [0, 0.25, 0.5, 0.75, 1]
            });
            intersectionObservers[this.margin] = io;
        }
        this.$el.$$lazyImage = this;
        intersectionObservers[this.margin].observe(this.$el);
    },
    beforeDestroy() {
        if (!this.beginLoad && !this.$isServer) {
            intersectionObservers[this.margin].unobserve(this.$el);
        }
    },
    methods: {
        onLoad(e) {
            this.loaded = true;
            this.$emit('load', e);
        },
        onError(e) {
            this.$emit('error', e);
        }
    }
};
</script>

<style lang="less">
@import "../_styles/base.less";

.@{lazy-image} {
    display: flex;
    position: relative;

    &--loaded {
        .@{lazy-image}__bg {
            opacity: 0;
        }
    }

    img {
        &[src=""],
        &:not([src]):not(.@{lazy-image}--color){
            opacity:0;
        }
        width: 100%;
        object-fit: contain;
    }

    &__bg {
        transition: all ease 0.2s;
        position: absolute;
        pointer-events: none;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
    }

}
</style>
