Membuat efek lengket keren untuk slider di Bereaksi

Ada banyak pustaka yang berbeda untuk menerapkan slider dengan semua efek yang memungkinkan. Beberapa yang terbaik untuk React adalah: ReactSlick dan Swiper . Tetapi ketika efek lengket horizontal diperlukan untuk proyek saya, tidak ada yang cocok ditemukan.



Pada artikel ini kita akan mencoba membuat slider secara bertahap, mungkin Anda akan membutuhkannya juga!


Instal paket yang diperlukan


Kami akan menggunakan Create React App untuk membuat proyek .


Buat aplikasi:


npx create-react-app my-app 

Kami tidak akan melakukan bilah geser dari awal, tetapi ambil pustaka Swiper , ada beberapa acara yang paling sesuai yang perlu Anda sambungkan (lebih lanjut tentang ini nanti). Maka kita perlu menginstal paket-paket berikut:


 npm i swiper react-id-swiper 

Dan paket terakhir (opsional) untuk menggunakan prepassassassass:


 npm i node-sass 

Hasilnya adalah package.json:


package.json


 { "name": "sticky-slider", "version": "0.1.0", "private": true, "dependencies": { "node-sass": "^4.13.0", "react": "^16.11.0", "react-dom": "^16.11.0", "react-id-swiper": "^2.3.2", "react-scripts": "3.2.0", "swiper": "^5.2.0" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": "react-app" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } 

Hebat, sekarang kita mulai menerapkan slider.


Buat slider sederhana


Mari kita mulai dengan membuat file kecil dengan slide kami.


src/data.json


 [ { "title": "Slide 1", "color": "#aac3bf" }, { "title": "Slide 2", "color": "#c9b1bd" }, { "title": "Slide 3", "color": "#d5a29c" }, { "title": "Slide 4", "color": "#82a7a6" }, { "title": "Slide 5", "color": "#e6af7a" }, { "title": "Slide 6", "color": "#95be9e" }, { "title": "Slide 7", "color": "#97b5c5" } ] 

Setelah itu kami akan membuat slider biasa dengan efek default.


 // src/components/StickySlider/StickySlider.jsx import React from 'react'; import Swiper from 'react-id-swiper'; import 'react-id-swiper/lib/styles/css/swiper.css'; import data from '../../data'; const StickySlider = () => { const params = { slidesPerView: 3, }; return ( <Swiper {...params}> {data.map((item, idx) => ( <div key={idx}> {item.title} </div> ))} </Swiper> ); }; export default StickySlider; 

Dan karenanya, kami membuat file indeks untuk komponen.


 // src/components/StickySlider/index.js export { default } from './StickySlider'; 

Satu-satunya parameter yang kami jelaskan adalah slidesPerView (jumlah slide yang terlihat). Kami tidak membutuhkan yang lain, tetapi semua parameter swiper yang memungkinkan dapat ditemukan di sini .


Buat Slide komponen terpisah, sehingga tampilan slider siap.


 // src/components/Slide/Slide.jsx import React from 'react'; import css from './Slide.module.scss'; const Slide = ({ children, color }) => { return ( <div className={css.container}> <div className={css.content} style={{ background: color }} /> <footer className={css.footer}> {children} </footer> </div> ); }; export default Slide; 

Gaya untuk slide.


 // src/components/Slide/Slide.module.scss .container { margin: 0 1em; border-radius: 4px; overflow: hidden; background-color: #fff; } .content { box-sizing: border-box; padding: 50% 0; } .footer { color: #333; font-weight: 700; font-size: 1.25em; text-align: center; padding: 1em; } 

Dan sesuai dengan file indeks:


 // src/components/Slide/index.js export { default } from './Slide'; 

Dan perbarui sedikit StickySlider.


 // src/components/StickySlider/StickySlider.jsx import React from 'react'; import Swiper from 'react-id-swiper'; import 'react-id-swiper/lib/styles/css/swiper.css'; import Slide from '../Slide'; import data from '../../data'; const StickySlider = () => { const params = { slidesPerView: 3, }; return ( <Swiper {...params}> {data.map((item, idx) => ( <div key={idx}> {/*   */} <Slide color={item.color}> {item.title} </Slide> </div> ))} </Swiper> ); }; export default StickySlider; 

Sekarang masukkan slider ini ke App.jsx , pada saat yang sama meletakkan struktur halaman minimum.


 // App.jsx import React from 'react'; import StickySlider from './components/StickySlider'; import css from './App.module.scss'; const App = () => { return ( <div className={css.container}> <h1 className={css.title}>Sticky slider</h1> <div className={css.slider}> <StickySlider /> </div> </div> ); }; export default App; 

Dan dalam file scss yang sesuai, kami akan menulis beberapa gaya.


 // App.module.scss .container { padding: 0 15px; } .title { font-weight: 700; font-size: 2.5em; text-align: center; margin: 1em 0; } .slider { margin: 0 -15px; } 

Sejauh ini, kami memiliki slider seperti itu:



Keren, permulaan telah dibuat, kami akan terus melakukan apa yang kami butuhkan dari slider ini.


Tambahkan efek lengket


Swiper memiliki dua peristiwa setTransition dan setTransition yang setTranslate setTransition .


PropertiKapan dipicuApa yang kembali
setTranslateIni berfungsi saat kita menggerakkan bilah geser dan saat kita menurunkannyamengembalikan nilai dengan mana slider saat ini digeser, dan dalam kasus ketika kita melepaskannya, nilai yang akan dibawa slider secara otomatis
setTransitionini bekerja ketika kita mulai memindahkan slider, ketika kita melepaskannya dan ketika slider dibawa ke posisi yang diinginkanmengembalikan nilai transisi dalam milidetik

Tambahkan ini ke komponen StickySlider kami dan segera kirimkan ke Slider , itu akan sangat berguna:


 // src/components/StickySlider/StickySlider.jsx import React, { useState, useEffect } from 'react'; import Swiper from 'react-id-swiper'; import 'react-id-swiper/lib/styles/css/swiper.css'; import Slide from '../Slide'; import data from '../../data'; const StickySlider = () => { const [swiper, updateSwiper] = useState(null); const [translate, updateTranslate] = useState(0); const [transition, updateTransition] = useState(0); const params = { slidesPerView: 3, }; useEffect(() => { if (swiper) { swiper.on('setTranslate', (t) => { updateTranslate(t); }); swiper.on('setTransition', (t) => { updateTransition(t); }); } }, [swiper]); return ( <Swiper getSwiper={updateSwiper} {...params}> {data.map((item, idx) => ( <div key={idx}> <Slide translate={translate} transition={transition} color={item.color} > {item.title} </Slide> </div> ))} </Swiper> ); }; export default StickySlider; 

Saya menyarankan Anda untuk memindahkan bilah geser dan melihat lebih detail apa yang ditampilkan saat ini:


 // src/components/StickySlider/StickySlider.jsx // ... useEffect(() => { if (swiper) { swiper.on('setTranslate', (t) => { console.log(t, 'translate'); updateTranslate(t); }); swiper.on('setTransition', (t) => { console.log(t, 'transform'); updateTransition(t); }); } }, [swiper]); // .. 

Saya menggunakan kait untuk menyimpan status. Jika Anda tidak terbiasa dengan mereka, saya menyarankan Anda untuk membaca dokumentasi (dalam bahasa Rusia) .


Selanjutnya, hal yang paling sulit akan terjadi pada komponen Slide .


Kita memerlukan status indentasi dari batas kiri slider dan lebar slide saat ini:


 // src/components/StickySlider/StickySlider.jsx // ... const container = useRef(null); const [offsetLeft, updateOffsetLeft] = useState(0); const [width, updateWidth] = useState(1); // ... 

Mereka ditambahkan sekali pada inisialisasi elemen dan tidak diubah. Oleh karena itu kami menggunakan useEffect dengan array kosong. Pada saat yang sama, kami mendapatkan parameter bukan dari slide itu sendiri, tetapi pembungkus teknisnya melalui parentElement , karena kami akan mengonversi pembungkus saat ini menggunakan properti transform .


 // src/components/StickySlider/StickySlider.jsx // ... useEffect(() => { setTimeout(() => { const parent = container.current.parentElement; updateOffsetLeft(parent.offsetLeft); updateWidth(parent.offsetWidth); }, 0); }, []); // ... 

Momen terpenting. Kami mempertimbangkan semua ini dan melemparkannya ke gaya:


 // src/components/Slide/Slide.jsx // ... const x = -translate - offsetLeft; const k = 1 - x / width; // [0 : 1] const style = x >= -1 ? { transform: `translateX(${x}px) scale(${k * 0.2 + 0.8})`, // [0.8 : 1] opacity: k < 0 ? 0 : k * 0.5 + 0.5, // [0.5 : 1] transition: `${transition}ms`, } : {}; // ... 

Properti translate datang kepada kami dari induknya dan sama untuk semua slide. Oleh karena itu, untuk menemukan terjemahan individu untuk satu slide, kurangi offsetLeft darinya.


Variabel k adalah nilai dari 0 hingga 1. Dengan menggunakan nilai ini, kita akan melakukan animasi. Ini adalah variabel kunci, karena dapat digunakan untuk membuat efek apa pun.


Sekarang kita menghitung gaya. Kondisi x >= -1 terpenuhi ketika slide berada di zona animasi, jadi ketika dijalankan, kita menggantung gaya di samping. Nilai scale dan opacity dapat dipilih sesuai keinginan. Interval berikut menurut saya paling cocok: [0.8 : 1] untuk scale dan [0.5 : 1] untuk opacity .


Properti transition dipasok langsung dari acara perpustakaan.


Inilah yang terjadi setelah menambahkan semua hal di atas:


 // src/components/Slide/Slide.jsx import React, { useRef, useEffect, useState } from 'react'; import css from './Slide.module.scss'; const Slide = ({ children, translate, transition, color }) => { const container = useRef(null); const [offsetLeft, updateOffsetLeft] = useState(0); const [width, updateWidth] = useState(1); useEffect(() => { setTimeout(() => { const parent = container.current.parentElement; updateOffsetLeft(parent.offsetLeft); updateWidth(parent.offsetWidth); }, 0); }, []); const x = -translate - offsetLeft; const k = 1 - x / width; // [0 : 1] const style = x >= -1 ? { transform: `translateX(${x}px) scale(${k * 0.2 + 0.8})`, // [0.8 : 1] opacity: k < 0 ? 0 : k * 0.5 + 0.5, // [0.5 : 1] transition: `${transition}ms`, } : {}; return ( <div ref={container} style={style} className={css.container}> <div className={css.content} style={{ background: color }} /> <footer className={css.footer}> {children} </footer> </div> ); }; export default Slide; 

Sekarang tambahkan properti berikut ke file gaya slide:


 // src/components/Slide/Slide.module.scss .container { // ... transform-origin: 0 50%; //      transition-property: opacity, transform; // ,   } // ... 

Nah, itu saja, efek kami siap! Anda dapat melihat contoh selesai di github saya .


Terima kasih atas perhatian anda!

Source: https://habr.com/ru/post/id474254/


All Articles