react+gsap+Draggable实现拖动撕开贴纸显示背部文字效果代码

代码语言:html

所属分类:拖放

代码描述:react+gsap+Draggable实现拖动撕开贴纸显示背部文字效果代码

代码标签: react gsap Draggable 拖动 撕开 贴纸 显示 背部 文字 代码

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  


<link type="text/css" rel="stylesheet" href="//repo.bfw.wiki/bfwrepo/css/normalize.5.0.css">

  
  
<style>
*,
*:after,
*:before {
	box-sizing: border-box;
}

:root {
	--bg: hsl(0 0% 98%);
}

body {
	display: grid;
	place-items: center;
	min-height: 100vh;
	font-family:  "SF Pro Text", "SF Pro Icons", "AOS Icons", "Helvetica Neue", Helvetica, Arial, sans-serif, system-ui;
	overflow: hidden;
	background: var(--bg);
}

section {
	height: 100vh;
	display: grid;
	place-items: center;
	position: fixed;
	inset: 0;
}

.tear-strip:focus-within {
	outline: 10px solid hsl(0 0% 0% / 0.15);
}

.strip-adder {
	position: fixed;
	top: 2rem;
	right: 2rem;
	width: 48px;
	aspect-ratio: 1;
	z-index: 22;
	border-radius: 50%;
	border: 0;
	display: grid;
	place-items: center;
	padding: 0;
	background: hsl(0 0% 90% / var(--alpha, 0));
	transition: background 0.2s;
}

.strip-adder svg {
	width: 65%;
	color: hsl(0 0% 10% / var(--alpha, 0.5));
	transition: color 0.2s;
}

.strip-adder:is(:hover, :focus-visible) {
	--alpha: 1;
}

.reference {
	opacity: 1;
	position: fixed;
	top: 50%;
	left: 50%;
	translate: -50% -150%;
}

.tear-strip {
	font-size: 1.3rem;
	font-weight: bold;
	width: clamp(300px, 470px, 28vw);
	width: 340px;
	height: 78px;
	display: grid;
	place-items: center;
/*	translate: 0 -80%;*/
	position: relative;
	border: 4px dashed hsl(0 0% 91%);
	border-radius: 100px;
	background: linear-gradient(hsl(0 0% 91%), hsl(0 0% 91%)) padding-box;
	color: hsl(0, 0%, 70%);
}

.tear-strip__content {
	position: absolute;
	font-size: 1rem;
	text-align: right;
}

.tear-strip__strip {
	position: absolute;
	inset: 0;
	background: var(--bg);
	display: flex;
	border-radius: 100px;
	align-items: center;
	justify-content: center;
	-webkit-clip-path: inset(-100% 0 -100% 1px);
	        clip-path: inset(-100% 0 -100% 1px);
	color: hsl(0, 0%, 71%);
	font-weight: 500;
}

.tear-strip__shadow {
	position: absolute;
	height: 100%;
	width: 20px;
	background: linear-gradient(90deg, transparent, hsl(0 0% 10% / 0.5));
	filter: blur(8px);
	transform-origin: 100% 50%;
	left: 0;
	opacity: 0;
}

.tear-strip__back {
	position: absolute;
	height: 100%;
	width: 100%;
	border-radius: 100px;
	right: 100%;
}

.tear-strip__backing {
	background: linear-gradient(90deg, hsl(0 0% calc(var(--tab-darkness, 40) * 1%) / var(--bg-alpha, 1)), hsl(0 0% 100% / var(--bg-alpha, 1)), hsl(0 0% 80% / var(--bg-alpha, 1)));
	background-position: 100% 50%;
	background-repeat: no-repeat;
	background-color: hsl(0 0% 93%);
	background-size: calc(var(--bg-size, 0) * 1px) 100%;
	position: absolute;
	inset: 0;
	border-radius: 1000px;
}

.tear-strip__backing::before {
	content: "";
	position: absolute;
	inset: 0 -8px 0 0;
	filter: blur(4px);
	background: radial-gradient(hsl(0 0% 10% / 0.5), transparent 80%);
	border-radius: 1000px;
	z-index: -1;
	opacity: var(--shadow-reveal, 0);
}

.tear-strip__back-shadow {
	position: absolute;
	border-radius: 1000px;
	background: transparent;
	right: 0;
	top: 50%;
	height: 100%;
	translate: 0 -50%;
	width: calc((var(--shadow-width) * var(--shadow-multiplier, 0.8)) * 1px);
	z-index: -1;
	min-width: 100px;
	box-shadow:
		0 0 calc(var(--shadow-spread, 0) * 60px) hsl(10 0% 50% / 0.35);
}

.tear-strip__strip svg {
	background: hsl(78, 75%, 57%);
	border-radius: 50%;
	width: 48px;
	padding: 10px;
	position: absolute;
	left: 11px;
	color: white;
	stroke-width: 2.5px;
	transform-origin: 100% 50%;
}

