View.js 之跳转动画

/**
 * 定义动画
 */
@keyframes fadeIn{
    from{opacity: 0;}
    to{opacity: 1;}
}
@keyframes fadeOut{
    from{opacity: 1;}
    to{opacity: 0;}
}
@keyframes hideToLeft{
    from{transform: translate3d(0, 0, 0); opacity: 1;}
    to{transform: translate3d(-50%, 0, 0); opacity: 1;}
}
@keyframes showFromRight{
    from{transform: translate3d(100%, 0, 0); opacity: 1;}
    to{transform: translate3d(0, 0, 0); opacity: 1;}
}
@keyframes hideToRight{
    from{transform: translate3d(0, 0, 0); opacity: 1;}
    to{transform: translate3d(100%, 0, 0); opacity: 1;}
}
@keyframes showFromLeft{
    from{transform: translate3d(-50%, 0, 0); opacity: 1;}
    to{transform: translate3d(0, 0, 0); opacity: 1;}
}

/**
 * 视图容器水平居中
 */
*[data-view-container]{
    position: relative;
    visibility: hidden;
    margin: 0 auto;
    overflow: hidden;
    transition: height ease 0.5s;
}
*[data-view-container][data-view-state=ready]{
    visibility: visible;
}
/**
 * 所有视图重叠在一起,默认都不显示
 */
*[data-view=true] {
    display: block;
    opacity: 0;
    z-index: 0;
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    overflow: auto;
    -webkit-overflow-scrolling: touch;
    background: #F3F3F3;
    box-shadow: 0 0 70px rgba(0, 0, 0, 0.3);
}
/**
 * 视图隐藏时要呈现的半透明黑色蒙层。默认不显示
 */
*[data-view=true]:before{
    opacity: 0;
    content: "";
    display: none;
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.3);
}
/**
 * 活动视图可见
 */
*[data-view=true].active {
    opacity: 1;
    z-index: 1;
}

/**
 * 有条件地引用动画
 */
.view.fadeIn{
    animation: fadeIn 0.5s ease-out;
}
.view.fadeOut{
    animation: fadeOut 0.5s ease-out;
}

/* 视图含有hideToLeft样式类时播放hideToLeft动画 */
.view.hideToLeft{
    animation: hideToLeft 0.5s ease-out;
}
/* 视图向左隐藏时逐渐显示半透明黑色蒙层 */
.view.hideToLeft:before{
    display: block;
    animation: fadeIn 0.5s linear;
}

/* 视图含有showFromLeft样式类时播放showFromLeft动画 */
.view.showFromLeft{
    animation: showFromLeft 0.5s ease-out;
}
/* 视图取消隐藏时逐渐关闭半透明黑色蒙层 */
.view.showFromLeft:before{
    display: block;
    animation: fadeOut 0.5s linear;
}

/**
 * 视图含有hideToRight样式类时播放hideToRight动画。
 * z-index要比活动视图的1更高,从而使其不会被活动视图覆盖
 */
.view.hideToRight{
    z-index: 2;
    animation: hideToRight 0.5s ease-out;
}

/* 视图含有showFromRightn样式类时播放showFromRightn动画 */
.view.showFromRight{
    animation: showFromRight 0.5s ease-out;
}

 

