728x90
⭐ Gsap
- 웹 화면에 쉽게 사용할 수 있는 강력한 타임라인 기반의 애니메이션 자바스크립트 라이브러리입니다.
- GSAP를 이용해서 멋진 인터랙티브한 웹사이트를 만들 수 있습니다.
- https://greensock.com/react
- https://www.npmjs.com/package/gsap
gsap
GSAP is a framework-agnostic JavaScript animation library that turns developers into animation superheroes. Build high-performance animations that work in **every** major browser. Animate CSS, SVG, canvas, React, Vue, WebGL, colors, strings, motion paths,.
www.npmjs.com
1. gsap install
- install
npm install gsap
- import
import gsap from 'gsap';
import ScrollToPlugin from 'gsap/ScrollToPlugin';
gsap.registerPlugin(ScrollToPlugin);
2. gsap - step1
- 기본 구조 및 css 정의
- gsap1.css
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic);
body, h1, h2, h3, h4, h5, h6, p, ul, ol, table, dl, dd {
margin: 0;
padding: 0;
}
h1 {
font-size: 16px;
}
a {
text-decoration: none;
color: #000;
}
ul, ol {
list-style: none;
}
img {
max-width: 100%;
vertical-align: top;
border: none;
}
body {
margin: 20px;
padding: 20px;
line-height: 1;
font-family: "Open Sans", sans-serif;
font-size: 1em;
background-color: #f1f1f1;
color: #555;
}
.title {
margin: 0;
padding: 0;
font-size: 1.5em;
font-weight: 300;
color: #555;
}
.container {
margin-top: 50px;
}
.ball {
position: absolute;
left: 0;
top: 200px;
width: 50px;
height: 50px;
background-color: #8ac007;
border-radius: 25px;
}
- App.js
import React, { Component, Fragment } from 'react';
import './App.css';
import gsap from 'gsap';
import './css/gsap1.css';
class App extends Component {
componentDidMount() {
let ball = document.getElementsByClassName("ball")[0];
ball.addEventListener("click", function() {
gsap.fromTo(ball, {opacity: 0}, {opacity: 1, left: 300, duration: 0.3, delay: 2});
});
}
render() {
return (
<Fragment>
<h1 className='title'>basic :: React Example</h1>
<div className='container'>
<div className='ball'></div>
</div>
</Fragment>
)
}
}
export default App;
3. gsap - step2
- 헤더, 콘텐트, Scroll Page 만들기
- gsap2.css
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic);
body, h1, h2, h3, h4, h5, h6, p, ul, ol, table, dl, dd {
margin: 0;
padding: 0;
}
h1 {
font-size: 16px;
}
a {
text-decoration: none;
color: #2f2f2f;
}
ul, ol {
list-style: none;
}
img {
max-width: 100%;
vertical-align: top;
border: none;
}
body {
line-height: 1;
font-family: "Open Sans", sans-serif;
font-size: 1em;
}
.top {
position: absolute;
left: 0;
top: 0;
width: 100%;
min-width: 1100px;
background-color: transparent;
}
.top.fixed {
position: fixed;
background-color: rgba(0,0,0,.1);
}
.top .top_inner {
margin: 0 auto;
padding: 30px 0;
width: 1100px;
height: 100px;
box-sizing: border-box;
}
.top .logo {
float: left;
height: 40px;
}
.top .logo a img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
#gnb {
float: left;
margin-left: 80px;
}
#gnb li {
display: inline-block;
}
#gnb li a {
display: block;
padding: 0 25px;
line-height: 40px;
text-transform: uppercase;
font-size: 0.875em;
font-weight: 400;
color: #000;
}
#gnb li a:hover,
#gnb li.active a {
color: #e5493a;
}
.content div {
padding: 120px 40px 40px;
height: 900px;
text-transform: uppercase;
font-size: 2em;
font-weight: 300;
color: #ccc;
border-bottom: 1px solid #eaeaea;
box-sizing: border-box;
}
- App.js
import React, { Component, Fragment } from 'react';
import './App.css';
import gsap from 'gsap';
import './css/gsap2.css';
import Logo from './js2/step3/Logo';
import Navigation from './js2/step3/Navigation';
import Content from './js2/step3/Content';
class App extends Component {
render() {
return (
<div className='container'>
<div className='top'>
<div className="top_inner">
<Logo />
<Navigation />
</div>
</div>
<Content />
</div>
)
}
}
export default App;
- Content.js : Content의 영역을 담을 컴포넌트
import React, { Component } from 'react';
import ContentList from './ContentList';
class Content extends React.Component {
render() {
return (
<div className='content'>
<ContentList id="area1">content1</ContentList>
<ContentList id="area2">content2</ContentList>
<ContentList id="area3">content3</ContentList>
<ContentList id="area4">content4</ContentList>
<ContentList id="area5">content5</ContentList>
<ContentList id="area6">content6</ContentList>
<ContentList id="area7">content7</ContentList>
<ContentList id="area8">content8</ContentList>
</div>
)
}
}
export default Content;
- ContentList.js : Content의 공통 사용 컴포넌트
import React, { Component } from 'react';
class ContentList extends React.Component {
render() {
return (
<div id={this.props.id}>{this.props.children}</div>
);
}
}
export default ContentList;
- Logo.js : 헤더의 로고 컴포넌트
import React, { Component } from 'react';
class Logo extends React.Component {
render() {
return (
<h1 className='logo'>
<a href=''>
<img src="/assets/images/logo.png" alt='logo'></img>
</a>
</h1>
)
}
}
export default Logo;
- Navigation.js : 실제 Navagation 행위가 이루어질 컴포넌트
import React, { Component } from 'react';
import gsap from 'gsap';
import ScrollToPlugin from 'gsap/ScrollToPlugin';
class Navigation extends Component {
componentDidMount() {
gsap.registerPlugin(ScrollToPlugin);
let n = 0;
let t = 0;
let targety = 0;
let scrollTimer = 0;
let winHalf;
let top = document.getElementsByClassName("top")[0];
let content=document.getElementsByClassName("content")[0];
let contentLi=content.children;
let gnb=document.getElementById("gnb");
let gnbLi=gnb.firstElementChild.children;
gnbLi[n].classList.add("active");
let init=() => winHalf=window.innerHeight/2;
init();
window.addEventListener("resize", init);
window.addEventListener("scroll", () => {
clearTimeout(scrollTimer);
scrollTimer=setTimeout(() => {
t=window.scrollY;
if(t < contentLi[1].offsetTop-winHalf){
n=0;
}
else if(t < contentLi[2].offsetTop-winHalf){
n=1;
}
else if(t < contentLi[3].offsetTop-winHalf){
n=2;
}
else if(t < contentLi[4].offsetTop-winHalf){
n=3;
}
else if(t < contentLi[5].offsetTop-winHalf){
n=4;
}
else if(t < contentLi[6].offsetTop-winHalf){
n=5;
}
else if(t < contentLi[7].offsetTop-winHalf){
n=6;
}
else{
n=7;
}
// console.log("n : "+n);
for(let i=0; i<gnbLi.length; i++){
if(i === n){
gnbLi[i].classList.add("active");
}
else{
gnbLi[i].classList.remove("active");
}
}
if(t > 80){
if(top.classList.contains("fixed") === false){
top.classList.add("fixed");
gsap.fromTo(top, {top: -100}, {top: 0, duration: 0.3, delay: 0.5});
}
}
else{
if(top.classList.contains("fixed") === true){
top.classList.remove("fixed");
top.removeAttribute("style");
}
}
}, 50);
});
for(let i=0; i<gnbLi.length; i++){
gnbLi[i].addEventListener("click", e => {
e.preventDefault();
targety=contentLi[i].offsetTop;
gsap.to(window, {scrollTo: targety, duration: 0.5});
});
}
}
render(){
return(
<nav id="gnb">
<ul>
<li><a href="#area1">HOME</a></li>
<li><a href="#area2">ABOUT US</a></li>
<li><a href="#area3">PAGES</a></li>
<li><a href="#area4">FEATURES</a></li>
<li><a href="#area5">PORTFOLIO</a></li>
<li><a href="#area6">BLOG</a></li>
<li><a href="#area7">SHOP</a></li>
<li><a href="#area8">CONTACT US</a></li>
</ul>
</nav>
);
}
}
export default Navigation;
- 결과
728x90
'React' 카테고리의 다른 글
React STEP 27 - jquery + react (0) | 2025.03.04 |
---|---|
React STEP 25 - 기본 구조 사용하기 (0) | 2025.03.04 |
React STEP 24 - TODO 리스트 예제 (2) | 2025.02.11 |
React STEP 23 - Create React App - 5 (1) | 2025.02.11 |
React STEP 22 - Create React App - 4 (0) | 2025.02.11 |