Chủ Nhật, 24 tháng 4, 2016

12:30:00
1
Chào các bạn, hôm nay có bạn hỏi mình làm sao để blog có thể trượt mượt mà như blog của mình khi kéo xuống hay kéo lên như vậy. Vì vậy, mình quyết định viết một bài chia sẻ một đoạn js mà mình có sưu tầm được về thủ thuật này trên mạng internet.
Với hiệu ứng này, blog của bạn sẽ trở nên mượt mà hơn mỗi khi di chuyển lên xuống, blog của bạn sẽ trông chuyên nghiệp hơn rất nhiều đấy. Hiện nay các trình duyệt cũng đã có tiện ích để làm cho blog/website bạn mượt mà như vậy. Tuy nhiên, mình chắc là chẳng có mấy độc giả biết đến nó đâu. Bởi vậy, tại sao bạn không tự trang bị cho blog của mình chức năng này, thay vì đợi và người khác nhỉ.
Dưới đây là nội dung của đoạn js:
(function () {
// Scroll Variables (tweakable)var defaultOptions = {    // Scrolling Core    frameRate        : 150, // [Hz]    animationTime    : 400, // [ms]    stepSize         : 120, // [px]    // Pulse (less tweakable)    // ratio of "tail" to "acceleration"    pulseAlgorithm   : true,    pulseScale       : 4,    pulseNormalize   : 1,    // Acceleration    accelerationDelta : 20,  // 20    accelerationMax   : 1,   // 1    // Keyboard Settings    keyboardSupport   : true,  // option    arrowScroll       : 50,     // [px]    // Other    touchpadSupport   : true,    fixedBackground   : true,
    excluded          : '' 
};var options = defaultOptions;// Other Variablesvar isExcluded = false;var isFrame = false;var direction = { x: 0, y: 0 };var initDone  = false;var root = document.documentElement;var activeElement;var observer;var deltaBuffer = [];var isMac = /^Mac/.test(navigator.platform);var key = { left: 37, up: 38, right: 39, down: 40, spacebar: 32,
            pageup: 33, pagedown: 34, end: 35, home: 36 };/*********************************************** * SETTINGS ***********************************************/var options = defaultOptions;/*********************************************** * INITIALIZE ***********************************************//** * Tests if smooth scrolling is allowed. Shuts down everything if not. */function initTest() {    if (options.keyboardSupport) {        addEvent('keydown', keydown);    }}/** * Sets up scrolls array, determines if frames are involved. */function init() {
    if (initDone || !document.body) return;    initDone = true;    var body = document.body;    var html = document.documentElement;    var windowHeight = window.innerHeight;
    var scrollHeight = body.scrollHeight; 
    // check compat mode for root element    root = (document.compatMode.indexOf('CSS') >= 0) ? html : body;    activeElement = body; 
    initTest();    // Checks if this script is running in a frame    if (top != self) {        isFrame = true;    }    /**     * This fixes a bug where the areas left and right to
     * the content does not trigger the onmousewheel event     * on some pages. e.g.: html, body { height: 100% }     */    else if (scrollHeight > windowHeight &&            (body.offsetHeight <= windowHeight ||
             html.offsetHeight <= windowHeight)) {        var fullPageElem = document.createElement('div');        fullPageElem.style.cssText = 'position:absolute; z-index:-10000; ' +                                     'top:0; left:0; right:0; height:' +
                                      root.scrollHeight + 'px';        document.body.appendChild(fullPageElem);     
        // DOM changed (throttled) to fix height        var pendingRefresh;        var refresh = function () {            if (pendingRefresh) return; // could also be: clearTimeout(pendingRefresh);            pendingRefresh = setTimeout(function () {                if (isExcluded) return; // could be running after cleanup                fullPageElem.style.height = '0';                fullPageElem.style.height = root.scrollHeight + 'px';                pendingRefresh = null;            }, 500); // act rarely to stay fast        };
        setTimeout(refresh, 10);        // TODO: attributeFilter?        var config = {            attributes: true,
            childList: true,
            characterData: false
            // subtree: true        };        observer = new MutationObserver(refresh);        observer.observe(body, config);        if (root.offsetHeight <= windowHeight) {            var clearfix = document.createElement('div');
            clearfix.style.clear = 'both';            body.appendChild(clearfix);        }    }    // disable fixed background    if (!options.fixedBackground && !isExcluded) {        body.style.backgroundAttachment = 'scroll';        html.style.backgroundAttachment = 'scroll';    }}/** * Removes event listeners and other traces left on the page. */function cleanup() {    observer && observer.disconnect();    removeEvent(wheelEvent, wheel);    removeEvent('mousedown', mousedown);    removeEvent('keydown', keydown);}/************************************************ * SCROLLING
 ************************************************/
