ISlider’s whole idea is that, regardless of boundaries, only three images will actually appear in our view when we actually slide, so first copy the outer DOM of the sliding content, and then empty the content of the DOM:

doc.innerHTML=""
Copy the code

Then insert the _prev, _current, and _next dom nodes that currently contain sliding content into the outer DOM :this.wrap. Swipe to the next one, the previous _prev is removed, and the next DOM is added to this.wrap; Swipe to the previous one, the previous _next is deleted, and the previous DOM is added to this.wrap.

/* the iSlider constructor already writes this.opts * when the user passes opts * in the new constructor, the user passes opts * with for in and overrides the default opts **/
// instantiate the constructor
new iSlider({
    //some configurations...
})

// Inside the constructor
// For details on HTML5 storage, click...
function iSlider(opts){
    this.opts = {
        //some configurations...
    };
    /* this.SS is a reference to sessionStoratge. * If the user clicks the details button of the list * after entering the details page, the user actually wants to return to the slide list * but the current window (browser) is not closed * sessionStorage is still stored * so using session is the best choice **/
    this.SS = false;
    //ios uses private mode, an error will be reported
    try {
        this.SS = sessionStorage;
        this.'spt'] = 1;
    } catch(e){
        this.SS = 0;
    }
    / / initialization
    this.init();
}
Copy the code

ISlider constructor, which defines most of the methods, including init:

// The iSlider prototype object is overwritten
// I think the constructor should be referred back to iSlider
iSlider.prototype = {
    // Here are some attributes:
    _sesiionKey: location.host + location.pathname,
    _tpl: []._prev: null._current: null._next: null.//_sesiionKey, the _tpl parameter is assigned in init
    init: function(){
    /* _sesiionKey: location.host + location. pathName * use location as ID **/
      this._sesiionKey = btoa(encodeURIComponent(this._sessionKey+this.wrap.id+this.wrap.className));
      var lastLocateIndex = parseInt(this.SS[this._sessionKey]);
      //index is the index of the current picture
      /* this.index = ... * if the details page has a "back to list" button * click button, the page is refreshed * init is reexecuted, this.index is reassigned * this.SS[_sessionKey] will be in init and prev, **/ is assigned in the next function
      if(this.SS){
          this.index = (this.opts.lastLocate && lastLocateIndex>=0)? lastLocateIndex :0;
      }else {
          / /...
      }
      / / querySelector lookup "wrap"
      // This. wrap then finds the DOM node of the wrap
      // make a copy of the DOM to this._tpl to avoid direct manipulation of the DOM
      this._tpl = this.wrap.cloneNode(true);
      // Return the slider content in the wrap DOM to _tpl
      this._tpl = this.opts.item ? this._tpl.querySelectorAll(this.opts.item) : this._tpl.children;
      
      / /...
      if(this.opts.fullScr){
          // In full screen mode
          // Add CSS styles here
          //html,body{... }
      }
      / /...
      
      // Initialize the DOM
      this._setHTML();
      
      // Bind events in the event delegate mode
      this._bindEvt(); }},Copy the code

These values are assigned in this._sethtml ()

    _prev: null.// Last node
    _current: null.// The current node
    _next: null.// Next node
Copy the code

This. _setHTML primarily initializes the DOM node in the sliding area of the page, using createDocumentFragment, which is a DOM fragment, to optimize performance

