рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкрд░ рдПрдХ рд╕реНрд▓рд╛рдЗрдбрд░ рдХреЗ рд▓рд┐рдП рдПрдХ рд╢рд╛рдВрдд рдЪрд┐рдкрдЪрд┐рдкрд╛ рдкреНрд░рднрд╛рд╡ рдмрдирд╛рдирд╛

рд╕рднреА рд╕рдВрднрд╛рд╡рд┐рдд рдкреНрд░рднрд╛рд╡реЛрдВ рдХреЗ рд╕рд╛рде рд╕реНрд▓рд╛рдЗрдбрд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдИ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИрдВред рд░рд┐рдПрдХреНрдЯ рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдЕрдЪреНрдЫреЗ рд╣реИрдВ: рд░рд┐рдПрдХреНрдЯреНрд╕реНрд▓рд┐рдХ рдФрд░ рд╕реНрд╡рд┐рдкрд░ ред рд▓реЗрдХрд┐рди рдЬрдм рдореЗрд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рдХреНрд╖реИрддрд┐рдЬ рдЪрд┐рдкрдЪрд┐рдкрд╛ рдкреНрд░рднрд╛рд╡ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереА, рддреЛ рдЙрдкрдпреБрдХреНрдд рдХреБрдЫ рднреА рдирд╣реАрдВ рдорд┐рд▓рд╛ред



рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рд╣рдо рдзреАрд░реЗ-рдзреАрд░реЗ рдРрд╕реЗ рд╕реНрд▓рд╛рдЗрдбрд░ рдмрдирд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВрдЧреЗ, рд╢рд╛рдпрдж рдЖрдкрдХреЛ рднреА рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА!


рдЖрд╡рд╢реНрдпрдХ рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ


рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдо Create React App рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ ред


рдПрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдПрдВ:


npx create-react-app my-app 

рд╣рдо рд╕реНрд▓рд╛рдЗрдбрд░ рдХреЛ рдЦрд░реЛрдВрдЪ рд╕реЗ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ, рд▓реЗрдХрд┐рди рд╕реНрд╡рд┐рдкрд░ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рд▓реЗрдВ, рд╕рдмрд╕реЗ рдЙрдкрдпреБрдХреНрдд рдШрдЯрдирд╛рдПрдВ рд╣реИрдВ рдЬрд┐рдирдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рд╣реБрдХ рдЕрдк рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА (рдЙрд╕ рдкрд░ рдмрд╛рдж рдореЗрдВ рдЕрдзрд┐рдХ)ред рдлрд┐рд░ рд╣рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреИрдХреЗрдЬреЛрдВ рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛:


 npm i swiper react-id-swiper 

рдФрд░ sass рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдВрддрд┐рдо рдкреИрдХреЗрдЬ (рд╡реИрдХрд▓реНрдкрд┐рдХ):


 npm i node-sass 

рдкрд░рд┐рдгрд╛рдо рдкреИрдХреЗрдЬ рд╣реИред рдЖрдЧрдЬрдиреА:


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" ] } } 

рдорд╣рд╛рди, рдЕрдм рд╣рдо рд╕реНрд▓рд╛рдЗрдбрд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рд░рд╣реЗ рд╣реИрдВред


рдПрдХ рд╕рд╛рдзрд╛рд░рдг рд╕реНрд▓рд╛рдЗрдбрд░ рдмрдирд╛рдПрдВ


рдЖрдЗрдП рд╣рдорд╛рд░реА рд╕реНрд▓рд╛рдЗрдбреНрд╕ рдХреЗ рд╕рд╛рде рдПрдХ рдЫреЛрдЯреА рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдХрд░ рд╢реБрд░реВ рдХрд░реЗрдВред


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" } ] 

рдЙрд╕рдХреЗ рдмрд╛рдж рд╣рдо рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкреНрд░рднрд╛рд╡реЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдирд┐рдпрдорд┐рдд рд╕реНрд▓рд╛рдЗрдбрд░ рдмрдирд╛рдПрдВрдЧреЗред


 // 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; 

