Hi ~ here is Sesame, today we together to make a “slider plug-in”. So what is a slider plugin? What does a slider do? See the picture below:


Yes, the most basic use of the plugin is to swipe left and right. Users only need to write a few lines of SIMPLE HTML and JS to achieve a simple slide effect, but you can combine various elements to suit different scenarios.

Of course, I have already written the plug-in, let’s take a look at how the plug-in is used, have a general understanding of the plug-in, later write up will not be too confused…

Plugin address: github.com/laravuel/sw… SRC /swiper.js can be used directly, but I use webpack and Babel transcoding.

<! -- demo.html -->

<! -- Swiper name can be customized -->
<div id="swiper">
    <! -- Swiper-item name can also be customized, equivalent to a slider -->
    <div class="swiper-item">
        <img src="./images/1.jpg" />
    </div>
    <div class="swiper-item">
        <img src="./images/2.jpg" />
    </div>
    <div class="swiper-item">
        <img src="./images/3.jpg" />
    </div>
</div>

<script src=".. /dist/swiper.js"></script>
<script>
    new Swiper({
        swiper: '#swiper'.// Swiper Node name
        item: '.swiper-item'.// Swiper Internal slider node name
        autoplay: false.// Whether to slide automatically
        duration: 3000.// Automatic slide interval time
        change(index) {			// Every time a slider is slid, the plugin triggers the change function, with index representing the current slider subscript
            console.log(index); }});</script>
Copy the code

It’s as simple as that. The plugin itself is just a class. You just need to new an object and pass some parameters. Furthermore, the plugin provides a change method that allows the user to control the slider from the outside!

const swiper = newSwiper({... }); swiper.change(2); // Slide to the third slider
Copy the code

Now it’s time for the tutorial, I’m not sure if you’ll be able to sit through it, but I’m sure you’ll be happy if you write it yourself!!

Since this tutorial is quite extensive, I have divided it into two parts. The first part focuses on principles, and the second part starts writing plug-ins. Therefore, interested partners can add a following first.

1. Functional analysis

We need to be clear about what features we want to implement. For those who are too lazy to think, you can use the GIF above to analyze it:

  1. Slider can slide left and right (support mobile and PC)
  2. Any element can be written inside the slider
  3. There is a limit when sliding to the first and last slider to prevent transgressions
  4. Auto-play

That’s about all we can see, and we’ll break them down and analyze them.

2. Implementation principle

The above simple comb some functions, in fact, can be extended to the following questions:

  1. What is the HTML structure of the slider?
  2. What is the sliding principle of the slider?
  3. How do I trigger a slide?

Take it easy. One at a time

2.1.1 What is the HTML structure of the slider?

Let’s start with a picture:

  • View our content display area, which acts as the outermost display layer
  • The width of the container is infinitely long to accommodate all the content we need to switch. The left/right sliding of the slider is essentially the left/right movement of the container, and each slider is actually static relative to the container
  • Slider by slider

So, according to this structure, you can use the following HTML code:

<! -- View Layer -->
<div class="swiper">
    <! -- -- -- > container
    <div class="swiper-container">
        <! - the slider - >
        <div class="swiper-item" style="background: #000">1</div>
        <div class="swiper-item" style="background: #4269eb">2</div>
        <div class="swiper-item" style="background: #247902">3</div>
    </div>
</div>
Copy the code

Then add CSS styles:

.swiper {
    position: relative;
    width: 300px;
	
    / * here is to let you see more clearly, decorated with * /
    padding: 30px 0;
    margin: 0 auto;
    background: #FFB973;
}
.swiper .swiper-container {
    position: relative;
    /* Why set -300px, because I want it to default to the second slider, I'll show you later */
    left: -300px;
    /* Make the container as wide as possible to hold more sliders */
    width: 10000%;
    /* Let the inner slider line up */
    display: flex;

    / * here is to let you see more clearly, decorated with * /
    background: red;
    padding: 15px 0;
}
.swiper .swiper-container .swiper-item {
    /* The width set to 1% will be filled with the width of the outer view */
    width: 1%;
    height: 300px;
    background: #eee;

    / * here is to let you see more clearly, decorated with * /
    text-align: center;
    font-size: 40px;
    color: #fff;
}
Copy the code