var que = [];var pending = false;var lastScroll = Date.now();/** * Pushes scroll actions to the scrolling queue. */function scrollArray(elem, left, top) { 
    directionCheck(left, top);    if (options.accelerationMax != 1) {        var now = Date.now();        var elapsed = now - lastScroll;        if (elapsed < options.accelerationDelta) {            var factor = (1 + (50 / elapsed)) / 2;            if (factor > 1) {                factor = Math.min(factor, options.accelerationMax);                left *= factor;                top  *= factor;            }        }        lastScroll = Date.now();    }   // push a scroll command    que.push({        x: left,
        y: top,
        lastX: (left < 0) ? 0.99 : -0.99,        lastY: (top  < 0) ? 0.99 : -0.99,
        start: Date.now()    });     
    // don't act if there's a pending queue    if (pending) {        return;    }    var scrollWindow = (elem === document.body); 
    var step = function (time) {     
        var now = Date.now();        var scrollX = 0;        var scrollY = 0;  
        for (var i = 0; i < que.length; i++) {         
            var item = que[i];            var elapsed  = now - item.start;            var finished = (elapsed >= options.animationTime);         
            // scroll position: [0, 1]            var position = (finished) ? 1 : elapsed / options.animationTime;         
            // easing [optional]            if (options.pulseAlgorithm) {                position = pulse(position);            }         
            // only need the difference            var x = (item.x * position - item.lastX) >> 0;            var y = (item.y * position - item.lastY) >> 0;         
            // add this to the total scrolling            scrollX += x;            scrollY += y;                     
            // update last values            item.lastX += x;            item.lastY += y;     
            // delete and step back if it's over            if (finished) {                que.splice(i, 1); i--;            }        
        }        // scroll left and top        if (scrollWindow) {            window.scrollBy(scrollX, scrollY);        }
        else {            if (scrollX) elem.scrollLeft += scrollX;            if (scrollY) elem.scrollTop  += scrollY;                 
        }     
        // clean up if there's nothing left to do        if (!left && !top) {            que = [];        }     
        if (que.length) {
            requestFrame(step, elem, (1000 / options.frameRate + 1));
        } else {
            pending = false;        }    }; 
    // start a new queue of actions    requestFrame(step, elem, 0);    pending = true;}/*********************************************** * EVENTS ***********************************************//** * Mouse wheel handler. * @param {Object} event */function wheel(event) {    if (!initDone) {        init();    } 
    var target = event.target;    var overflowing = overflowingAncestor(target);    // use default if there's no overflowing    // element or default action is prevented
    // or it's a zooming event with CTRL
    if (!overflowing || event.defaultPrevented || event.ctrlKey) {        return true;    } 
    // leave embedded content alone (flash & pdf)    if (isNodeName(activeElement, 'embed') ||
       (isNodeName(target, 'embed') && /\.pdf/i.test(target.src)) ||       isNodeName(activeElement, 'object')) {        return true;    }    var deltaX = -event.wheelDeltaX || event.deltaX || 0;    var deltaY = -event.wheelDeltaY || event.deltaY || 0; 
    if (isMac) {        if (event.wheelDeltaX && isDivisible(event.wheelDeltaX, 120)) {            deltaX = -120 * (event.wheelDeltaX / Math.abs(event.wheelDeltaX));        }        if (event.wheelDeltaY && isDivisible(event.wheelDeltaY, 120)) {            deltaY = -120 * (event.wheelDeltaY / Math.abs(event.wheelDeltaY));        }    } 
    // use wheelDelta if deltaX/Y is not available    if (!deltaX && !deltaY) {        deltaY = -event.wheelDelta || 0;    }    // line based scrolling (Firefox mostly)    if (event.deltaMode === 1) {        deltaX *= 40;        deltaY *= 40;    } 
    // check if it's a touchpad scroll that should be ignored    if (!options.touchpadSupport && isTouchpad(deltaY)) {        return true;    }    // scale by step size    // delta is 120 most of the time    // synaptics seems to send 1 sometimes    if (Math.abs(deltaX) > 1.2) {        deltaX *= options.stepSize / 120;    }    if (Math.abs(deltaY) > 1.2) {        deltaY *= options.stepSize / 120;    } 
    scrollArray(overflowing, deltaX, deltaY);    event.preventDefault();    scheduleClearCache();}/** * Keydown event handler. * @param {Object} event */function keydown(event) {    var target   = event.target;    var modifier = event.ctrlKey || event.altKey || event.metaKey ||
                  (event.shiftKey && event.keyCode !== key.spacebar); 
    // our own tracked active element could've been removed from the DOM    if (!document.contains(activeElement)) {        activeElement = document.activeElement;    }    // do nothing if user is editing text    // or using a modifier key (except shift)    // or in a dropdown    // or inside interactive elements    var inputNodeNames = /^(textarea|select|embed|object)$/i;    var buttonTypes = /^(button|submit|radio|checkbox|file|color|image)$/i;    if ( inputNodeNames.test(target.nodeName) ||         isNodeName(target, 'input') && !buttonTypes.test(target.type) ||         isNodeName(activeElement, 'video') ||         isInsideYoutubeVideo(event) ||         target.isContentEditable ||
         event.defaultPrevented   ||         modifier ) {      return true;    } 
    // spacebar should trigger button press    if ((isNodeName(target, 'button') ||         isNodeName(target, 'input') && buttonTypes.test(target.type)) &&        event.keyCode === key.spacebar) {      return true;    } 
    var shift, x = 0, y = 0;    var elem = overflowingAncestor(activeElement);    var clientHeight = elem.clientHeight;    if (elem == document.body) {        clientHeight = window.innerHeight;    }    switch (event.keyCode) {        case key.up:            y = -options.arrowScroll;            break;        case key.down:            y = options.arrowScroll;            break;      
        case key.spacebar: // (+ shift)            shift = event.shiftKey ? 1 : -1;            y = -shift * clientHeight * 0.9;            break;        case key.pageup:            y = -clientHeight * 0.9;            break;        case key.pagedown:            y = clientHeight * 0.9;            break;        case key.home:            y = -elem.scrollTop;            break;        case key.end:            var damt = elem.scrollHeight - elem.scrollTop - clientHeight;            y = (damt > 0) ? damt+10 : 0;            break;        case key.left:            x = -options.arrowScroll;            break;        case key.right:            x = options.arrowScroll;            break;         
        default:            return true; // a key we don't care about    }    scrollArray(elem, x, y);    event.preventDefault();    scheduleClearCache();}/** * Mousedown event only for updating activeElement */function mousedown(event) {    activeElement = event.target;}/*********************************************** * OVERFLOW ***********************************************/var uniqueID = (function () {    var i = 0;    return function (el) {        return el.uniqueID || (el.uniqueID = i++);    };})();var cache = {}; // cleared out after a scrolling sessionvar clearCacheTimer;//setInterval(function () { cache = {}; }, 10 * 1000);function scheduleClearCache() {    clearTimeout(clearCacheTimer);    clearCacheTimer = setInterval(function () { cache = {}; }, 1*1000);}function setCache(elems, overflowing) {    for (var i = elems.length; i--;)        cache[uniqueID(elems[i])] = overflowing;    return overflowing;}//  (body)                (root)//         | hidden | visible | scroll |  auto  |// hidden  |   no   |    no   |   YES  |   YES  |// visible |   no   |   YES   |   YES  |   YES  |// scroll  |   no   |   YES   |   YES  |   YES  |// auto    |   no   |   YES   |   YES  |   YES  |function overflowingAncestor(el) {    var elems = [];    var body = document.body;    var rootScrollHeight = root.scrollHeight;    do {        var cached = cache[uniqueID(el)];        if (cached) {            return setCache(elems, cached);        }        elems.push(el);        if (rootScrollHeight === el.scrollHeight) {            var topOverflowsNotHidden = overflowNotHidden(root) && overflowNotHidden(body);            var isOverflowCSS = topOverflowsNotHidden || overflowAutoOrScroll(root);            if (isFrame && isContentOverflowing(root) ||
               !isFrame && isOverflowCSS) {                return setCache(elems, getScrollRoot());
            }        } else if (isContentOverflowing(el) && overflowAutoOrScroll(el)) {            return setCache(elems, el);        }    } while (el = el.parentElement);}function isContentOverflowing(el) {    return (el.clientHeight + 10 < el.scrollHeight);}// typically for <body> and <html>function overflowNotHidden(el) {    var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');    return (overflow !== 'hidden');}// for all other elementsfunction overflowAutoOrScroll(el) {    var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');    return (overflow === 'scroll' || overflow === 'auto');}/*********************************************** * HELPERS ***********************************************/function addEvent(type, fn) {    window.addEventListener(type, fn, false);}function removeEvent(type, fn) {    window.removeEventListener(type, fn, false);
}function isNodeName(el, tag) {    return (el.nodeName||'').toLowerCase() === tag.toLowerCase();}function directionCheck(x, y) {    x = (x > 0) ? 1 : -1;    y = (y > 0) ? 1 : -1;    if (direction.x !== x || direction.y !== y) {        direction.x = x;        direction.y = y;        que = [];        lastScroll = 0;    }}var deltaBufferTimer;if (window.localStorage && localStorage.SS_deltaBuffer) {    deltaBuffer = localStorage.SS_deltaBuffer.split(',');}function isTouchpad(deltaY) {    if (!deltaY) return;    if (!deltaBuffer.length) {        deltaBuffer = [deltaY, deltaY, deltaY];    }    deltaY = Math.abs(deltaY)    deltaBuffer.push(deltaY);    deltaBuffer.shift();    clearTimeout(deltaBufferTimer);    deltaBufferTimer = setTimeout(function () {        if (window.localStorage) {            localStorage.SS_deltaBuffer = deltaBuffer.join(',');        }    }, 1000);    return !allDeltasDivisableBy(120) && !allDeltasDivisableBy(100);}
function isDivisible(n, divisor) {    return (Math.floor(n / divisor) == n / divisor);}function allDeltasDivisableBy(divisor) {    return (isDivisible(deltaBuffer[0], divisor) &&            isDivisible(deltaBuffer[1], divisor) &&            isDivisible(deltaBuffer[2], divisor));}function isInsideYoutubeVideo(event) {    var elem = event.target;    var isControl = false;    if (document.URL.indexOf ('www.youtube.com/watch') != -1) {        do {            isControl = (elem.classList &&
                         elem.classList.contains('html5-video-controls'));            if (isControl) break;        } while (elem = elem.parentNode);    }    return isControl;}var requestFrame = (function () {      return (window.requestAnimationFrame       ||
              window.webkitRequestAnimationFrame ||
              window.mozRequestAnimationFrame    ||              function (callback, element, delay) {                 window.setTimeout(callback, delay || (1000/60));             });})();var MutationObserver = (window.MutationObserver ||
                        window.WebKitMutationObserver ||                        window.MozMutationObserver);