iSlider.prototype = {
    / /...
    _setHTML: function(){
        // Empty the slide area of the page
        this.wrap.innerHTML = ""
        // Create a DOM fragment
        var initDOM = document.createDocumentFragment();
        
        // Assign the three attributes below
        if(this.index > 0) {// If index>0, the current node contains at least two nodes
            this._prev = this._tpl[this.index- 1].cloneNode(true);
            / / forward clientWidth / / clientHeight size
            this._prev.style.cssText += this._getTransform(The '-'+this.scrollDist+'px'); 
            initDom.appendChild(this._prev);
        }else{
            If (this._prev){if(this._prev){if(this._prev){}else{... } * * /
            this._prev = null
        }
        this._current =this._tpl[this.index].cloneNode(true);

        this._current.style.cssText+=this._getTransform(0);
        
        initDom.appendChild(this._current);
        
        // Similarly, assign the _next node
        if (this.index<this.length- 1) {
            this._next=this._tpl[this.index+1].cloneNode(true);
            this._next.style.cssText+=this._getTransform(this.scrollDist+'px');
            initDom.appendChild(this._next)
        }else {
            this._next=null;
        }

        this.wrap.appendChild(initDom); }}Copy the code

Then there is the this._bindevt function, which binds the event to the parent node. That is, the event is bound to the DOM when the current page is sliding full-screen, otherwise it is bound to the this.wrap outer DOM.

/* If target sets data-stop * and the value is "true", there is no need to block the default behavior **/
if (this.opts.fullScr || this.opts.preventMove) {
            handlrElm.addEventListener('touchmove'.function (e) {
                e.target.getAttribute('data-stop')! = ="true" && e.preventDefault(); 
            }, false);
        }
Copy the code

The _pageInit() function basically adds a “play” class to each sliding DOM, as well as animation callbacks.

After that, there are three sliding events, _touchstart, _touchmove, and _touchEnd.

Touchstart: there are a few variables to comb through, lockSlide: mark variables. If the lockSlide is true, then the current slide is not allowed, i.e. the _touchmove after the exit. If the lockSlide is true, then the _touchmove is not allowed.

_touchmove: function(){
    / *... * /
    if(e.touches.length ! = =1 || this.lockSlide){ 
       return; }}Copy the code
_touchstart: function(){
    this._touchstartX = e.touches[0].pageX;
    this._touchstartY = e.touched[0].pageY;
    // Initialize the touch position
    this.touchInitPos = this.opts.isVertical ? e.touches[0].pageY:e.touches[0].pageX;
    // To avoid frame jamming
    // We need to clear the animation
    // Check whether _next, _prev exist
    Duration is set to 0 if it exists
    //this._current.style.cssText = ...
    if(this._next){
        //
    }
    if(this._prev){
        //}}Copy the code

_touchmove events. This is an interesting do-while loop where parent is not null and parent is not the outer dom.wrap. One possible way to end a loop is: parent is this.wrap. When the user slides a finger in the sliding component area, the sliding range is still in the sliding component area (e.target is the touch point because of the event delegate). E.target is a child of the outer.wrap. So it can trigger the slide effect behind normally.

There is another case where the loop terminates when parent is null. Document (document.parentNode = null) is traversed, followed by if judgment, terminating touchMove event. The only way this can happen is if your fingers slip outside of this.wrap.

_touchmove: function(){
    var parent = e.target;
    do{
        parent = parent.parentNode;
    }while(parent && parent ! =this.wrap)
    
    if(! parent && e.target ! =this.wrap){
        return ;
    }
Copy the code

Gx and GY represent the X and Y sides of a triangle respectively. The base of a vertical triangle, based on geometry. If gx> Gy, the sliding direction of finger inclines to x axis, that is, the finger is judged to be horizontal sliding.

_touchmove: function(){    
    /********* split line *************/
    var gx=Math.abs(e.touches[0].pageX - this._touchstartX);
    var gy=Math.abs(e.touches[0].pageY - this._touchstartY);
    if (gx>gy && this.opts.isVertical) { 
        // The page slides vertically
        // The current finger is sliding horizontally
        this.lockSlide=true;
        return ;
    }else if(gx<gy && !this.opts.isVertical){ 
        // The page slides horizontally
        // The current finger is sliding vertically
        this.lockSlide=true;
        return; }}Copy the code

Next, the main thing is to calculate the offset, so if this.totalDist<0, then expose (not slide to) the next slide, and vice versa. This uses tranlante3D properties (with GPU acceleration enabled).

The _loading function is used in detail. Imgurl [0] {this.src===imgurl[0]}} It also frees up some memory.

for (var i=0; i<imgurls.length; i++) { imgs[i]=new Image(); imgs[i].src=imgurls[i]; imgs[i].onload=imgs[i].onerror=imgs[i].onabort=function (e) { loaded++; if (this.src === imgurls[0] && e.type === 'load') { clearTimeout(fallback) } checkloaded(); this.onload=this.onerror=this.onabort=null; }}Copy the code

[0] iSlider source code