рдФрд░ рддрджрдиреБрд╕рд╛рд░, рд╣рдо рдШрдЯрдХ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реВрдЪрдХрд╛рдВрдХ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рддреЗ рд╣реИрдВред


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

рдПрдХрдорд╛рддреНрд░ рдкреИрд░рд╛рдореАрдЯрд░ рдЬреЛ рд╣рдордиреЗ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рд╣реИ slidesPerView рд╣реИ slidesPerView (рджреГрд╢реНрдпрдорд╛рди рд╕реНрд▓рд╛рдЗрдб рдХреА рд╕рдВрдЦреНрдпрд╛)ред рд╣рдореЗрдВ рдХрд┐рд╕реА рдФрд░ рдЪреАрдЬ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣рд╛рдВ рдкрд░ рд╕рднреА рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рдВрднрд╛рд╡рд┐рдд рдкреИрд░рд╛рдореАрдЯрд░ рдорд┐рд▓ рд╕рдХрддреЗ рд╣реИрдВ ред


рдПрдХ рдЕрд▓рдЧ рдШрдЯрдХ рд╕реНрд▓рд╛рдЗрдб рдмрдирд╛рдПрдВ, рддрд╛рдХрд┐ рд╕реНрд▓рд╛рдЗрдбрд░ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рддреИрдпрд╛рд░ рд╣реЛред


 // 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; 

рд╕реНрд▓рд╛рдЗрдб рдХреЗ рд▓рд┐рдП рд╢реИрд▓рд┐рдпрд╛рдБ


 // 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; } 

рдФрд░ рддрд░реНрдЬрдиреА рдХреЗ рдЕрдиреБрд╕рд╛рд░:


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

рдФрд░ 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; 

рдЕрдм рдЗрд╕ рд╕реНрд▓рд╛рдЗрдбрд░ рдХреЛ App.jsx рдореЗрдВ App.jsx , рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рдиреНрдпреВрдирддрдо рдкреЗрдЬ рд╕рдВрд░рдЪрдирд╛ рд░рдЦреЗрдВред


 // 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; 

рдФрд░ рдЗрд╕реА scss рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╣рдо рдХреБрдЫ рд╢реИрд▓рд┐рдпреЛрдВ рдХреЛ рд▓рд┐рдЦреЗрдВрдЧреЗред


 // 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; } 

рдЕрдм рддрдХ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдРрд╕рд╛ рд╕реНрд▓рд╛рдЗрдбрд░ рд╣реИ:



рдХреВрд▓, рдПрдХ рд╢реБрд░реБрдЖрдд рдХреА рдЧрдИ рд╣реИ, рд╣рдо рд╡рд╣ рдХрд░рдирд╛ рдЬрд╛рд░реА рд░рдЦреЗрдВрдЧреЗ рдЬреЛ рд╣рдореЗрдВ рдЗрд╕ рд╕реНрд▓рд╛рдЗрдбрд░ рд╕реЗ рдЪрд╛рд╣рд┐рдПред


рдПрдХ рдЪрд┐рдкрдЪрд┐рдкрд╛ рдкреНрд░рднрд╛рд╡ рдЬреЛрдбрд╝реЗрдВ


Swiper рдореЗрдВ рджреЛ setTranslate рдФрд░ setTransition рдИрд╡реЗрдВрдЯ рд╣реЛрддреЗ рд╣реИрдВ setTransition setTranslate setTransition ред


