react模仿iphone14灵动岛ui交互设计效果代码

代码语言:html

所属分类:布局界面

代码描述:react模仿iphone14灵动岛ui交互设计效果代码,包含消息提示、视频小窗播放、电池余量提醒、loading加载动画等。

代码标签: react 模仿 iphone14 灵动岛 ui 交互 设计

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


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

<head>

  <meta charset="UTF-8">
  

  
  
<style>
@import 'https://unpkg.com/open-props/open-props.min.css';
@import 'https://unpkg.com/open-props/normalize.min.css';

main {
  display: grid;
  place-items: center;
  min-height: 100vh;
  background: var(--gradient-11);
}
button {
  padding: var(--size-2) var(--size-4);
  border-radius: var(--radius-3);
}

.dynamic-island {
  --height: 36px;
  --font-size: calc(var(--height) * 0.35);
  --camera-size: calc(3.6 * var(--height));
  position: fixed;
  top: var(--size-4);
  left: 50%;
  transform: translateX(-50%);
  /*min-width: var(--size-10);*/
  min-height: var(--height);
  transition: all 0.2s ease;
  display: inline-flex;
  /*gap: var(--size-4);*/
  justify-content: center;
  align-items: center;
  font-size: var(--font-size-1);
  font-size: var(--font-size);
  color: var(--gray-0);
  /*background: grey;*/
  /*opacity: 0.5;*/
  display: grid;
  align-items: center;
  grid-template-columns: var(--auxiliary-width, 1fr) var(--camera-size) var(--auxiliary-width, 1fr);
  grid-template-rows: var(--height) 1fr;
}
@media(min-width: 768px) {
  .dynamic-island { --height: 50px; }
}

.dynamic-island:after {
  content: "";
  min-height: var(--height);
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, 0) scaleX(var(--scale-x, 1));
  border-radius: calc(var(--font-size) + var(--size-2));
  min-width: var(--camera-size);
  width: calc(var(--width-imposed, 40) * 1px);
  height: calc(var(--height-imposed, 40) * 1px);
  background: var(--gray-9);
  transition: width 0.2s var(--ease-elastic-2), height 0.2s var(--ease-elastic-2);
  z-index: -1;
  /*opacity: 0.8;*/
}

.dynamic-island__media {
  display: flex;
  -webkit-animation: enter-media 0.2s 0.1s both;
          animation: enter-media 0.2s 0.1s both;
  white-space: nowrap;
}

.dynamic-island__stage--camera {
  width: var(--camera-size);
  display: flex;
  justify-content: flex-end;
  padding-right: var(--size-4);
}

.dynamic-island__lens {
  height: calc(var(--height) * 0.5);
  opacity: 0.5;
  aspect-ratio: 1;
}

.dynamic-island__stage--center {
  grid-column: 1 / -1;
  display: grid;
  place-items: center;
  width: 100%;
  max-width: 100%;
  overflow: hidden;
}

#player {
  max-width: 100%;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
}

.dynamic-island__center {
  padding: var(--size-4);
  -webkit-animation: enter-info 0.2s 0.1s both;
          animation: enter-info 0.2s 0.1s both;
  width: 100%;
}

.dynamic-island__info {
  padding-left: var(--size-4);
  white-space: nowrap;
  -webkit-animation: enter-info 0.2s 0.1s both;
          animation: enter-info 0.2s 0.1s both;
}

.dynamic-island__media {
  padding-right: var(--size-4);
  display: flex;
  justify-content: flex-end;
}

@-webkit-keyframes enter-info {
  from {
    opacity: 0;
  }
}

@keyframes enter-info {
  from {
    opacity: 0;
  }
}

@-webkit-keyframes enter-media {
  from {
    transform: scale(0);
  }
}

@keyframes enter-media {
  from {
    transform: scale(0);
  }
}

.template {
  display: none;
  position: fixed;
  opacity: 0.2;
  transform: translate(0, -19%);
}

.battery {
  display: flex;
}

.globe {
  display: inline-block;
  position: relative;
}

.globes {
  position: relative;
  overflow: hidden;
  -webkit-clip-path: inset(0 0 0 0);
          clip-path: inset(0 0 0 0);
}