You should see something like this:


Of course, you can remove all the embellishments AND CSS styles I’ve added and try again.

2.1.2 What is the sliding principle of slider?

If you can understand the HTML structure above, we can slide through it. (If that doesn’t make sense, read on and you may suddenly see the light!)

Above we mentioned the concept of a “slider container”, which is responsible for the left and right movement of the slider

.swiper .swiper-container {
    position: relative;
    left: -300px;
}
Copy the code

Because the width of the slider is the same as the width of the view, so the width of the slider here is 300px, so if we set the left of the container to -300px, that means we’ve moved one slider to the left, and -600px means we’ve moved two slider widths to the left, you get the idea, if you want to move a slider, All you need to do is know the order of the slider (starting at 0) and multiply it by the inverse of the width of the slider. For example, if you want to move to the third slider, which is in order 2, you get 2 * -300 = -600

See the GIF below for a demo:


Some of you might like to use jquery and get used to all of the animate methods. I don’t like them very much, because I think CSS animation can handle most of the needs. And when you use vue, the MVVM framework, You will find that jquery animation is not practical!

Instead of using the CSS animation property, we can use transition, which is a transition property. For details, please refer to developer.mozilla.org/zh-CN/docs/…

Let’s try adding the transition property to the container:

.swiper .swiper-container {
    / * omit... * /
    
    transition: left 0.2 s ease-in-out;
}
Copy the code



The transition: left 0.2 s ease - in-out;
If the element’s left value changes, there will be a 0.2s transition animation (tween animation)

Each swiper-item swiper-item moves left or right, but its parent swiper-container moves left or right. Then we use the Transition property to animate the transition!

2.1.3 How do I trigger sliding?

Above we have a bunch of HTML and CSS, let’s move on to JS. “How do I trigger a slide?” , we do not consider the mobile terminal, according to the PC web page, then trigger operation is to hold down the mouse on the container to drag left/right, and then release the mouse, the slider will slide left/right.

The whole process is tied to mouse events:

  1. mousedownMouse down event
  2. mousemoveMouse movement event
  3. mouseupMouse up event

Make good use of these 3 events, we can achieve mouse control slider movement! Let’s start by holding down the mouse and dragging the slider to the left and right. Since swiper-container is responsible for left and right movement, let’s listen for its mouse events, first using querySelector to get the view and container element nodes:

// Get the view-layer element first
const swiperEl = document.querySelector('.swiper');
// Look for container elements in the view layer
const containerEl = swiperEl.querySelector('.swiper-container');
Copy the code

Once we get the container element, we can use its addEventListener to listen for events:

containerEl.addEventListener('mousedown', (event) => {
    console.log('Mouse down');
});
containerEl.addEventListener('mousemove', (event) => {
    console.log('Mouse moved');
});
containerEl.addEventListener('mouseup', (event) => {
    console.log('Mouse up');
});
Copy the code


Take a look at the GIF operation:

Although we can successfully listen to the mouse operation events, but there seems to be a problem, we expect the result is that the mouse movement will only be triggered when the mouse is pressed, but now it does not appear, so we can consider adding a state control.

let state = 0;  // Default mouse status

containerEl.addEventListener('mousedown', (event) => {
    state = 1;  // Set to 1 to press the mouse
    console.log('Mouse down');
});
containerEl.addEventListener('mousemove', (event) => {
    if(state ! =1) return; // This event can be executed only when state == 1
    console.log('Mouse moved');
});
containerEl.addEventListener('mouseup', (event) => {
    state = 0;  // Restore the default state
    console.log('Mouse up');
});
Copy the code

Now that we have the mouse event, we need to make the container move left and right with the mouse.

We want to know, the browser for any operation, the mouse will have a coordinate parameters (pageX and pageY), so, we can according to the coordinates of the mouse movement time parameters to calculate the container left value, you can imagine, when you press the mouse and move around, every time the mouse motion relative to the last will cause the distance, Can we add or subtract this distance from the left value of the container to create a drag effect? Remember the event parameter in our callback function, which is the property of the current mouse operation, and we only need the pageX property