.tear-strip__handle {
	position: absolute;
	left: 0;
	top: 0;
	bottom: 0;
	aspect-ratio: 1;
	translate: 0% 0;
	background: hsl(280 0% 75% / var(--alpha, 0));
	border-radius: 50%;
	scale: 1.35;
	transition: background 0.2s;
}

.tear-strip__handle:hover:not(:active) {
	--alpha: 0.25;
}

.tear-strip__handle::before {
	content: "";
	width: 200%;
	position: absolute;
	height: 100%;
	left: 50%;
	translate: -50% 0;
}

.sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border-width: 0;
}
</style>

  
  
</head>

<body >
  <div id="app"></div>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/babel.7.18.13.js"></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/gsap.3.9.1.js"></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/Draggable3.min.js"></script>

<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/react.production.17.1.js"></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/react-dom.production.17.1.js"></script>
      <script  type="text/babel">
 const { react } = window.React;
  const { render } = window.ReactDOM;
gsap.registerPlugin(Draggable)

const ROOT_NODE = document.querySelector('#app')

const TearStrip = ({ children }) => {
  const stripRef = React.useRef(null)
  const tabRef = React.useRef(null)
  const backingRef = React.useRef(null)
  const handleRef = React.useRef(null)
  const iconRef = React.useRef(null)
  const draggableRef = React.useRef(null)
  const shadowRef = React.useRef(null)
  const proxyRef = React.useRef(document.createElement('div'))
  const [torn, setTorn] = React.useState(false)
  const audioRef = React.useRef(new Audio('/tear_open.mp3'))
  // Handle all the draggable stuff, etc.
  React.useEffect(() => {
    // Need to load the audio so I can get the duration
    const DISTANCE_OF_RESISTANCE = stripRef.current.offsetWidth * 0.25
    gsap.set(handleRef.current, {
      x: 0,
      y: 0,
    })
    // Create the Draggable instance which is where all the interactivity happens
    draggableRef.current = Draggable.create(proxyRef.current, {
      // NOTE:: Instances of "this" refer to the Draggable if you're new to Draggable
      type: 'x,y',
      trigger: handleRef.current,
      allowContextMenu: true,
      dragResistance: 0.99,
      // onDragStart: () => {
      //   audioRef.current.playbackRate = 0.1
      //   audioRef.current.play()
      // },
      onDrag: function (event) {
        // If you void the dragging by going up/down too much before tearing
        if (this.__void) return false
        // If the strip is torn, then you can move it around the page
        if (this.__torn) {
          return gsap.to(tabRef.current, {
            x: this.x - stripRef.current.offsetWidth * 2,
            y: this.y,
            duration: 0.1,
          })
        }
        // Void the drag if you go too high up or down
        const HANDLE_HEIGHT = handleRef.current.offsetHeight
        if (
          this.y < this.startY - HANDLE_HEIGHT * 0.5 ||
          this.y > this.startY + HANDLE_HEIGHT * 0.5
        ) {
          return (this.__void = true)
        }
        // Update the dragResistance as you tear.
        // TODO:: Would be ideal to have some resistance added again before the end.
        // But, it flakes out. Could be a GSAP bug :thinking:
        if (this.x > this.startX) {
          // Trick here is to clamp agains the current dragResistance. It can only go down.
          this.dragResistance = gsap.utils.clamp(
            0,
            this.dragResistance,
            gsap.utils.mapRange(0, DISTANCE_OF_RESISTANCE, 0.99, 0, this.x)
          )
        }
        if (!this.__torn) {
          // Map the clip of the strip based on the handle position
          const clip = gsap.utils.mapRange(
            0,
            stripRef.current.offsetWidth * 2,
            0,
            stripRef.current.offsetWidth,
            this.x
          )
          gsap.set(tabRef.current, {
            clipPath: `inset(-100% -1000% -100% ${clip}px)`,
          })
        }

        // Set custom props for use across the strip
        gsap.set(stripRef.current, {
          '--tab-darkness': gsap.utils.clamp(
            10,
            80,
            gsap.utils.mapRange(0, stripRef.current.offsetWidth, 10, 80, this.x)
          ),
          '--shadow-spread': gsap.utils.clamp(
            0,
            1,
            gsap.utils.mapRange(
              stripRef.current.offsetWidth * 0.25,
              stripRef.current.offsetWidth,
              0,
              1,
              this.x
            )
          ),
          '--shadow-reveal': gsap.utils.clamp(0, 1, gsap.utils.mapRange(stripRef.current.offsetWidth * 0.1, stripRef.current.offsetWidth * 0.2, 0, 1, this.x)),
          '--shadow-width': this.x * 0.5,
          '--bg-size': this.x * 0.5,
          '--shadow-multiplier': gsap.utils.clamp(
            0.8,
            0.9,
            gsap.utils.mapRange(
              stripRef.current.offsetWidth,
              stripRef.current.offsetWidth * 2,
              0.8,
              0.9,
              this.x
            )
          ),
        })

        // Move the icon
        gsap.set(iconRef.current, {
.........完整代码请登录后点击上方下载按钮下载查看

网友评论0