Schreiben eines komplizierten, aber interessanten JavaScript-Schiebereglers



Guten Tag, Freunde! Ich beschloss, zum Thema Schieberegler zurückzukehren. Dieser Artikel diente als Inspiration . Ein Artikel über den Bildergalerie-Generator mit integriertem Schieberegler ist hier .

Der Schieberegler, den wir schreiben werden, funktioniert nach dem Prinzip eines endlosen Kartenspiels oder eines Stapel von Bildern. Das obere Bild wird in einer von drei Richtungen verworfen - links, rechts oder oben. Das verworfene Bild wird durch das folgende ersetzt und so weiter bis ins Unendliche. Sie können Ihre Bilder hochladen oder die Standardbilder verwenden.

Zum Registrieren von Gesten (Berührungen) und Bewegen (Ziehen und Ablegen) wird hammer.js verwendet . Mit dieser Bibliothek können Sie sowohl Mausklicks als auch Fingerberührungen erkennen.

So lass uns gehen.

Das Markup sieht folgendermaßen aus:

<input type="file" multiple>
<button>build carousel</button>
<div></div>

Wir haben eine „Eingabe“ zum Laden von Bildern, eine Schaltfläche zum Erstellen eines Karussells und einen Behälter für Karten.

Fügen Sie einige Stile hinzu:

body {
    margin: 0;
    overflow: hidden;
}

div {
    width: 100%;
    height: 100vh;
    position: relative;
}

img {
    width: 320px;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0.95);
    box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.1);
}

Hier gibt es nichts Besonderes: Die Bilder sind 320 Pixel breit und übereinander zentriert.

Wir gehen zu JS. Ich werde den ganzen Code geben. Haben Sie keine Angst vor der Anzahl der Linien, alles ist ganz einfach, außer vielleicht die Positionen und Koordinaten zu berechnen. Fast jede Zeile hat einen Kommentar.

let button = document.querySelector('button')
let input = document.querySelector('input')
let files
let i = 0

button.addEventListener('click', () => {
    //   
    files = input.files

    document.body.removeChild(input)
    document.body.removeChild(button)

    let board = document.querySelector('div')
    //  
    let carousel = new Carousel(board)
})

class Carousel {
    constructor(element) {
        this.board = element

        //     
        this.push()

        //  
        i++
        this.push()

        //  
        this.handle()
    }

    handle() {
        //    
        this.cards = this.board.querySelectorAll('img')

        //   
        this.topCard = this.cards[this.cards.length - 1]

        //   
        this.nextCard = this.cards[this.cards.length - 2]

        //      
        if (this.cards.length > 0) {
            //      
            this.topCard.style.transform =
                'translate(-50%, -50%) rotate(0deg) scale(1)'

            //   ()   ()   
            this.hammer = new Hammer(this.topCard)
            this.hammer.add(new Hammer.Tap())
            this.hammer.add(new Hammer.Pan({
                position: Hammer.position_ALL,
                threshold: 0
            }))

            //        
            this.hammer.on('tap', (e) => {
                this.onTap(e)
            })
            this.hammer.on('pan', (e) => {
                this.onPan(e)
            })
        }
    }

    //  ()
    onTap(e) {
        //      
        let propX = (e.center.x - e.target.getBoundingClientRect().left) / e.target.clientWidth

        //      Y (+/-15 )
        let rotateY = 15 * (propX < 0.05 ? -1 : 1)

        //    transition
        this.topCard.style.transition = 'transform 100ms ease-out'

        // 
        this.topCard.style.transform =
            'translate(-50%, -50%) rotateX(0deg) rotateY(' + rotateY + 'deg) scale(1)'

        //   
        setTimeout(() => {
            //    transform
            this.topCard.style.transform =
                'translate(-50%, -50%) rotate(0deg) scale(1)'
        }, 100)

    }

    //  ()
    onPan(e) {
        if (!this.isPanning) {
            this.isPanning = true

            //    transition
            this.topCard.style.transition = null
            if (this.nextCard) this.nextCard.style.transition = null

            //      
            let style = window.getComputedStyle(this.topCard)
            let mx = style.transform.match(/^matrix\((.+)\)$/)
            this.startPosX = mx ? parseFloat(mx[1].split(', ')[4]) : 0
            this.startPosY = mx ? parseFloat(mx[1].split(', ')[5]) : 0

            //    
            let bounds = this.topCard.getBoundingClientRect()

            //      ,  (1)   (-1)
            this.isDraggingFrom =
                (e.center.y - bounds.top) > this.topCard.clientHeight / 2 ? -1 : 1
        }

        //   
        let posX = e.deltaX + this.startPosX
        let posY = e.deltaY + this.startPosY

        //       
        let propX = e.deltaX / this.board.clientWidth
        let propY = e.deltaY / this.board.clientHeight

        //   ,  (-1)   (1)
        let dirX = e.deltaX < 0 ? -1 : 1

        //   ,  0  +/-45 
        let deg = this.isDraggingFrom * dirX * Math.abs(propX) * 45

        //    ,  95  100%
        let scale = (95 + (5 * Math.abs(propX))) / 100

        //   
        this.topCard.style.transform =
            'translateX(' + posX + 'px) translateY(' + posY + 'px) rotate(' + deg + 'deg) scale(1)'

        //   
        if (this.nextCard) this.nextCard.style.transform =
            'translate(-50%, -50%) rotate(0deg) scale(' + scale + ')'

        if (e.isFinal) {
            this.isPanning = false

            let successful = false

            //    transition
            this.topCard.style.transition = 'transform 200ms ease-out'
            if (this.nextCard) this.nextCard.style.transition = 'transform 100ms linear'

            //  
            if (propX > 0.25 && e.direction == Hammer.DIRECTION_RIGHT) {
                successful = true

                //    
                posX = this.board.clientWidth

            } else if (propX < -0.25 && e.direction == Hammer.DIRECTION_LEFT) {
                successful = true

                //    
                posX = -(this.board.clientWidth + this.topCard.clientWidth)

            } else if (propY < -0.25 && e.direction == Hammer.DIRECTION_UP) {
                successful = true

                //    
                posY = -(this.board.clientHeight + this.topCard.clientHeight)

            }

            if (successful) {
                //     
                this.topCard.style.transform =
                    'translateX(' + posX + 'px) translateY(' + posY + 'px) rotate(' + deg + 'deg)'

                //   
                setTimeout(() => {
                    //   
                    this.board.removeChild(this.topCard)

                    //  
                    i++
                    //      ,  
                    if (i === files.length) i = 0

                    //   
                    this.push()
                    //      
                    this.handle()
                }, 200)

            } else {
                //   
                this.topCard.style.transform =
                    'translate(-50%, -50%) rotate(0deg) scale(1)'
                if (this.nextCard) this.nextCard.style.transform =
                    'translate(-50%, -50%) rotate(0deg) scale(0.95)'
            }
        }
    }

    //  
    push() {
        let card = document.createElement('img')
        
        //    ,    
        //  ,  
        if (files.length === 0) {
            card.src = 'https://picsum.photos/320/320/?random=' +
                Math.round(Math.random() * 1000000) +
                ')'
        } else {
            card.src = URL.createObjectURL(files[i])
        }

        if (this.board.firstChild) {
            this.board.insertBefore(card, this.board.firstChild)
        } else {
            this.board.append(card)
        }
    }
}



Github

Vielen Dank für Ihre Aufmerksamkeit.

All Articles