рд╕рдВрдкрддреНрддрд┐рдЬрдм рдЯреНрд░рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИрдХреНрдпрд╛ рд▓реМрдЯрд╛?
setTranslateрдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм рд╣рдо рд╕реНрд▓рд╛рдЗрдбрд░ рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЙрд╕ рд╕рдордп рдЬрдм рд╣рдо рдЗрд╕реЗ рдХрдо рдХрд░рддреЗ рд╣реИрдВрд╡рд╣ рдорд╛рди рд▓реМрдЯрд╛рддрд╛ рд╣реИ рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рд╕реНрд▓рд╛рдЗрдбрд░ рдХреЛ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдорд╛рдорд▓реЗ рдореЗрдВ рдЬрдм рд╣рдо рдЗрд╕реЗ рдЬрд╛рд░реА рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╡рд╣ рдорд╛рди рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдпрд╣ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛
setTransitionрдпрд╣ рддрдм рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм рд╣рдо рд╕реНрд▓рд╛рдЗрдбрд░ рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рдЬрдм рд╣рдо рдЗрд╕реЗ рдЬрд╛рд░реА рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЬрдм рд╕реНрд▓рд╛рдЗрдбрд░ рдХреЛ рд╡рд╛рдВрдЫрд┐рдд рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд▓рд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИрдорд┐рд▓реАрд╕реЗрдХрдВрдб рдореЗрдВ рд╕рдВрдХреНрд░рдордг рдорд╛рди рд▓реМрдЯрд╛рддрд╛ рд╣реИ

рдЗрд╕реЗ рд╣рдорд╛рд░реЗ StickySlider рдШрдЯрдХ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ рдФрд░ рдЗрд╕реЗ рддреБрд░рдВрдд Slider рдЕрдЧреНрд░реЗрд╖рд┐рдд рдХрд░реЗрдВ, рд╡рд╣рд╛рдВ рдпрд╣ рдХрд╛рдо рдЖрдПрдЧрд╛:


 // 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; 

рдореИрдВ рдЖрдкрдХреЛ рд╕реНрд▓рд╛рдЗрдбрд░ рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВ рдФрд░ рдЗрд╕ рдХреНрд╖рдг рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдП рдЧрдП рдЕрдзрд┐рдХ рд╡рд┐рд╡рд░рдг рдореЗрдВ рджреЗрдЦ рд╕рдХрддрд╛ рд╣реВрдВ:


 // 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]); // .. 

рдореИрдВ рд░рд╛рдЬреНрдп рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред рдпрджрд┐ рдЖрдк рдЙрдирд╕реЗ рдкрд░рд┐рдЪрд┐рдд рдирд╣реАрдВ рд╣реИрдВ, рддреЛ рдореИрдВ рдЖрдкрдХреЛ рдкреНрд░рд▓реЗрдЦрди (рд░реВрд╕реА рдореЗрдВ) рдкрдврд╝рдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВред


рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, Slide рдШрдЯрдХ рдореЗрдВ рд╕рдмрд╕реЗ рдХрдард┐рди рдХрд╛рдо рд╣реЛрдЧрд╛ред


рд╣рдореЗрдВ рд╕реНрд▓рд╛рдЗрдбрд░ рдХреА рдмрд╛рдИрдВ рд╕реАрдорд╛ рд╕реЗ рдЪрд╛рд▓реВ рд╕реНрдерд┐рддрд┐ рдФрд░ рд╡рд░реНрддрдорд╛рди рд╕реНрд▓рд╛рдЗрдб рдХреА рдЪреМрдбрд╝рд╛рдИ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:


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

рд╡реЗ рддрддреНрд╡ рдЖрд░рдВрднреАрдХрд░рдг рдореЗрдВ рдПрдХ рдмрд╛рд░ рдЬреБрдбрд╝ рдЬрд╛рддреЗ рд╣реИрдВ рдФрд░ рдмрджрд▓реЗ рдирд╣реАрдВ рдЬрд╛рддреЗ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП рд╣рдо рдПрдХ рдЦрд╛рд▓реА рд╕рд░рдгреА рдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдЙрд╕реА рд╕рдордп, рд╣рдо рдкреИрд░рд╛рдореАрдЯрд░ рдХреЛ рд╕реНрд▓рд╛рдЗрдб рдХреЗ рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ parentElement рдорд╛рдзреНрдпрдо рд╕реЗ рдЗрд╕рдХреЗ рддрдХрдиреАрдХреА рдЖрд╡рд░рдг рд╕реЗ parentElement , рдХреНрдпреЛрдВрдХрд┐ рд╣рдо transform рд╕рдВрдкрддреНрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡рд░реНрддрдорд╛рди рдЖрд╡рд░рдг рдХреЛ рдмрджрд▓ рджреЗрдВрдЧреЗред


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

рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдХреНрд╖рдгред рд╣рдо рдЗрд╕ рдкреВрд░реА рдмрд╛рдд рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рд╢реИрд▓рд┐рдпреЛрдВ рдореЗрдВ рдкрд┐рд░реЛрддреЗ рд╣реИрдВ:


 // 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`, } : {}; // ... 

translate рд╕рдВрдкрддреНрддрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдорд╛рддрд╛-рдкрд┐рддрд╛ рд╕реЗ рдЖрддреА рд╣реИ рдФрд░ рдпрд╣ рд╕рднреА рд╕реНрд▓рд╛рдЗрдб рдХреЗ рд▓рд┐рдП рд╕рдорд╛рди рд╣реИред рдЗрд╕рд▓рд┐рдП, рдПрдХ рд╕реНрд▓рд╛рдЗрдб рдХреЗ рд▓рд┐рдП рдПрдХ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдЕрдиреБрд╡рд╛рдж рдвреВрдВрдврдиреЗ рдХреЗ рд▓рд┐рдП, offsetLeft рдХреЛ рдШрдЯрд╛рдПрдВред


рдЪрд░ k 0 рд╕реЗ 1 рддрдХ рдХрд╛ рдорд╛рди рд╣реИред рдЗрд╕ рдорд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдПрдиреАрдореЗрд╢рди рдХрд░реЗрдВрдЧреЗред рдпрд╣ рдПрдХ рдореБрдЦреНрдп рдЪрд░ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рд╕реА рднреА рдкреНрд░рднрд╛рд╡ рдХреЛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред


рдЕрдм рд╣рдо рд╢реИрд▓рд┐рдпреЛрдВ рдХреА рдЧрдгрдирд╛ рдХрд░рддреЗ рд╣реИрдВред рдПрдиреАрдореЗрд╢рди рдЬрд╝реЛрди рдореЗрдВ рд╕реНрд▓рд╛рдЗрдб рд╣реЛрдиреЗ рдкрд░ рдХрдВрдбреАрд╢рди x >= -1 рд╕рдВрддреБрд╖реНрдЯ рд╣реЛрддреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЬрдм рдЗрд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рд╣рдо рд╢реИрд▓рд┐рдпреЛрдВ рдХреЛ рд╕рд╛рдЗрдб рдореЗрдВ рд▓рдЯрдХрд╛ рджреЗрддреЗ рд╣реИрдВред scale рдФрд░ opacity рдорд╛рди рдХрд╛ рдЪрдпрди рдЖрдкрдХреА рдЗрдЪреНрдЫрд╛рдиреБрд╕рд╛рд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЕрдВрддрд░рд╛рд▓ рдореБрдЭреЗ рд╕рдмрд╕реЗ рдЙрдкрдпреБрдХреНрдд рд▓рдЧрддрд╛ рдерд╛: scale рд▓рд┐рдП [0.8 : 1] рдФрд░ opacity рд▓рд┐рдП [0.5 : 1] ред


transition рдкреНрд░реЙрдкрд░реНрдЯреА рдХреЛ рд╕реАрдзреЗ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдЗрд╡реЗрдВрдЯ рд╕реЗ рд╕рдкреНрд▓рд╛рдИ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


рдпрд╣рд╛рдБ рдЙрдкрд░реЛрдХреНрдд рд╕рднреА рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рдмрд╛рдж рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ:


 // 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; 

рдЕрдм рд╕реНрд▓рд╛рдЗрдб рд╢реИрд▓реА рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЧреБрдг рдЬреЛрдбрд╝реЗрдВ:


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

рдЦреИрд░, рдпрд╣ рддреЛ рд╣реИ, рд╣рдорд╛рд░рд╛ рдкреНрд░рднрд╛рд╡ рддреИрдпрд╛рд░ рд╣реИ! рдЖрдк рдореЗрд░реЗ рдЧреАрдереБрдм рдкрд░ рд╕рдорд╛рдкреНрдд рдЙрджрд╛рд╣рд░рдг рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ ред


рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!

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


All Articles