transition

.swiper .swiper-container {
    / * omit... * /
    
    /* Transition: left 0.2s ease-in; * /
}
Copy the code

Each step of the operation is detailed in the comments:

// Get the view-layer element first
const swiperEl = document.querySelector('.swiper');
// Look for container elements in the view layer
const containerEl = swiperEl.querySelector('.swiper-container');

let state = 0;  		// Default mouse status
let oldEvent = null;    // To record the last mouse position
// Get the initial left value of the container
let left = containerEl.offsetLeft;

containerEl.addEventListener('mousedown', (event) => {
    state = 1;  // Set to 1 to press the mouse
    oldEvent = event;   // Record the initial position when the mouse is pressed
    console.log('Mouse down');
});

containerEl.addEventListener('mousemove', (event) => {
    if(state ! =1) return; // This event can be executed only when state == 1

    // Compare the current mouse position with the previous mouse position
    // If the pageX of the current mouse is smaller than the pageX of the last mouse, it means that the mouse is dragging to the left
    if (event.pageX < oldEvent.pageX) {
        left -= oldEvent.pageX - event.pageX;
    }
    else {
        left += event.pageX - oldEvent.pageX;
    }
    // Remember to assign the current mouse position to oldEvent
    oldEvent = event;
    // Assign left to the container
    containerEl.style.left = left + 'px';
    console.log('Mouse moved');
});

containerEl.addEventListener('mouseup', (event) => {
    state = 0;  // Restore the default state
    console.log('Mouse up');
});
Copy the code

Run to see the effect:


But, but, after you release the mouse, you did not slide to the corresponding position, ah, ah, we did not talk about it in front, slider order, slider width still remember? 0 – slider order * slider width is going to move to this slider, remember?

We use index to record the current slider order

let index = 0;          // Record the current slider order (starting from 0)
Copy the code

Use itemWidth to store the width of the slider

// Get all slider elements
const itemEls = containerEl.querySelectorAll('.swiper-item');
// Get the width of the slider
const itemWidth = itemEls[0].offsetWidth;
Copy the code

Let’s change our left variable, which gets the left value of the container element directly, to index

// let left = containerEl.offsetLeft;
// The left value of the container is calculated according to index
let left = 0 - itemWidth * index;
// Set the initial position of the container
containerEl.style.left = left + 'px';
Copy the code

All we need to do is change the value of the index variable, and the initial position of the container will change.

Then, when the mouse is pressed down, we record the coordinate position, and when the mouse is raised, compare the current mouse position with the pressed position to judge whether the user is left or right!

let startEvent = null;  // Use to record the position when the mouse is pressed (initial position)

containerEl.addEventListener('mousedown', (event) => {
    state = 1;  // Set to 1 to press the mouse
    startEvent = oldEvent = event;   // Record the initial position when the mouse is pressed
    console.log('Mouse down');
});
Copy the code

So when the mouse is up, just compare it to startEvent. PageX to determine whether to swipe left or right. If we swipe left, we make index + 1, and if we swipe right, we make index – 1

containerEl.addEventListener('mouseup', (event) => {
    state = 0;  // Restore the default state
    
    // When the mouse is up, compare it with the down coordinate to determine whether to slide left or right
    // Swipe left to display the next slider, so index is increased by 1
    if (event.pageX < startEvent.pageX) {
        index ++;
    }
    else {
        index --;
    }

    left = 0 - itemWidth * index;
    containerEl.style.left = left + 'px';
    console.log('Mouse up');
});
Copy the code



transition
transition
swiper-container
.move
swiper-container
move

.swiper .swiper-container.move {
    transition: left 0.2 s ease-in-out;
} 
Copy the code
containerEl.addEventListener('mouseup', (event) => {
    state = 0;  // Restore the default state
    
    // When the mouse is up, compare it with the down coordinate to determine whether to slide left or right
    // Swipe left to display the next slider, so index is increased by 1
    if (event.pageX < startEvent.pageX) {
        index ++;
    }
    else {
        index --;
    }

    // Append a move style
    containerEl.className += ' move';
    // When the transition is over, be sure to remove this class
    containerEl.addEventListener('transitionend', () = > {// Regular substitution \s+ represents one or more whitespace characters
        containerEl.className = containerEl.className.replace(/\s+move/.' ');
    })
    
    left = 0 - itemWidth * index;
    containerEl.style.left = left + 'px';
    console.log('Mouse up');
});
Copy the code

Observe the DOM node of swiper-Container:



index

containerEl.addEventListener('mouseup', (event) => {
    state = 0;  // Restore the default state
    
    // When the mouse is up, compare it with the down coordinate to determine whether to slide left or right
    // Swipe left to display the next slider, so index is increased by 1
    if (event.pageX < startEvent.pageX) {
        index ++;
    }
    else {
        index --;
    }

    // Prevent the slider from running out of bounds
    // If the current slider is first, slide to the right to return to the first slider
    // If it is the last one, slide left to return to the last slider
    if (index < 0) {
        index = 0;
    }
    else if (index > itemEls.length - 1) {
        index = itemEls.length - 1;
    }

    // Append a move style
    containerEl.className += ' move';
    // When the transition is over, be sure to remove this class
    containerEl.addEventListener('transitionend', () = > {// Regular substitution \s+ represents one or more whitespace characters
        containerEl.className = containerEl.className.replace(/\s+move/.' ');
    })

    left = 0 - itemWidth * index;
    containerEl.style.left = left + 'px';
    console.log('Mouse up');
});
Copy the code






2.2 Mechanism of Auto Play

Going back to our list of features, let’s look at number four, “autoplay,” and the first one that comes to mind is setInterval

setInterval((a)= > {
    // This callback is executed every 2 seconds
}, 2000);
Copy the code

So, why don’t we just write code inside the callback to make the slider slide? We use the index variable to control the current slider, so every 2 seconds increase index by 1, and then calculate the left value according to index.

setInterval((a)= > {
    // Swipe left by default
    index ++;
    // If you slide to the last slider, go back to the first slider
    if (index > itemEls.length - 1) {
        index = 0;
    }

    // The following code is the same as our mouse lift event code, do you want to consider simple encapsulation?
    // Append a move style
    containerEl.className += ' move';
    // When the transition is over, be sure to remove this class
    containerEl.addEventListener('transitionend', () = > {// Regular substitution \s+ represents one or more whitespace characters
        containerEl.className = containerEl.className.replace(/\s+move/.' ');
    })

    left = 0 - itemWidth * index;
    containerEl.style.left = left + 'px';
}, 2000);
Copy the code


But it’s not a problem that he does this all the time. Sometimes I want to read something, and then I swipe it away before I’m done, so we can stop it when the mouse is over the container, and then we can start it again

  1. mouseoverMouse over an element
  2. mouseoutMouse over an element

We still listen for both events on the container and use a state autoplay to control playback:

// Automatic playback status
let autoplay = true;

setInterval((a)= > {
    if(! autoplay)return;  
    // Swipe left by default
    index ++;
    // If you slide to the last slider, go back to the first slider
    if (index > itemEls.length - 1) {
        index = 0;
    }

    // Append a move style
    containerEl.className += ' move';
    // When the transition is over, be sure to remove this class
    containerEl.addEventListener('transitionend', () = > {// Regular substitution \s+ represents one or more whitespace characters
        containerEl.className = containerEl.className.replace(/\s+move/.' ');
    })

    left = 0 - itemWidth * index;
    containerEl.style.left = left + 'px';
}, 2000);

containerEl.addEventListener('mouseover', () = > {// Move the mouse over the container to stop playing
    autoplay = false;
});
containerEl.addEventListener('mouseout', () = > {// Remove the mouse from the container and resume playing
    autoplay = true;
});
Copy the code



clearInterval





3. The end

So far, our principle is about, there is omission, but also hope to point out, so in the second part, I will and everyone to write a miscellaneous miscellaneous code to do a package, let our code plug-in, adapt to more scenarios.


Like children’s shoes, powder bai ~, irregular technical tutorial update