var getScrollRoot = (function() {  var SCROLL_ROOT;  return function() {    if (!SCROLL_ROOT) {      var dummy = document.createElement('div');      dummy.style.cssText = 'height:10000px;width:1px;';      document.body.appendChild(dummy);      var bodyScrollTop  = document.body.scrollTop;      var docElScrollTop = document.documentElement.scrollTop;      window.scrollBy(0, 1);      if (document.body.scrollTop != bodyScrollTop)        (SCROLL_ROOT = document.body);      else
        (SCROLL_ROOT = document.documentElement);      window.scrollBy(0, -1);      document.body.removeChild(dummy);    }    return SCROLL_ROOT;  };})();/*********************************************** * PULSE (by Michael Herf) ***********************************************/
/** * Viscous fluid with a pulse for part and decay for the rest. * - Applies a fixed force over an interval (a damped acceleration), and * - Lets the exponential bleed away the velocity over a longer interval * - Michael Herf, http://stereopsis.com/stopping/ */function pulse_(x) {    var val, start, expx;    // test    x = x * options.pulseScale;    if (x < 1) { // acceleartion        val = x - (1 - Math.exp(-x));    } else {     // tail        // the previous animation ended here:        start = Math.exp(-1);        // simple viscous drag        x -= 1;        expx = 1 - Math.exp(-x);        val = start + (expx * (1 - start));    }    return val * options.pulseNormalize;}function pulse(x) {    if (x >= 1) return 1;    if (x <= 0) return 0;     if (options.pulseNormalize == 1) {        options.pulseNormalize /= pulse_(1);    }    return pulse_(x);}var wheelEvent;if ('onwheel' in document.createElement('div'))    wheelEvent = 'wheel';else if ('onmousewheel' in document.createElement('div'))    wheelEvent = 'mousewheel'; if (wheelEvent) {    addEvent(wheelEvent, wheel);    addEvent('mousedown', mousedown);    addEvent('load', init);}})();
Với mỗi mã nguồn, nền tảng có lẽ sẽ có những cách chèn khác nhau. Tuy nhiên, tất cả đều có chung một cách chèn đó là
 <script src='link flie js' type='text/javascript'/>. 
Vì vậy, nếu bạn không biết phải chèn như thế nào thì bạn hãy copy dòng sau đây và dán và trên thẻ </body> trong blog của bạn là được:
<script src="https://a44d96df9defe676467f55bacaa4f23d0646da4a.googledrive.com/host/0ByBzWAyW5EdvSHctbjJ5R1R6RDQ/smoothscroll.js" type="text/javascript"/>
Chúc các bạn vui với thủ thuật nhỏ này !

1 Bình luận:

Khi các bạn đóng góp ý kiến nhớ chú ý ngôn từ cho phù hợp với thuần phong ,mỹ tục văn hóa nước ta. Cảm ơn!