Skip to content
This repository has been archived by the owner on Nov 12, 2024. It is now read-only.

vframe依赖加载插件 #44

Open
xinglie opened this issue Nov 28, 2017 · 2 comments
Open

vframe依赖加载插件 #44

xinglie opened this issue Nov 28, 2017 · 2 comments

Comments

@xinglie
Copy link
Member

xinglie commented Nov 28, 2017

在我们做一个复杂的长列表页面时,我们通常要优先加载主功能,或者滚动到可视区域时才加载相应的view,这时候就可以使用该插件。

源码:

let Magix = require('magix');
let $ = require('$');
let { Vframe, Event: MEvent, mix } = Magix;
let WaitObserver = mix({}, MEvent);
let Base = Vframe.prototype;
let OldMountView = Base.mountView;
Vframe.on('add', e => {
    WaitObserver.fire(e.vframe.id + ':add', e, 1);
});
Vframe.on('remove', e => {
    WaitObserver.off(e.vframe.id + ':add');
});
let WaitVframe = (vfId, callback) => {
    let vf = Vframe.get(vfId);
    if (vf) {
        if (vf.$cr) {
            callback();
        } else {
            let ready = () => {
                vf.off('created', ready);
                callback();
            };
            vf.on('created', ready);
        }
    } else {
        WaitObserver.on(vfId + ':add', e => {
            let vf = e.vframe;
            let ready = () => {
                vf.off('created', ready);
                callback();
            };
            vf.on('created', ready);
        });
    }
};
let Win = $(window);
let ScrollList = [];
let Intersect = (rect1, rect2) => {
    let half1Width = rect1.width / 2,
        half1Height = rect1.height / 2,
        half2Width = rect2.width / 2,
        half2Height = rect2.height / 2,
        cen1 = {
            x: rect1.x + half1Width,
            y: rect1.y + half1Height
        },
        cen2 = {
            x: rect2.x + half2Width,
            y: rect2.y + half2Height
        };

    return Math.abs(cen2.x - cen1.x) <= half1Width + half2Width &&
        Math.abs(cen2.y - cen1.y) <= half1Height + half2Height;
};
let Scrolled = function () {
    let viewport = {
        x: Win.scrollLeft(),
        y: Win.scrollTop(),
        width: Win.width(),
        height: Win.height()
    };
    for (let i = 0; i < ScrollList.length; i++) {
        let one = ScrollList[i];
        let node = $('#' + one.id);
        if (node.length) {
            let offset = node.offset();
            let rect = {
                x: offset.left,
                y: offset.top,
                width: node.width(),
                height: node.height()
            };
            if (Intersect(viewport, rect)) {
                ScrollList.splice(i--, 1);
                one.cb();
            }
        } else {
            ScrollList.splice(i--, 1);
        }
    }
    if (!ScrollList.length) {
        Win.off('scroll', Scrolled);
    }
};
let ScrollWatch = (vfId, callback) => {
    if (!ScrollList.length) {
        Win.on('scroll', Scrolled);
    }
    ScrollList.push({
        id: vfId,
        cb: callback
    });
    Scrolled();
};
Base.mountView = function (viewPath, viewInitParams) {
    let me = this;
    let sign = ++me.$s;
    let node = $('#' + me.id);
    let dep = node.attr('mx-dep');
    if (dep) { //有依赖
        if (dep | 0) { //延时
            setTimeout(() => { //由sign保证正确,所以无须取消setTimeout的执行
                if (sign == me.$s) {
                    OldMountView.call(me, viewPath, viewInitParams);
                }
            }, dep);
        } else { //其它依赖
            if (dep == '@viewport') { //以@开头的表示内置的命令:当vframe节点处在可视区域时加载
                ScrollWatch(me.id, () => {
                    if (sign == me.$s) {
                        OldMountView.call(me, viewPath, viewInitParams);
                    }
                });
            } else { //其它vframe依赖
                //if (IsVframeCreated(dep)) { //如果依赖的已经加载完成
                // oldMountView.call(me, viewPath, viewInitParams, callback);
                //} else {
                WaitVframe(dep, () => { //等待相应的vframe加载
                    if (me.$s == sign) {
                        OldMountView.call(me, viewPath, viewInitParams);
                    }
                });
                //}
            }
        }
    } else {
        OldMountView.call(me, viewPath, viewInitParams);
    }
};

插件使用方式

  1. 把该文件保存成vfdep.js,放在app目录下
  2. 在Magix.boot时,在exts中启用该插件,如
Magix.boot({
    exts: ['vfdep']
});

插件支持的功能

延时加载

通过mx-dep指定一个延时的时间,毫秒为单位

<div mx-view="path/to/view" mx-dep="2000">loading</div>
滚动到可视区域加载

通过mx-dep值为@Viewport来指示view滚动到可视区域时才加载

<div mx-view="path/to/view" mx-dep="@viewport">loading</div>
在其它view加载完成后才加载

通过mx-dep值为其它view的id时,其它view加载渲染完成时才加载该view

<div mx-view="path/to/view-a" mx-dep="@viewport" id="viewa">loading</div>
<div mx-view="path/to/view-b" mx-dep="viewa">loading</div>
@youwenda
Copy link

👍 很常见的应用场景。目前更多的应用场景@Viewport这种模式。滚动到dom节点才去动态mountview,既mx-view 变更为 mx-lazy-view 。滚动到此后开始mount.
需要给一淘的同学推荐一下。

@xinglie
Copy link
Member Author

xinglie commented Dec 16, 2017

用mx-lazy-view也可以,我这个思路是拦截并改变原来的加载流程。把这个过程放在外部,实现类似img-lazyload的效果也是可行的。

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants