2
\$\begingroup\$

This is a follow-up to the thread jQuery Tab Scroller. Adjusts have been made based on community suggestions, and here is the updated JSFiddle.

  • Calls for jQuery and Font Awesome have been included in the HTML head
  • Corrected naming conventions
  • Removed multiple occurrences of 'use strict'
  • Merged everything within a self-contained function
    • ; at beginning is due to my reading that this helps prevent conflicts with other programs
  • Renamed function tab_switch() to function toggle_class()
    • Changed .css() to .toggleClass()

Questions

  1. Some places had said just using 'use strict' at the top is enough and there's no need to use the function method. Is there a reason I would prefer one over the other in this case?
  2. Is it better to use pure JS for most cases and jQuery as a supplement rather than the framework? I'm curious about reducing load times, etc.
  3. Should most external sources be loaded async? I assume in this case, I want to ensure that jQuery has fully loaded before my script ever runs or else it'll throw some sort of jQuery is undefined error, but I can load my script async as long as I ensure all of my functions are scoped within a document.ready() function due to them interacting with the DOM?

/**
 * Name:        jQuery Tab Scroller
 * Description: A tab scroller using jQuery
 * @package     Chimera Apps
 * @version     1.1.0
 * @author      Chimera.Zen
 * @copyright   Copyright (c) 2017, Chimera.Zen
 * @link        https://github.com/ChimeraZen
 * @license     http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 */
;(function($){
  'use strict';
  var scroll_distance = 275,    // Distance .tab-container should scroll when <i> is clicked
      animate_speed   = 400;    // Speed at which .tab-container should animate the scroll

  /** Load the scroller details **/
  function get_scroll_details(scroller) {
    var tab_true_width  = Math.round(scroller.siblings('.tab-container').children('ul').width()),
        container_width = Math.round(scroller.siblings('.tab-container').width()),
        left_scrolled   = Math.round(scroller.siblings('.tab-container').scrollLeft()),
        scrolls = {
          "distance" : tab_true_width - container_width,
          "left_scrolled" : left_scrolled,
          "remaining" : tab_true_width - container_width - left_scrolled,
          "scroll_next" : scroller.parent().children('.scroller.next'),
          "scroll_prev" : scroller.parent().children('.scroller.prev')
        };
    return scrolls;
  }

  /** Tab Scroller **/
  function toggle_class(scroller) {
    var scrolls      = get_scroll_details(scroller),
        next_visible = scrolls.leftscrolled === 0 || scrolls.remaining !== 0,
        prev_visible = scrolls.remaining === 0 || scrolls.left_scrolled !== 0;
    scrolls.scroll_next.toggleClass('visible', next_visible).toggleClass('hidden', !next_visible);
    scrolls.scroll_prev.toggleClass('visible', prev_visible).toggleClass('hidden', !prev_visible);
  }

  /** Animate and check if <i> visibility needs to switch **/
  function scroll_it(scroller, scroll) {
    scroller.siblings('.tab-container').animate({scrollLeft: scroll}, animate_speed, function () {
      toggle_class(scroller);
    });
  }

  /** Animate & Scroll on Click **/
  $('.scroller.next').click(function () {
    var scroller  = $(this),
        scrolls   = get_scroll_details(scroller);
    if (scrolls.remaining >= scroll_distance) {
      scroll_it(scroller, scrolls.left_scrolled + scroll_distance);
    } else {
      scroll_it(scroller, scrolls.left_scrolled + scrolls.remaining);
    }
  });

  $('.scroller.prev').click(function () {
    var scroller  = $(this),
        scrolls   = get_scroll_details(scroller);
    if (scrolls.leftscrolled !== 0) {
      scroll_it(scroller, scrolls.left_scrolled - scroll_distance);
    } else {
      scroll_it(scroller, 0);
    }
  });
})(jquery);
.tab-scroller{
  display: flex;
  justify-content: space-around;
  align-items: center;
  width: 100%;
  max-height: 50px;
}
.tab-container{
  max-width: 50%;
  overflow: hidden;
}
.tab-scroller i {
  padding: 15px;
  font-size: 20px;
  cursor: pointer;
}
.tab-scroller .tab-container ul{
  display: flex;
  width: max-content;
  padding: 0;
}
.tab-scroller .tab-container li{
  display: flex;
  margin-right: 10px;
}
.tab-scroller .tab-container li:last-child{
  margin-right: 0;
}
.visible{
  visibility: visible;
}
.hidden{
  visibility: hidden;
}
<html>
  <head>
    <link type="text/css" src="tab-scroller.css" />
    <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css"></script>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script type="text/javascript" src="tab-scroller.js"></script>
  </head>
  <body>
    <div class="tab-scroller">
      <!-- <i class="scroller prev">&lt;</i> -->
      <i class="fa fa-chevron-left scroller prev"></i>
      <div class="tab-container">
        <ul>
          <li>Archery</li>
          <li>Baseball</li>
          <li>Basketball</li>
          <li>Boxing</li>
          <li>Football</li>
          <li>Golf</li>
          <li>Soccer</li>
          <li>Surfing</li>
        </ul>
      </div>
      <!-- <i class="scroller prev">&gt;</i> -->
      <i class="fa fa-chevron-right scroller next"></i>
    </div>
  </body>
</html>

\$\endgroup\$
2
\$\begingroup\$

Some places had said just using 'use strict' at the top is enough and there's no need to use the function method. Is there a reason I would prefer one over the other in this case?

Strict mode is the same thing whether you use it in a function or at the top of the file. The difference is scope. putting it at the top of the file means it will take effect for the entire file, putting it in a function means it will only take effect for that function. If you want to make sure your entire script is in strict mode put it at the top of your file simply because it's easier and saves a few bytes.

There are cases when you would want to put it in only certain functions though. If you have a bunch of undeclared variables, in strict mode, rather than defining the vars in the global scope it will throw an error, so you wouldn't want to put the entire script into strict mode. But what if later on you have to use exec() (god forbid) in a function and want to make sure it doesn't introduce any variables in the surrounding scope, putting "strict mode"; at the top of the function can be a helpful security measure.

Really, everything you need to know about strict mode is documented in MDN.

Is it better to use pure JS for most cases and jQuery as a supplement rather than the framework? I'm curious about reducing load times, etc.

Mankind has been asking this question for eons.

enter image description here

The answer depends on what your definition of "better" is. jQuery was intended to make developing easier, but it has trade offs: it requires you to add a large script to your page that will slow down load times, and it a lot of cases, yea, it is slower than vanilla JS.

The thing is, a few years ago there were a lot of discrepancies between browsers and people used jQuery to bridge that gap. Today, with ES6, there are a lot fewer discrepancies and that's why jQuery is slowly dying.

In most cases, I would say, If you can reasonably do it, try to avoid jQuery. However if your entire codebase uses jQuery and it's gonna be there anyway then there's no reason to go out of your way to avoid it.

Should most external sources be loaded async? I assume in this case, I want to ensure that jQuery has fully loaded before my script ever runs or else it'll throw some sort of jQuery is undefined error, but I can load my script async as long as I ensure all of my functions are scoped within a document.ready() function due to them interacting with the DOM?

I would say yes. Loading anything synchronously means longer load times for the user. Synchronous XHR has been deprecated for a while now because it provides a "bad user experience".

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.