$30 off During Our Annual Pro Sale. View Details »

I know jQuery. Now what?

I know jQuery. Now what?

I've always been a big believer in using jQuery as a shortcut route to adding interactivity to web sites. You don't need to know the intricacies of browsers bugs around the DOM. But now you've got that essential jQuery knowledge, what's next? How do you live without jQuery? Are we even there yet? And what about your colleagues and peers - how do they progress with you?

Remy Sharp

April 19, 2013
Tweet

More Decks by Remy Sharp

Other Decks in Technology

Transcript

  1. I know
    jQuery.
    Now what?
    Remy Sharp • @rem

    View Slide

  2. 7 years ago...

    View Slide

  3. 7 years ago...
    Actually,
    me 7 years ago...

    View Slide

  4. $ =

    View Slide

  5. View Slide

  6. View Slide

  7. Ajax Grokage
    Ajax + me
    WAT?

    View Slide

  8. function getXmlHttpRequest() {
    var xhr;
    if (window.XMLHttpRequest) {
    xhr = new XMLHttpRequest();
    } else {
    try {
    xhr = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
    try {
    xhr = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {
    xhr = false;
    }
    }
    }
    return xhr;
    }
    // disclaimer: John's jQuery version is a lot more elegant!

    View Slide

  9. Back to the Future

    View Slide

  10. querySelectorAll

    View Slide

  11. var $ = document.querySelectorAll.bind(document);
    Element.prototype.on = Element.prototype.addEventListener;
    $('#somelink')[0].on('touchstart', handleTouch);

    View Slide

  12. View Slide

  13. When I use jQuery

    View Slide

  14. No mustard
    cu ing:
    I include
    jQuery.

    View Slide

  15. if (querySelector in document &&
    localStorage in window &&
    addEventListener in window) {
    // bootstrap the JavaScript app
    }

    View Slide

  16. Quick 'n Dirty

    View Slide

  17. Sans jQuery

    View Slide

  18. document.ready

    View Slide

  19. .attr()

    View Slide

  20. $('input').on('change', function () {
    var value = $(this).attr('value');
    alert('The new value is' + value);
    });

    View Slide

  21. $('input').on('change', function () {
    var value = this.value;
    alert('The new value is' + value);
    });

    View Slide

  22. $('a').attr('href')
    a.getAttribute('href')
    a.href

    View Slide




  23. <br/>$('body').addClass('hasJS');<br/>

    View Slide



  24. <br/>document.body.className = 'hasJS';<br/>

    View Slide

  25. Classy

    View Slide

  26. body.className += ' hasJS'

    View Slide

  27. body.classList.add('hasJS')

    View Slide

  28. body.classList.remove('hasJS')

    View Slide

  29. body.classList.toggle('hasJS')

    View Slide

  30. body.classList.add('foo', 'bar')

    View Slide

  31. body.classList.contains('');
    // SyntaxError: DOM Exception 12
    :(

    View Slide

  32. data

    View Slide

  33. el.dataset.user = JSON.stringify(user);
    el.dataset.score = score;

    View Slide

  34. ax

    View Slide

  35. function request(type, url, opts, callback) {
    var xhr = new XMLHttpRequest();
    if (typeof opts === 'function') {
    callback = opts;
    opts = null;
    }
    xhr.open(type, url);
    // serialise post data
    if (type === 'POST' && opts) {
    //
    }
    xhr.onload = function () { callback(JSON.parse(xhr.response)); };
    xhr.send(opts ? fd : null);
    }
    var get = request.bind(this, 'GET');
    var post = request.bind(this, 'POST');

    View Slide

  36. function request(type, url, opts, callback) {
    var xhr = new XMLHttpRequest();
    if (typeof opts === 'function') {
    callback = opts;
    opts = null;
    }
    xhr.open(type, url);
    // serialise post data
    if (type === 'POST' && opts) {
    //
    }
    xhr.onload = function () { callback(JSON.parse(xhr.response)); };
    xhr.send(opts ? fd : null);
    }
    var get = request.bind(this, 'GET');
    var post = request.bind(this, 'POST');
    xhr.onload = function () { callback(JSON.parse(xhr.response)); };

    View Slide

  37. function request(type, url, opts, callback) {
    var xhr = new XMLHttpRequest();
    if (typeof opts === 'function') {
    callback = opts;
    opts = null;
    }
    xhr.open(type, url);
    // serialise post data
    if (type === 'POST' && opts) {
    //
    }
    xhr.onload = function () { callback(JSON.parse(xhr.response)); };
    xhr.send(opts ? fd : null);
    }
    var get = request.bind(this, 'GET');
    var post = request.bind(this, 'POST');

    View Slide

  38. •CORS
    •Progress events
    •Upload progress events
    •Different posting types
    •Using FormData

    View Slide

  39. fffffffffforms!

    View Slide


  40. View Slide


  41. View Slide


  42. View Slide

  43. Style & animation

    View Slide

  44. CSS > JS

    View Slide

  45. CSS > JS

    View Slide

  46. CSS > JS
    (for CSS, duh)

    View Slide

  47. Ss

    View Slide

  48. Bad: .css

    View Slide

  49. Good: .addClass

    View Slide

  50. Gooderer: .className

    View Slide

  51. If it's native to the
    browser, let the
    browser get on
    with it's job.

    View Slide

  52. Animation

    View Slide

  53. setInterval
    VS.
    requestAnimationFrame

    View Slide

  54. setInterval requestAnimationFrame

    View Slide

  55. View Slide

  56. rAF > setInterval

    View Slide

  57. CSS animations
    also uses
    rAF scheduling

    View Slide

  58. View Slide

  59. Translate =

    View Slide

  60. el.on("webkitTransitionEnd", ended);
    el.on("transitionend", ended);
    Note the the lowercase 'e' on 'end'...

    View Slide

  61. And yes, there
    are plugins.
    1. jQuery-Animate-Enhanced
    2. jQuery.Transit

    View Slide

  62. jQuery plugin.
    Just because.

    View Slide

  63. View Slide

  64. View Slide

  65. $.fn.fitText = function( kompressor, options ) {
    // Setup options
    var compressor = kompressor || 1,
    settings = $.extend({
    'minFontSize' : Number.NEGATIVE_INFINITY,
    'maxFontSize' : Number.POSITIVE_INFINITY
    }, options);
    return this.each(function(){
    // Store the object
    var $this = $(this);
    // Resizer() resizes items based on the object width divided by the compressor * 10
    var resizer = function () {
    $this.css('font-size', Math.max(Math.min($this.width() / (compressor*10),
    parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)));
    };
    // Call once to set.
    resizer();
    // Call on resize. Opera debounces their resize by default.
    $(window).on('resize orientationchange', resizer);
    });
    };

    View Slide

  66. $.fn.fitText = function( kompressor, options ) {
    // Setup options
    var compressor = kompressor || 1,
    settings = $.extend({
    'minFontSize' : Number.NEGATIVE_INFINITY,
    'maxFontSize' : Number.POSITIVE_INFINITY
    }, options);
    return this.each(function(){
    // Store the object
    var $this = $(this);
    // Resizer() resizes items based on the object width divided by the compressor * 10
    var resizer = function () {
    $this.css('font-size', Math.max(Math.min($this.width() / (compressor*10),
    parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)));
    };
    // Call once to set.
    resizer();
    // Call on resize. Opera debounces their resize by default.
    $(window).on('resize orientationchange', resizer);
    });
    };
    1. extend

    View Slide

  67. $.fn.fitText = function( kompressor, options ) {
    // Setup options
    var compressor = kompressor || 1,
    settings = $.extend({
    'minFontSize' : Number.NEGATIVE_INFINITY,
    'maxFontSize' : Number.POSITIVE_INFINITY
    }, options);
    return this.each(function(){
    // Store the object
    var $this = $(this);
    // Resizer() resizes items based on the object width divided by the compressor * 10
    var resizer = function () {
    $this.css('font-size', Math.max(Math.min($this.width() / (compressor*10),
    parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)));
    };
    // Call once to set.
    resizer();
    // Call on resize. Opera debounces their resize by default.
    $(window).on('resize orientationchange', resizer);
    });
    };
    1. extend
    2. each

    View Slide

  68. $.fn.fitText = function( kompressor, options ) {
    // Setup options
    var compressor = kompressor || 1,
    settings = $.extend({
    'minFontSize' : Number.NEGATIVE_INFINITY,
    'maxFontSize' : Number.POSITIVE_INFINITY
    }, options);
    return this.each(function(){
    // Store the object
    var $this = $(this);
    // Resizer() resizes items based on the object width divided by the compressor * 10
    var resizer = function () {
    $this.css('font-size', Math.max(Math.min($this.width() / (compressor*10),
    parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)));
    };
    // Call once to set.
    resizer();
    // Call on resize. Opera debounces their resize by default.
    $(window).on('resize orientationchange', resizer);
    });
    };
    1. extend
    2. each
    3. width

    View Slide

  69. $.fn.fitText = function( kompressor, options ) {
    // Setup options
    var compressor = kompressor || 1,
    settings = $.extend({
    'minFontSize' : Number.NEGATIVE_INFINITY,
    'maxFontSize' : Number.POSITIVE_INFINITY
    }, options);
    return this.each(function(){
    // Store the object
    var $this = $(this);
    // Resizer() resizes items based on the object width divided by the compressor * 10
    var resizer = function () {
    $this.css('font-size', Math.max(Math.min($this.width() / (compressor*10),
    parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)));
    };
    // Call once to set.
    resizer();
    // Call on resize. Opera debounces their resize by default.
    $(window).on('resize orientationchange', resizer);
    });
    };
    1. extend
    2. each
    3. width
    4. css

    View Slide

  70. $.fn.fitText = function( kompressor, options ) {
    // Setup options
    var compressor = kompressor || 1,
    settings = $.extend({
    'minFontSize' : Number.NEGATIVE_INFINITY,
    'maxFontSize' : Number.POSITIVE_INFINITY
    }, options);
    return this.each(function(){
    // Store the object
    var $this = $(this);
    // Resizer() resizes items based on the object width divided by the compressor * 10
    var resizer = function () {
    $this.css('font-size', Math.max(Math.min($this.width() / (compressor*10),
    parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)));
    };
    // Call once to set.
    resizer();
    // Call on resize. Opera debounces their resize by default.
    $(window).on('resize orientationchange', resizer);
    });
    };
    1. extend
    2. each
    3. width
    4. css
    5. on

    View Slide

  71. if (options === undefined) {
    options = {};
    }
    if (options.minFontSize === undefined) {
    options.minFontSize = Number.NEGATIVE_INFINITY;
    }
    if (options.maxFontSize === undefined) {
    options.maxFontSize = Number.POSITIVE_INFINITY;
    }
    .extend becomes init default options

    View Slide

  72. // assuming polyfill or IE9+
    nodes.forEach(function (node) {
    // where we used `this`, we now use `node`
    // ...
    })
    .each becomes regular loop

    View Slide

  73. var resizer = function () {
    var width = node.clientWidth;
    // ...
    };
    .width becomes .clientWidth property
    Note: clientWidth != .width() - but will do for our solution

    View Slide

  74. node.style.fontSize = Math.max(...);
    .css becomes se ing style property

    View Slide

  75. // assuming polyfill or IE9+
    window.addEventListener('resize', resizer, false);
    .on becomes .addEventLister
    Polyfill: h ps://gist.github.com/eirikbacker/2864711

    View Slide

  76. Idea:
    Why not use PE to
    support jQuery?

    View Slide

  77. Recap
    querySelectorAll for DOM
    navigation
    Think about when to use
    jQuery / a library
    Ditch document.ready
    Use this.value
    Try .classList
    Really grok ajax
    No more JavaScript
    animations
    Maybe no-jQuery first?

    View Slide

  78. Your turn.

    View Slide