;(function () {
    var timer;

    /**
     * 动画持续时长,需要与css中定义的动画时长一致
     * @type {number}
     */
    var animationDuration = 500;

    /**
     * 判断给定的对象是否包含指定名称的样式类
     */
    var hasClass = function (obj, clazz) {
        if (null == clazz || (clazz = String(clazz).trim()) === "")
            return false;

        if (obj.classList && obj.classList.contains)
            return obj.classList.contains(clazz);

        return new RegExp("\\b" + clazz + "\\b", "gim").test(obj.className);
    };

    /**
     * 为指定的对象添加样式类
     */
    var addClass = function (obj, clazz) {
        if (null == clazz || (clazz = String(clazz).trim()) === "" || hasClass(obj, clazz))
            return;

        if (obj.classList && obj.classList.add) {
            obj.classList.add(clazz);
            return;
        }

        obj.className = (obj.className.trim() + " " + clazz).trim();
    };

    /**
     * 为指定的对象删除样式类
     */
    var removeClass = function (obj, clazz) {
        if (null == clazz || (clazz = String(clazz).trim()) === "" || !hasClass(obj, clazz))
            return;

        if (obj.classList && obj.classList.remove) {
            obj.classList.remove(clazz);
            return;
        }

        clazz = String(clazz).toLowerCase();
        var arr = obj.className.split(/\s+/),
            str = "";
        for (var i = 0; i < arr.length; i++) {
            var tmp = arr[i];
            if (null == tmp || (tmp = tmp.trim()) === "")
                continue;

            if (tmp.toLowerCase() === clazz)
                continue;

            str += " " + tmp;
        }
        if (str.length > 0)
            str = str.substring(1);
        obj.className = str.trim();
    };


    /**
     * 清除给定DOM元素上声明的动画样式
     * @param {HTMLElement} obj
     */
    var clear = function (obj) {
        if (!obj)
            return;

        "hideToLeft, showFromRight, hideToRight, showFromLeft".split(/\s*,\s*/).forEach(function (className) {
            removeClass(obj, className);
        });
    };

    /**
     * @param {Object} meta 切换信息
     * @param {HTMLElement} meta.srcElement 视图切换时,要离开的当前视图对应的DOM元素。可能为null
     * @param {HTMLElement} meta.targetElement 视图切换时,要进入的目标视图对应的DOM元素
     * @param {String} type 视图切换方式
     * @param {String} trigger 视图切换触发器
     * @param {Function} render 渲染句柄
     */
    View.setSwitchAnimation(function (meta) {
        var srcElement = meta.srcElement,
            tarElement = meta.targetElement,
            type = meta.type,
            trigger = meta.trigger,
            render = meta.render;

        /**
         * 动画播放前清除可能存在的动画样式
         */
        clear(srcElement);
        clear(tarElement);

        /**
         * 调用View.js传递而来的渲染句柄,完成活动视图的切换,包括:
         * 1. 视图参数的传递
         * 2. 活动视图样式类的切换
         * 3. leave,ready、enter等事件的触发
         */
        render();

        var isNav = type === View.SWITCHTYPE_VIEWNAV,
            isChange = type === View.SWITCHTYPE_VIEWCHANGE,
            isHistoryBack = type === View.SWITCHTYPE_HISTORYBACK,
            isHistoryForward = type === View.SWITCHTYPE_HISTORYFORWARD;

        if (/\bsafari\b/i.test(navigator.userAgent) && (isHistoryBack || isHistoryForward) && trigger ===
            View.SWITCHTRIGGER_NAVIGATOR)
            return;

        /**
         * 视图切换动作是“替换堆栈”的方式,或浏览器不支持对history的操作
         */
        if (!View.checkIfBrowserHistorySupportsPushPopAction() || isChange) {
            addClass(srcElement, "fadeOut");
            addClass(tarElement, "fadeIn");
        } else if (isHistoryForward || isNav) {
            /**
             * 视图切换动作是“压入堆栈”的方式(浏览器前进,或代码触发)
             */

            addClass(srcElement, "hideToLeft");
            addClass(tarElement, "showFromRight");
        } else {
            /**
             * 视图切换动作是“弹出堆栈”的方式(浏览器后退)
             */

            addClass(srcElement, "hideToRight");
            addClass(tarElement, "showFromLeft");
        }

        /**
         * 动画播放完成后清除动画样式
         */
        clearTimeout(timer);
        timer = setTimeout(function () {
            clear(srcElement);
            clear(tarElement);
        }, animationDuration);
    });
})();

 

posted @ 2020-09-15 14:35  样子2018  阅读(290)  评论(1编辑  收藏  举报