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