.battery__icon--lightning {
  display: inline-block;
  -webkit-animation: lightning 1s infinite;
          animation: lightning 1s infinite;
}

@-webkit-keyframes lightning {
  0%, 10%, 20% {
    transform:  skew(15deg);
  }
  5%, 15%, 25% {
    transform:  skew(-15deg);
  }
  30%, 100% {
    transform:  skew(0deg);
  }
}

@keyframes lightning {
  0%, 10%, 20% {
    transform:  skew(15deg);
  }
  5%, 15%, 25% {
    transform:  skew(-15deg);
  }
  30%, 100% {
    transform:  skew(0deg);
  }
}

.globes__placeholder {
  color: transparent;
}

.loader {
  height: calc(var(--height) * 0.6);
  aspect-ratio: 1;
  position: relative;
  display: grid;
  place-items: center;
  -webkit-animation: load 1s infinite steps(var(--count));
          animation: load 1s infinite steps(var(--count));
}

@-webkit-keyframes load {
  to {
    transform: rotate(360deg);
  }
}

@keyframes load {
  to {
    transform: rotate(360deg);
  }
}

.loader > span {
  width: 25%;
  height: 10%;
  background: white;
  position: absolute;
  transform: rotate(calc((360 / var(--count)) * var(--index) * 1deg)) translateX(150%);
  opacity: calc(1 / var(--count) * var(--index));
}

.globes__translater {
  position: absolute;
  top: 50%;
  left: 0;
  display: inline-block;
  transform: translate(0, -50%);
  white-space: nowrap;
  -webkit-animation: globe-spin 0.5s infinite both steps(3);
          animation: globe-spin 0.5s infinite both steps(3);
}

@-webkit-keyframes globe-spin {
  to {
    transform: translate(-100%, -50%);
  }
}

@keyframes globe-spin {
  to {
    transform: translate(-100%, -50%);
  }
}
</style>


</head>

<body >
  <div id="app"></div>
<main>
	<div class="controls">
		<button class="hello">Hello</button>
		<button class="charge">Battery</button>
		<button class="loading">Loading</button>
		<button class="youtube">Media</button>
	</div>
</main>

<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/react.production.16.13.js"></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/react-dom.production.16.13.js"></script>
      <script type="text/babel">



const ROOT = document.getElementById('app')

const DynamicIsland = () => {
  const timerRef = React.useRef(null)
  const islandRef = React.useRef(null)
  const mediaRef = React.useRef(null)
  const infoRef = React.useRef(null)
  const centerRef = React.useRef(null)
  const scaleRef = React.useRef(null)
  const cbRef = React.useRef(null)
  const [info, setInfo]   = React.useState(null)
  const [media, setMedia] = React.useState(null)
  const [box, setBox] = React.useState(null)
  
  React.useEffect(() => {
    const winddown = () => {
      const anims = []
      
      if (mediaRef.current)
        anims.push(mediaRef.current.animate({
          scale: 0
        }, {
          duration: 200,
          fill: 'forwards'
        }).finished)
      if (infoRef.current)
        anims.push(infoRef.current.animate({
          opacity: 0,
        }, {
          duration: 200,
          fill: 'forwards'
        }).finished)
      if (centerRef.current)
        anims.push(centerRef.current.animate({
          opacity: 0,
        }, {
          duration: 200,
          fill: 'forwards'
        }).finished)
      if (anims.length) {
        Promise.all(anims).then(() => {
          setInfo(null)
          setMedia(null)
          setBox(null)
        })
      }
    }
    const processIsland = ({ detail: { box, info, media, timeout, cb, nuke } }) => {
      if (nuke) return winddown()
      
      setInfo(info)
      setMedia(media)
      setBox(box)
      cbRef.current = cb

      if (timeout) {
        if (timerRef.current) clearTimeout(timerRef.current)
        timerRef.current = setTimeout(winddown, timeout)
      }
    }
    document.body.addEventListener('island:event', processIsland)
 .........完整代码请登录后点击上方下载按钮下载查看

网友评论0