• impress.js 中文注释


    impress.js 中文注释

                               玄魂

    /**

     * impress.js

     *(本翻译并未完全遵照原作者的注释翻译)

     * Impress.js 是受 Prezi启发,基于现代浏览器的 CSS3 JavaScript

     *语言完成的一个可供开发者使用的表现层框架.

     *

     *

     * Copyright 2011-2012 Bartek Szopka (@bartaz)

     *

     * Released under the MIT and GPL Licenses.

     *

     * ------------------------------------------------

     *  作者:  Bartek Szopka

     *  版本: 0.5.3

     *  url:     http://bartaz.github.com/impress.js/

     *  源码:  http://github.com/bartaz/impress.js/

     */

     

    /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, latedef:true, newcap:true,

             noarg:true, noempty:true, undef:true, strict:true, browser:true */

     

    // 想知道impress.js内部工作原理吗?

    // 现在从使impress.js开始运转的齿轮开始为您介绍...

    (function (document, window) {

        'use strict';

     

        // 辅助函数

     

        // `pfx` 是一个采用标准的CSS3属性为参数,返回其在当前浏览器是否被支持的信息。

        // 代码参考了Modernizr http://www.modernizr.com/

        var pfx = (function () {

     

            var style = document.createElement('dummy').style,

                prefixes = 'Webkit Moz O ms Khtml'.split(' '),

                memory = {};

     

            returnfunction (prop) {

                if (typeof memory[prop] === "undefined") {

     

                    var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1),

                        props = (prop + ' ' + prefixes.join(ucProp + ' ') + ucProp).split(' ');

     

                    memory[prop] = null;

                    for (var i in props) {

                        if (style[props[i]] !== undefined) {

                            memory[prop] = props[i];

                            break;

                        }

                    }

     

                }

     

                return memory[prop];

            };

     

        })();

     

        // `arraify` 接收一个类似数组的参数,然后将它放入真正的数组,

        // 以使所有的数组属性完整有效。

        var arrayify = function (a) {

            return [].slice.call(a);

        };

     

        // `css` 函数提供以下功能:

        // `props` 对象中的样式添加到元素‘el’中。

        // 通过 `pfx` 函数确保样式的每一个属性可用。

        // sure proper prefixed version of the property is used.

        var css = function (el, props) {

            var key, pkey;

            for (key in props) {

                if (props.hasOwnProperty(key)) {

                    pkey = pfx(key);

                    if (pkey !== null) {

                        el.style[pkey] = props[key];

                    }

                }

            }

            return el;

        };

     

        // `toNumber` 函数提供类型强制转换功能,将传入参数转换为数值类型。

        // 如果转换失败,返回0 (或者自定义的

        //  `fallback`回调函数).

        var toNumber = function (numeric, fallback) {

            return isNaN(numeric) ? (fallback || 0) : Number(numeric);

        };

     

        // `byId` 返回给定`id`的元素 - 你懂得 ;)

        var byId = function (id) {

            return document.getElementById(id);

        };

     

        // `$` 通过给定的 CSS选择器(`selector`返回在

        //上下文(`context`,指定元素或者整个文档)中

        //第一个匹配的元素

        var $ = function (selector, context) {

            context = context || document;

            return context.querySelector(selector);

        };

     

        // `$$`通过给定的 CSS选择器(`selector`返回在

        //上下文(`context`,指定元素或者整个文档)中

        //匹配的元素数组

        var $$ = function (selector, context) {

            context = context || document;

            return arrayify(context.querySelectorAll(selector));

        };

     

        // `triggerEvent` 为指定元素构建事件

        // 该函数有三个参数:

        // el:目标元素

        // eventName:事件名称

        //detail:传入数据

     

        var triggerEvent = function (el, eventName, detail) {

            var event = document.createEvent("CustomEvent");

            event.initCustomEvent(eventName, true, true, detail);

            el.dispatchEvent(event);

        };

     

        // `translate` 根据给定参数构建平移变换调用字符串.

        var translate = function (t) {

            return" translate3d(" + t.x + "px," + t.y + "px," + t.z + "px) ";

        };

     

        // `rotate` 根据给定参数构建旋转变换调用字符串..

        // 默认情况下,旋转按照xyz轴顺序进行,

        // 可以通过设置第二个参数‘revert’来改变旋转顺序

        var rotate = function (r, revert) {

            var rX = " rotateX(" + r.x + "deg) ",

                rY = " rotateY(" + r.y + "deg) ",

                rZ = " rotateZ(" + r.z + "deg) ";

     

            return revert ? rZ + rY + rX : rX + rY + rZ;

        };

     

        // `scale` 根据给定参数构建缩放变换调用字符串

        var scale = function (s) {

            return" scale(" + s + ") ";

        };

     

        // `perspective` 根据给定参数构建透视变换调用字符串.

        var perspective = function (p) {

            return" perspective(" + p + "px) ";

        };

     

        // `getElementFromHash`

        //  IDkey,从window location中取得数据

        var getElementFromHash = function () {

            // url中取得id,通过删除开头的 `#` 或者 `#/`

            // 所以 "fallback" `#slide-id` "enhanced" `#/slide-id` 都合乎规范

            return byId(window.location.hash.replace(/^#/?/, ""));

        };

     

        // `computeWindowScale` 通过定义在config文件中的 window size size

        //计算实际的缩放效果,

        var computeWindowScale = function (config) {

            var hScale = window.innerHeight / config.height,

                wScale = window.innerWidth / config.width,

                scale = hScale > wScale ? wScale : hScale;

     

            if (config.maxScale && scale > config.maxScale) {

                scale = config.maxScale;

            }

     

            if (config.minScale && scale < config.minScale) {

                scale = config.minScale;

            }

     

            return scale;

        };

     

        // 校验支持性

        var body = document.body;

     

        var ua = navigator.userAgent.toLowerCase();

        var impressSupported =

                              // 浏览器应该支持 CSS 3D 变换、classList dataset APIs

                               (pfx("perspective") !== null) &&

     

     

                               (body.classList) &&

                               (body.dataset) &&

     

                              // 但是一些移动设备得上黑名单了,

                              // 因为他们对CSS 3D的支持和硬件特性不足以运行impress.js

                              //  sorry...

                               (ua.search(/(iphone)|(ipod)|(android)/) === -1);

     

        if (!impressSupported) {

            // 无法确定 `classList` 是否被支持

            body.className += " impress-not-supported ";

        } else {

            body.classList.remove("impress-not-supported");

            body.classList.add("impress-supported");

        }

     

        // 全局变量和默认值

     

        // root元素,所有impress.js实例都必须保持并维护.

        // 是的!在一个页面里我们可以拥有多个实例,但是

        // 我不知道多个实例的意义在哪里;)

        var roots = {};

     

        // 默认配置.

        var defaults = {

            1024,

            height: 768,

            maxScale: 1,

            minScale: 0,

     

            perspective: 1000,

     

            transitionDuration: 1000

        };

     

        // 仅仅是一个空方法 ... 好吧,这个注释也很无聊^_^.

        var empty = function () { returnfalse; };

     

        // IMPRESS.JS API

     

        // 你感兴趣的地方,才刚刚开始.

        //  `impress` function 是整个impress组件的核心,它返回一个指定id的对象,默认为

        //该对象包含所有impress API 接口。

        //

        var impress = window.impress = function (rootId) {

     

            // 如果impress.js不被浏览器看支持,它返回一个假的对象

            // 这可能不是一个好的解决方案,但是这可以避免程序继续运行而出错

            if (!impressSupported) {

                return {

                    init: empty,

                    goto: empty,

                    prev: empty,

                    next: empty

                };

            }

     

            rootId = rootId || "impress";

     

            // 如果root已经初始化,返回该api

            if (roots["impress-root-" + rootId]) {

                return roots["impress-root-" + rootId];

            }

     

            // 所有演示步骤(step)的数据

            var stepsData = {};

     

            // 当前正在播放的step所在的html元素

            var activeStep = null;

     

            // 当前演示的状态数据 (position(位置),

            //rotation(旋转) scale(缩放))

            var currentState = null;

     

            // step 元素数组

            var steps = null;

     

            // 配置项

            var config = null;

     

            // 浏览器缩放效果配置参数

            var windowScale = null;

     

            // 根对象

            var root = byId(rootId);

            var canvas = document.createElement("div");

     

            var initialized = false;

     

            // step 事件

            //

            // impress.js中,有两个事件会被触发

            //  step在屏幕中被展现时将触发 `impress:stepenter`事件

            //  (上一个step展现结束)

            // `impress:stepleave` 当前step展现结束,下一个step即将开始时将触发

            //`impress:stepleave`事件

     

            // 上一个step的引用

            var lastEntered = null;

     

            // step刚被展现的时候,onStepEnter会被调用

            // 前提是当前step必须和上一step不同

            //

            var onStepEnter = function (step) {

                if (lastEntered !== step) {

                    triggerEvent(step, "impress:stepenter");

                    lastEntered = step;

                }

            };

     

            // step结束的时候,onStepLeave会被调用

            // 前提是当前step必须和上一step相同

            //

            var onStepLeave = function (step) {

                if (lastEntered === step) {

                    triggerEvent(step, "impress:stepleave");

                    lastEntered = null;

                }

            };

     

            // `initStep` 使用data属性中的数据初始化指定的step元素,

            //并设置正确的样式

            var initStep = function (el, idx) {

                var data = el.dataset,

                    step = {

                        translate: {

                            x: toNumber(data.x),

                            y: toNumber(data.y),

                            z: toNumber(data.z)

                        },

                        rotate: {

                            x: toNumber(data.rotateX),

                            y: toNumber(data.rotateY),

                            z: toNumber(data.rotateZ || data.rotate)

                        },

                        scale: toNumber(data.scale, 1),

                        el: el

                    };

     

                if (!el.id) {

                    el.id = "step-" + (idx + 1);

                }

     

                stepsData["impress-" + el.id] = step;

     

                css(el, {

                    position: "absolute",

                    transform: "translate(-50%,-50%)" +

                               translate(step.translate) +

                               rotate(step.rotate) +

                               scale(step.scale),

                    transformStyle: "preserve-3d"

                });

            };

     

            // `init` API:初始化并运行当前演示文档.

            var init = function () {

                if (initialized) { return; }

     

                // 首先,为移动设备设置视角.

                // 由于某些原因,ipad会卡死.

                var meta = $("meta[name='viewport']") || document.createElement("meta");

                meta.content = "width=device-width, minimum-scale=1, maximum-scale=1, user-scalable=no";

                if (meta.parentNode !== document.head) {

                    meta.name = 'viewport';

                    document.head.appendChild(meta);

                }

     

                // 初始化配置对象

                var rootData = root.dataset;

                config = {

                    toNumber(rootData.width, defaults.width),

                    height: toNumber(rootData.height, defaults.height),

                    maxScale: toNumber(rootData.maxScale, defaults.maxScale),

                    minScale: toNumber(rootData.minScale, defaults.minScale),

                    perspective: toNumber(rootData.perspective, defaults.perspective),

                    transitionDuration: toNumber(rootData.transitionDuration, defaults.transitionDuration)

                };

     

                windowScale = computeWindowScale(config);

     

                // step元素封装到canvas对象中

                arrayify(root.childNodes).forEach(function (el) {

                    canvas.appendChild(el);

                });

                root.appendChild(canvas);

     

                // 初始化默认样式

                document.documentElement.style.height = "100%";

     

                css(body, {

                    height: "100%",

                    overflow: "hidden"

                });

     

                var rootStyles = {

                    position: "absolute",

                    transformOrigin: "top left",

                    transition: "all 0s ease-in-out",

                    transformStyle: "preserve-3d"

                };

     

                css(root, rootStyles);

                css(root, {

                    top: "50%",

                    left: "50%",

                    transform: perspective(config.perspective / windowScale) + scale(windowScale)

                });

                css(canvas, rootStyles);

     

                body.classList.remove("impress-disabled");

                body.classList.add("impress-enabled");

     

                // 获取并设置step

                steps = $$(".step", root);

                steps.forEach(initStep);

     

                // canvas初始化默认属性值

                currentState = {

                    translate: { x: 0, y: 0, z: 0 },

                    rotate: { x: 0, y: 0, z: 0 },

                    scale: 1

                };

     

                initialized = true;

     

                triggerEvent(root, "impress:init", { api: roots["impress-root-" + rootId] });

            };

     

            // `getStep` 是一个辅助函数,根据参数返回指定的step.

            // 如果参数是数字,返回‘step-n’对象,

            // 如果参数是字符串,返回id和该字符串相同的step元素,

            // 如果参数为DOM元素,返回该step对象(只要对象存在).

            var getStep = function (step) {

                if (typeof step === "number") {

                    step = step < 0 ? steps[steps.length + step] : steps[step];

                } elseif (typeof step === "string") {

                    step = byId(step);

                }

                return (step && step.id && stepsData["impress-" + step.id]) ? step : null;

            };

     

            // `impress:stepenter` 事件设置timeout

            var stepEnterTimeout = null;

     

            // `goto` API 函数,根据传入的‘el’,跳转至指定的step (索引值,id或者元素),

            //  `duration` 可选,单位为秒.

            var goto = function (el, duration) {

     

                if (!initialized || !(el = getStep(el))) {

                    // presentation not initialized or given element is not a step

                    returnfalse;

                }

     

                // 有时候通过键盘操作来使第一个链接获得焦点是有必要的.

                // 浏览器此时可能会滚动页面显示这个元素

                // (甚至直接将bodyoverflow属性设置为hidden都不行) 这将影响我们的布局效果.

                //

                // 最简单的,在任何一个step显示的时候,我们都将页面滚动到顶端

                //

                // 如果你有更好的解决方案,请联系我,洗耳恭听!

                window.scrollTo(0, 0);

     

                var step = stepsData["impress-" + el.id];

     

                if (activeStep) {

                    activeStep.classList.remove("active");

                    body.classList.remove("impress-on-" + activeStep.id);

                }

                el.classList.add("active");

     

                body.classList.add("impress-on-" + el.id);

     

                // 基于给定的step,计算其在canvas上的显示状态

                var target = {

                    rotate: {

                        x: -step.rotate.x,

                        y: -step.rotate.y,

                        z: -step.rotate.z

                    },

                    translate: {

                        x: -step.translate.x,

                        y: -step.translate.y,

                        z: -step.translate.z

                    },

                    scale: 1 / step.scale

                };

     

                // 确定变换是否缩放(zooming in)(逐渐放大过程).

                //

                // 下面的信息用于修改变换时的样式:

                // 当元素逐渐放大的时候 - 首先进行平移和旋转

                // 之后才进行缩放, 当逐步缩小(zooming out)时,

                // 先进行向内缩放,然后做平移和旋转.

                var zoomin = target.scale >= currentState.scale;

     

                duration = toNumber(duration, config.transitionDuration);

                var delay = (duration / 2);

     

                // 如果相同的step被重复选中,强制计算窗口缩放值,

                // 因为这有可能是窗口大小改变引起的

                if (el === activeStep) {

                    windowScale = computeWindowScale(config);

                }

     

                var targetScale = target.scale * windowScale;

     

                //触发当前step的离开(leave)事件 (只有不是重复选择的step才触发该事件)

                if (activeStep && activeStep !== el) {

                    onStepLeave(activeStep);

                }

     

                // 现在我们修改 `root` `canvas` 的变换属性,触发变换.

                //

                // 存在rootcanvas这两个对象原因---

                // 它们独立进行动画:

                // `root`用于缩放 `canvas` 用于平移和旋转.

                // 二者开始变换的延时时间也不相同

                // (为了变换过程在视觉效果上看起来自然、美观),

                // 所以我们需要知道二者的行为是否都结束了.

                css(root, {

                    // 为了保证在不同的缩放时使透视效果看起来是一样的

                    // 我们同时需要缩放透视(perspective

                    transform: perspective(config.perspective / targetScale) + scale(targetScale),

                    transitionDuration: duration + "ms",

                    transitionDelay: (zoomin ? delay : 0) + "ms"

                });

     

                css(canvas, {

                    transform: rotate(target.rotate, true) + translate(target.translate),

                    transitionDuration: duration + "ms",

                    transitionDelay: (zoomin ? 0 : delay) + "ms"

                });

     

                // 最复杂的部分到了...

                //

                // 如果在缩放、平移、旋转属性上无任何变化, 就意味着没有延迟

                //  - 因为在 `root` 或者`canvas`元素上没有任何变换.

                // 我们需要在恰当的时刻触发 `impress:stepenter` 事件,

                // 所以我们比较当前和目标值从而确定是否需要计算延迟.

                //

                // 我只懂这个‘if’听起来很可怕, 但是当你知道即将要发生什么,这一切都变得很简单,

                // - 简单到只需要比较下面这些值.

                if (currentState.scale === target.scale ||

                    (currentState.rotate.x === target.rotate.x && currentState.rotate.y === target.rotate.y &&

                     currentState.rotate.z === target.rotate.z && currentState.translate.x === target.translate.x &&

                     currentState.translate.y === target.translate.y && currentState.translate.z === target.translate.z)) {

                    delay = 0;

                }

     

                // 存储当前状态

                currentState = target;

                activeStep = el;

     

                // 这是触发 `impress:stepenter` 事件的地方.

                //我们简单的使用定时器去解决变换延迟问题.

                //

                // 我确实想用更优雅的方式去解决这个问题

                //`transitionend` 事件看起来是最好的方式。

                //  但是我是在两个独立的元素上应用变换,同时

                //  `transitionend`事件在只要有一个值发生变化就会被触发 (change in the values)

                // 这引发了一些bug,并且使代码变得复杂, 因为我必须对所有场景都单独考虑.

                // 而且当根本没有变换发生的时候,仍然需要一个 `setTimeout`延迟回调函数, .

                // 所以我决定选择写更简单的代码而不是使用看起来更酷的 `transitionend`事件.

                //

                // 如果你想学习一些有意思的内容,

                //impress.js 0.5.2版本: http://github.com/bartaz/impress.js/blob/0.5.2/js/impress.js

                window.clearTimeout(stepEnterTimeout);

                stepEnterTimeout = window.setTimeout(function () {

                    onStepEnter(activeStep);

                }, duration + delay);

     

                return el;

            };

     

            // `prev` API function goes to previous step (in document order)

            var prev = function () {

                var prev = steps.indexOf(activeStep) - 1;

                prev = prev >= 0 ? steps[prev] : steps[steps.length - 1];

     

                return goto(prev);

            };

     

            // `next` API 函数,跳转到下一个step (在文档中的顺序)

            var next = function () {

                var next = steps.indexOf(activeStep) + 1;

                next = next < steps.length ? steps[next] : steps[0];

     

                return goto(next);

            };

     

            // step元素添加一些有用的类.

            //

            // 所有未被展示的step都被添加 `future` .

            // step被播放时, `future`类被移除 `present`类被添加

            //step结束时, `present` 类被‘past’类替换

            //

            // 所以每一个step都具有下面三种状态:

            // `future`, `present` and `past`.

            //

            // 这三种类可以通过css,配置step在不同状态下的呈现样式.

            // 例如 `present`可以被用于当某个step展现的时候

            // 触发一些自定义动画

            root.addEventListener("impress:init", function () {

                // STEP 的类

                steps.forEach(function (step) {

                    step.classList.add("future");

                });

     

                root.addEventListener("impress:stepenter", function (event) {

                    event.target.classList.remove("past");

                    event.target.classList.remove("future");

                    event.target.classList.add("present");

                }, false);

     

                root.addEventListener("impress:stepleave", function (event) {

                    event.target.classList.remove("present");

                    event.target.classList.add("past");

                }, false);

     

            }, false);

     

            // 添加hash变化支持.

            root.addEventListener("impress:init", function () {

     

                // 被探测到的上一个hash

                var lastHash = "";

     

                // 使用`#/step-id` 替代 `#step-id`

                //以阻止浏览器滚动到该id的元素

     

                // 必须在动画结束之后设置hash,

                // 因为在google浏览器会导致变换的动画延迟.

                // BUG: http://code.google.com/p/chromium/issues/detail?id=62820

                root.addEventListener("impress:stepenter", function (event) {

                    window.location.hash = lastHash = "#/" + event.target.id;

                }, false);

     

                window.addEventListener("hashchange", function () {

                    // step开始展现, location 中的hash已经被更新,

                    // (就是上面几行代码),

                    //所以hashchange事件被触发,这导致同一step元素会被再次调用 `goto`

                    //

                    // 为了避免这一情况,我们存储上次的hash值然后做比较

                    if (window.location.hash !== lastHash) {

                        goto(getElementFromHash());

                    }

                }, false);

     

                //

                // 通过url或者选择文档中的第一个step开始播放

                goto(getElementFromHash() || steps[0], 0);

            }, false);

     

            body.classList.add("impress-disabled");

     

            // 存储并返回root对象

            return (roots["impress-root-" + rootId] = {

                init: init,

                goto: goto,

                next: next,

                prev: prev

            });

     

        };

     

        // 浏览器是否支持impress.js的标记

        impress.supported = impressSupported;

     

    })(document, window);

     

    // 导航事件

     

    // 如你所见,这一部分代码和impress.js核心代码相分离.

    // 这是因为这一部分代码仅仅需要impress.js提供的接口

    //

    //

    // 在将来,我考虑将这部分代码放到独立的文件中

    // 以插件的形式的存在.

    (function (document, window) {

        'use strict';

     

        // throttling function calls, by Remy Sharp

        // http://remysharp.com/2010/07/21/throttling-function-calls/

        var throttle = function (fn, delay) {

            var timer = null;

            returnfunction () {

                var context = this, args = arguments;

                clearTimeout(timer);

                timer = setTimeout(function () {

                    fn.apply(context, args);

                }, delay);

            };

        };

     

        // 等待 impress.js 初始化完毕

        document.addEventListener("impress:init", function (event) {

            // eventdata中获取api接口.

            // 所以你不必在意impress.jsroot元素的id或者其他属性是什么。

            // `impress:init` event data给你所有想要的数据去控制播放

            // .

            var api = event.detail.api;

     

            // 键盘导航处理函数

     

            // 当被支持的按键按下时,阻止默认按键.

            document.addEventListener("keydown", function (event) {

                if (event.keyCode === 9 || (event.keyCode >= 32 && event.keyCode <= 34) || (event.keyCode >= 37 && event.keyCode <= 40)) {

                    event.preventDefault();

                }

            }, false);

     

            // 当按键弹起事,触发按键事件 (← 或者 →   )

     

            // 支持的按键:

            // [空格] - 跳到下一页

            // [↑] [→] / [↓] [←] - 上,右,下,左,

            // [下一页] / [下一页] - 通常被遥控器触发,

            // [tab] -很有争议,理由就不讨论了

            //   备忘录... 记得诡异的部分:

            //   每一个step播放时,页面窗口都从(0,0)开始

            // 

            //   ,  [tab] 在默认情况下导航至可定位焦点的元素,

            //  所以频繁的点击此键,会破坏演示效果

            //   我不想简单的禁用[tab], 所以我使用 [tab]

            //   作为跳到下一个step的另一种方法... 当然, 为了保持一致性

            //    我应该添加 [shift+tab] 作为回退操作...

            document.addEventListener("keyup", function (event) {

                if (event.keyCode === 9 || (event.keyCode >= 32 && event.keyCode <= 34) || (event.keyCode >= 37 && event.keyCode <= 40)) {

                    switch (event.keyCode) {

                        case 33: // pg up

                        case 37: // left

                        case 38: // up

                            api.prev();

                            break;

                        case 9:  // tab

                        case 32: // space

                        case 34: // pg down

                        case 39: // right

                        case 40: // down

                            api.next();

                            break;

                    }

     

                    event.preventDefault();

                }

            }, false);

     

            // 处理在当前演示step中产生的单击事件

            document.addEventListener("click", function (event) {

                // 处理事件冒泡( "bubbling"

                // 是否是超链接

                var target = event.target;

                while ((target.tagName !== "A") &&

                        (target !== document.documentElement)) {

                    target = target.parentNode;

                }

     

                if (target.tagName === "A") {

                    var href = target.getAttribute("href");

     

                    //如果指向某一step,直接到该step

                    if (href && href[0] === '#') {

                        target = document.getElementById(href.slice(1));

                    }

                }

     

                if (api.goto(target)) {

                    event.stopImmediatePropagation();

                    event.preventDefault();

                }

            }, false);

     

            // 处理在stepi上的点击

            document.addEventListener("click", function (event) {

                var target = event.target;

                //查找最近的没有被激活的step

                while (!(target.classList.contains("step") && !target.classList.contains("active")) &&

                        (target !== document.documentElement)) {

                    target = target.parentNode;

                }

     

                if (api.goto(target)) {

                    event.preventDefault();

                }

            }, false);

     

            // 处理触摸屏上的轻敲屏幕左右边缘的事件

            // 参考 @hakimel: https://github.com/hakimel/reveal.js

            document.addEventListener("touchstart", function (event) {

                if (event.touches.length === 1) {

                    var x = event.touches[0].clientX,

                        width = window.innerWidth * 0.3,

                        result = null;

     

                    if (x < width) {

                        result = api.prev();

                    } elseif (x > window.innerWidth - width) {

                        result = api.next();

                    }

     

                    if (result) {

                        event.preventDefault();

                    }

                }

            }, false);

     

            // 浏览器窗口改变时,重新展示当前step

            window.addEventListener("resize", throttle(function () {

                // 强制再次激活当前step

                api.goto(document.querySelector(".step.active"), 500);

            }, 250), false);

     

        }, false);

     

    })(document, window);

     

    // 到此为止!

    //

    // 谢谢你把它全部读完.

    //即使你是直接滚到到此处,仍然感谢.

    //

    // 在编写impress.js时,我学到了很多。希望这些代码和注释能对你有所帮助。

     

     

    欢迎访问玄魂的博客

    ps:对此文章或者安全、安全编程感兴趣的读者,可以加qq群:Hacking:303242737;Hacking-2群:147098303;Hacking-3群:31371755;hacking-4群:201891680;Hacking-5群:316885176

  • 相关阅读:
    [题解]北京2018
    [数据结构][字典树]Word Puzzles
    [数据结构][字典树]Hardwood Species
    [数学][广义欧拉定理]上帝与集合的正确用法
    Equal Sums
    Useful Decomposition
    网络流 EK算法
    线段树各类操作
    唯一分解定理
    Kuro and Walking Route
  • 原文地址:https://www.cnblogs.com/xuanhun/p/3641153.html
Copyright © 2020-2023  润新知