웹 프론트엔드 JS 튜토리얼 vue를 사용하여 슬라이딩 스택 구성 요소 만들기(자세한 튜토리얼)

vue를 사용하여 슬라이딩 스택 구성 요소 만들기(자세한 튜토리얼)

Jun 01, 2018 am 09:13 AM
만들다 스택 슬라이드

Tantan의 스택 슬라이딩 컴포넌트가 중요한 역할을 합니다. vue로 Tantan 스택 컴포넌트를 작성하는 방법을 살펴보겠습니다. 관심 있는 친구들은 함께 살펴보세요

렌더링은 다음과 같습니다.

머리말

안녕하세요, 탄탄이라면 프로그램에 익숙하실 겁니다. (결국 여자분들이 많죠.) 탄탄의 겹겹이 쌓인 슬라이딩 부품은 브랜드를 원활하게 뒤집는 데 중요한 역할을 합니다. .함수, vue를 사용하여 Tantan 스태킹 컴포넌트를 작성하는 방법을 살펴보겠습니다

1. 기능 분석

간단히 Tantan을 사용하면 스태킹 및 슬라이딩 기능이 매우 간단하다는 것을 알 수 있습니다. :

포함된 기본 기능에 대한 간략한 요약:

  • 사진 쌓기

  • 첫 번째 사진 슬라이딩

  • 조건 성공 후 슬라이딩하고 리바운드 조건이 실패한 후

  • 슬라이딩 아웃 후 다음 사진이 위에 쌓입니다

  • 경험 최적화

  • 서로 다른 터치 지점에 따라 슬라이딩 시 첫 번째 사진이 다른 각도로 오프셋됩니다

  • 오프셋 영역에 따라 슬라이딩 성공 여부가 결정됩니다. Out

2. 구체적인 구현

요약된 기능 포인트를 통해 구성요소 구현 아이디어가 더욱 명확해집니다

1.

인터넷에 쌓인 그림 효과가 많이 있습니다. 구현 방법은 주로 상위 레이어에 원근감과 원점을 설정하여 하위 레이어의 원근감을 설정하는 방식으로 유사합니다. 하위 레이어의 값은 스태킹 효과를 시뮬레이션할 수 있습니다. 구체적인 코드는 다음과 같습니다

// 图片堆叠dom
 <!--opacity: 0 隐藏我们不想看到的stack-item层级-->
 <!--z-index: -1 调整stack-item层级"-->
<ul class="stack">
 <li class="stack-item" style="transform: translate3d(0px, 0px, 0px);opacity: 1;z-index: 10;"><img src="1.png" alt="01"></li>
 <li class="stack-item" style="transform: translate3d(0px, 0px, -60px);opacity: 1;z-index: 1"><img src="2.png" alt="02"></li>
 <li class="stack-item" style="transform: translate3d(0px, 0px, -120px);opacity: 1;z-index: 1"><img src="3.png" alt="03"></li>
 <li class="stack-item" style="transform: translate3d(0px, 0px, -180px);opacity: 0;z-index: -1"><img src="4.png" alt="04"></li>
 <li class="stack-item" style="transform: translate3d(0px, 0px, -180px);opacity: 0;z-index: -1"><img src="5.png" alt="05"></li>
</ul>
<style>
.stack {
 width: 100%;
 height: 100%;
 position: relative;
 perspective: 1000px; //子元素视距
 perspective-origin: 50% 150%; //子元素透视位置
 -webkit-perspective: 1000px;
 -webkit-perspective-origin: 50% 150%;
 margin: 0;
 padding: 0;
 }
 .stack-item{
 background: #fff;
 height: 100%;
 width: 100%;
 border-radius: 4px;
 text-align: center;
 overflow: hidden;
 }
 .stack-item img {
 width: 100%;
 display: block;
 pointer-events: none;
 }
</style>
로그인 후 복사

위는 우리가 원하는 것은 vue 컴포넌트이므로 컴포넌트를 만들어야 합니다. template stack.vue 먼저 템플릿에서 v-for를 사용하여 스택 노드를 순회하고 :style을 사용하여 각 항목의 스타일을 수정할 수 있습니다. 코드는 다음과 같습니다

<template>
 <ul class="stack">
  <li class="stack-item" v-for="(item, index) in pages" :style="[transform(index)]">
  <img :src="item.src">
  </li>
 </ul>
</template>
<script>
export default {
 props: {
 // pages数据包含基础的图片数据
 pages: {
  type: Array,
  default: []
 }
 },
 data () {
 return {
  // basicdata数据包含组件基本数据
  basicdata: {
  currentPage: 0 // 默认首图的序列
  },
  // temporaryData数据包含组件临时数据
  temporaryData: {
  opacity: 1, // 记录opacity
  zIndex: 10, // 记录zIndex
  visible: 3 // 记录默认显示堆叠数visible
  }
 }
 },
 methods: {
 // 遍历样式
 transform (index) {
  if (index >= this.basicdata.currentPage) {
  let style = {}
  let visible = this.temporaryData.visible
  let perIndex = index - this.basicdata.currentPage
  // visible可见数量前滑块的样式
  if (index <= this.basicdata.currentPage + visible - 1) {
   style[&#39;opacity&#39;] = &#39;1&#39;
   style[&#39;transform&#39;] = &#39;translate3D(0,0,&#39; + -1 * perIndex * 60 + &#39;px&#39; + &#39;)&#39;
   style[&#39;zIndex&#39;] = visible - index + this.basicdata.currentPage
   style[&#39;transitionTimingFunction&#39;] = &#39;ease&#39;
   style[&#39;transitionDuration&#39;] = 300 + &#39;ms&#39;
  } else {
   style[&#39;zIndex&#39;] = &#39;-1&#39;
   style[&#39;transform&#39;] = &#39;translate3D(0,0,&#39; + -1 * visible * 60 + &#39;px&#39; + &#39;)&#39;
  }
  return style
  }
 }
 }
}
</script>
로그인 후 복사

핵심 사항

: 스타일은 객체뿐만 아니라 배열 및 함수도 바인딩할 수 있어 탐색할 때 매우 유용합니다.
가장 기본적인 돔 구조가 구축되었으며, 다음 단계는 첫 번째 그림을 "이동"시키는 것입니다

2. Sliding

그림 슬라이딩 효과는 터치 이벤트를 모니터링하고 변위를 얻은 다음 Translate3D를 통해 대상 변위를 변경하는 것이 원칙이므로 구현해야 하는 단계는 다음과 같습니다.

터치 이벤트를 스택에 바인딩
  • 동작 위치 변경 값을 모니터링하고 저장합니다.
  • 첫 번째 이미지의 CSS 속성에서 Translate3D의 x, y 값을 변경합니다
  • #### 구체적인 구현
vue 프레임워크에서는 노드를 직접 조작하는 것이 아니라 v-on 명령을 통해 요소를 바인딩하는 것을 권장하므로 모든 바인딩을 v-for에 작성합니다. 순회 중에 인덱스를 사용하여 해당 요소인지 확인합니다. 첫 번째 이미지를 사용한 후 :style을 사용하여 홈페이지 스타일을 수정합니다. 구체적인 코드는 다음과 같습니다.

<template>
 <ul class="stack">
  <li class="stack-item" v-for="(item, index) in pages"
  :style="[transformIndex(index),transform(index)]"
  @touchstart.stop.capture="touchstart"
  @touchmove.stop.capture="touchmove"
  @touchend.stop.capture="touchend"
  @mousedown.stop.capture="touchstart"
  @mouseup.stop.capture="touchend"
  @mousemove.stop.capture="touchmove">
  <img :src="item.src">
  </li>
 </ul>
</template>
<script>
export default {
 props: {
 // pages数据包含基础的图片数据
 pages: {
  type: Array,
  default: []
 }
 },
 data () {
 return {
  // basicdata数据包含组件基本数据
  basicdata: {
  start: {}, // 记录起始位置
  end: {}, // 记录终点位置
  currentPage: 0 // 默认首图的序列
  },
  // temporaryData数据包含组件临时数据
  temporaryData: {
  poswidth: &#39;&#39;, // 记录位移
  posheight: &#39;&#39;, // 记录位移
  tracking: false // 是否在滑动,防止多次操作,影响体验
  }
 }
 },
 methods: {
 touchstart (e) {
  if (this.temporaryData.tracking) {
  return
  }
  // 是否为touch
  if (e.type === &#39;touchstart&#39;) {
  if (e.touches.length > 1) {
   this.temporaryData.tracking = false
   return
  } else {
   // 记录起始位置
   this.basicdata.start.t = new Date().getTime()
   this.basicdata.start.x = e.targetTouches[0].clientX
   this.basicdata.start.y = e.targetTouches[0].clientY
   this.basicdata.end.x = e.targetTouches[0].clientX
   this.basicdata.end.y = e.targetTouches[0].clientY
  }
  // pc操作
  } else {
  this.basicdata.start.t = new Date().getTime()
  this.basicdata.start.x = e.clientX
  this.basicdata.start.y = e.clientY
  this.basicdata.end.x = e.clientX
  this.basicdata.end.y = e.clientY
  }
  this.temporaryData.tracking = true
 },
 touchmove (e) {
  // 记录滑动位置
  if (this.temporaryData.tracking && !this.temporaryData.animation) {
  if (e.type === &#39;touchmove&#39;) {
   this.basicdata.end.x = e.targetTouches[0].clientX
   this.basicdata.end.y = e.targetTouches[0].clientY
  } else {
   this.basicdata.end.x = e.clientX
   this.basicdata.end.y = e.clientY
  }
  // 计算滑动值
  this.temporaryData.poswidth = this.basicdata.end.x - this.basicdata.start.x
  this.temporaryData.posheight = this.basicdata.end.y - this.basicdata.start.y
  }
 },
 touchend (e) {
  this.temporaryData.tracking = false
  // 滑动结束,触发判断
 },
 // 非首页样式切换
 transform (index) {
  if (index > this.basicdata.currentPage) {
  let style = {}
  let visible = 3
  let perIndex = index - this.basicdata.currentPage
  // visible可见数量前滑块的样式
  if (index <= this.basicdata.currentPage + visible - 1) {
   style[&#39;opacity&#39;] = &#39;1&#39;
   style[&#39;transform&#39;] = &#39;translate3D(0,0,&#39; + -1 * perIndex * 60 + &#39;px&#39; + &#39;)&#39;
   style[&#39;zIndex&#39;] = visible - index + this.basicdata.currentPage
   style[&#39;transitionTimingFunction&#39;] = &#39;ease&#39;
   style[&#39;transitionDuration&#39;] = 300 + &#39;ms&#39;
  } else {
   style[&#39;zIndex&#39;] = &#39;-1&#39;
   style[&#39;transform&#39;] = &#39;translate3D(0,0,&#39; + -1 * visible * 60 + &#39;px&#39; + &#39;)&#39;
  }
  return style
  }
 },
 // 首页样式切换
 transformIndex (index) {
  // 处理3D效果
  if (index === this.basicdata.currentPage) {
  let style = {}
  style[&#39;transform&#39;] = &#39;translate3D(&#39; + this.temporaryData.poswidth + &#39;px&#39; + &#39;,&#39; + this.temporaryData.posheight + &#39;px&#39; + &#39;,0px)&#39;
  style[&#39;opacity&#39;] = 1
  style[&#39;zIndex&#39;] = 10
  return style
  }
 }
 }
}
</script>
로그인 후 복사

3. 조건이 성공하면 슬라이드 아웃되고, 조건이 실패하면 리바운드됩니다. 조건의 트리거 판단은 터치엔드/마우스업 이후에 수행됩니다. 여기서는 먼저 간단한 조건을 사용하여 판단하고 동시에 첫 번째 이미지 팝업 및 리바운드 효과를 제공합니다

<template>
 <ul class="stack">
  <li class="stack-item" v-for="(item, index) in pages"
  :style="[transformIndex(index),transform(index)]"
  @touchmove.stop.capture="touchmove"
  @touchstart.stop.capture="touchstart"
  @touchend.stop.capture="touchend"
  @mousedown.stop.capture="touchstart"
  @mouseup.stop.capture="touchend"
  @mousemove.stop.capture="touchmove">
  <img :src="item.src">
  </li>
 </ul>
</template>
<script>
export default {
 props: {
  // pages数据包含基础的图片数据
 pages: {
  type: Array,
  default: []
 }
 },
 data () {
 return {
  // basicdata数据包含组件基本数据
  basicdata: {
  start: {}, // 记录起始位置
  end: {}, // 记录终点位置
  currentPage: 0 // 默认首图的序列
  },
  // temporaryData数据包含组件临时数据
  temporaryData: {
  poswidth: &#39;&#39;, // 记录位移
  posheight: &#39;&#39;, // 记录位移
  tracking: false, // 是否在滑动,防止多次操作,影响体验
  animation: false, // 首图是否启用动画效果,默认为否
  opacity: 1 // 记录首图透明度
  }
 }
 },
 methods: {
 touchstart (e) {
  if (this.temporaryData.tracking) {
  return
  }
  // 是否为touch
  if (e.type === &#39;touchstart&#39;) {
  if (e.touches.length > 1) {
   this.temporaryData.tracking = false
   return
  } else {
   // 记录起始位置
   this.basicdata.start.t = new Date().getTime()
   this.basicdata.start.x = e.targetTouches[0].clientX
   this.basicdata.start.y = e.targetTouches[0].clientY
   this.basicdata.end.x = e.targetTouches[0].clientX
   this.basicdata.end.y = e.targetTouches[0].clientY
  }
  // pc操作
  } else {
  this.basicdata.start.t = new Date().getTime()
  this.basicdata.start.x = e.clientX
  this.basicdata.start.y = e.clientY
  this.basicdata.end.x = e.clientX
  this.basicdata.end.y = e.clientY
  }
  this.temporaryData.tracking = true
  this.temporaryData.animation = false
 },
 touchmove (e) {
  // 记录滑动位置
  if (this.temporaryData.tracking && !this.temporaryData.animation) {
  if (e.type === &#39;touchmove&#39;) {
   this.basicdata.end.x = e.targetTouches[0].clientX
   this.basicdata.end.y = e.targetTouches[0].clientY
  } else {
   this.basicdata.end.x = e.clientX
   this.basicdata.end.y = e.clientY
  }
  // 计算滑动值
  this.temporaryData.poswidth = this.basicdata.end.x - this.basicdata.start.x
  this.temporaryData.posheight = this.basicdata.end.y - this.basicdata.start.y
  }
 },
 touchend (e) {
  this.temporaryData.tracking = false
  this.temporaryData.animation = true
  // 滑动结束,触发判断
  // 简单判断滑动宽度超出100像素时触发滑出
  if (Math.abs(this.temporaryData.poswidth) >= 100) {
  // 最终位移简单设定为x轴200像素的偏移
  let ratio = Math.abs(this.temporaryData.posheight / this.temporaryData.poswidth)
  this.temporaryData.poswidth = this.temporaryData.poswidth >= 0 ? this.temporaryData.poswidth + 200 : this.temporaryData.poswidth - 200
  this.temporaryData.posheight = this.temporaryData.posheight >= 0 ? Math.abs(this.temporaryData.poswidth * ratio) : -Math.abs(this.temporaryData.poswidth * ratio)
  this.temporaryData.opacity = 0
  // 不满足条件则滑入
  } else {
  this.temporaryData.poswidth = 0
  this.temporaryData.posheight = 0
  }
 },
 // 非首页样式切换
 transform (index) {
  if (index > this.basicdata.currentPage) {
  let style = {}
  let visible = 3
  let perIndex = index - this.basicdata.currentPage
  // visible可见数量前滑块的样式
  if (index <= this.basicdata.currentPage + visible - 1) {
   style[&#39;opacity&#39;] = &#39;1&#39;
   style[&#39;transform&#39;] = &#39;translate3D(0,0,&#39; + -1 * perIndex * 60 + &#39;px&#39; + &#39;)&#39;
   style[&#39;zIndex&#39;] = visible - index + this.basicdata.currentPage
   style[&#39;transitionTimingFunction&#39;] = &#39;ease&#39;
   style[&#39;transitionDuration&#39;] = 300 + &#39;ms&#39;
  } else {
   style[&#39;zIndex&#39;] = &#39;-1&#39;
   style[&#39;transform&#39;] = &#39;translate3D(0,0,&#39; + -1 * visible * 60 + &#39;px&#39; + &#39;)&#39;
  }
  return style
  }
 },
 // 首页样式切换
 transformIndex (index) {
  // 处理3D效果
  if (index === this.basicdata.currentPage) {
  let style = {}
  style[&#39;transform&#39;] = &#39;translate3D(&#39; + this.temporaryData.poswidth + &#39;px&#39; + &#39;,&#39; + this.temporaryData.posheight + &#39;px&#39; + &#39;,0px)&#39;
  style[&#39;opacity&#39;] = this.temporaryData.opacity
  style[&#39;zIndex&#39;] = 10
  if (this.temporaryData.animation) {
   style[&#39;transitionTimingFunction&#39;] = &#39;ease&#39;
   style[&#39;transitionDuration&#39;] = 300 + &#39;ms&#39;
  }
  return style
  }
 }
 }
}
</script>
로그인 후 복사

4. 슬라이드 아웃 다음 그림을 맨 위로 쌓기

리스태킹은 컴포넌트의 마지막 기능이자 가장 중요하고 복잡한 기능이기도 합니다. 우리 코드에서 스택 항목의 정렬은 바인딩 스타일의 변형 함수와 변형에 따라 달라집니다. 함수에서 결정된 조건은 currentPage를 변경하고 재스택을 완료하려면 +1해야 합니까? ?

답은 그리 간단하지 않습니다. 슬라이드 아웃은 300ms 동안 지속되는 애니메이션 효과이고 currentPage 변경으로 인한 재배열이 즉시 변경되어 애니메이션 진행을 방해하기 때문입니다. 따라서 변환 함수의 정렬 조건을 먼저 수정한 후 currentPage를 변경해야 합니다. #### 특정 구현

변환 함수 정렬 조건 수정

    Let currentPage+1
  • onTransitionEnd 이벤트를 추가하고 슬라이드아웃이 끝나면 스택 목록에서 코드를 재배치합니다
  • 다음과 같습니다.


    <template>
     <ul class="stack">
      <li class="stack-item" v-for="(item, index) in pages"
      :style="[transformIndex(index),transform(index)]"
      @touchmove.stop.capture="touchmove"
      @touchstart.stop.capture="touchstart"
      @touchend.stop.capture="touchend"
      @mousedown.stop.capture="touchstart"
      @mouseup.stop.capture="touchend"
      @mousemove.stop.capture="touchmove"
      @webkit-transition-end="onTransitionEnd"
      @transitionend="onTransitionEnd"
      >
      <img :src="item.src">
      </li>
     </ul>
    </template>
    <script>
    export default {
     props: {
     // pages数据包含基础的图片数据
     pages: {
      type: Array,
      default: []
     }
     },
     data () {
     return {
      // basicdata数据包含组件基本数据
      basicdata: {
      start: {}, // 记录起始位置
      end: {}, // 记录终点位置
      currentPage: 0 // 默认首图的序列
      },
      // temporaryData数据包含组件临时数据
      temporaryData: {
      poswidth: &#39;&#39;, // 记录位移
      posheight: &#39;&#39;, // 记录位移
      lastPosWidth: &#39;&#39;, // 记录上次最终位移
      lastPosHeight: &#39;&#39;, // 记录上次最终位移
      tracking: false, // 是否在滑动,防止多次操作,影响体验
      animation: false, // 首图是否启用动画效果,默认为否
      opacity: 1, // 记录首图透明度
      swipe: false // onTransition判定条件
      }
     }
     },
     methods: {
     touchstart (e) {
      if (this.temporaryData.tracking) {
      return
      }
      // 是否为touch
      if (e.type === &#39;touchstart&#39;) {
      if (e.touches.length > 1) {
       this.temporaryData.tracking = false
       return
      } else {
       // 记录起始位置
       this.basicdata.start.t = new Date().getTime()
       this.basicdata.start.x = e.targetTouches[0].clientX
       this.basicdata.start.y = e.targetTouches[0].clientY
       this.basicdata.end.x = e.targetTouches[0].clientX
       this.basicdata.end.y = e.targetTouches[0].clientY
      }
      // pc操作
      } else {
      this.basicdata.start.t = new Date().getTime()
      this.basicdata.start.x = e.clientX
      this.basicdata.start.y = e.clientY
      this.basicdata.end.x = e.clientX
      this.basicdata.end.y = e.clientY
      }
      this.temporaryData.tracking = true
      this.temporaryData.animation = false
     },
     touchmove (e) {
      // 记录滑动位置
      if (this.temporaryData.tracking && !this.temporaryData.animation) {
      if (e.type === &#39;touchmove&#39;) {
       this.basicdata.end.x = e.targetTouches[0].clientX
       this.basicdata.end.y = e.targetTouches[0].clientY
      } else {
       this.basicdata.end.x = e.clientX
       this.basicdata.end.y = e.clientY
      }
      // 计算滑动值
      this.temporaryData.poswidth = this.basicdata.end.x - this.basicdata.start.x
      this.temporaryData.posheight = this.basicdata.end.y - this.basicdata.start.y
      }
     },
     touchend (e) {
      this.temporaryData.tracking = false
      this.temporaryData.animation = true
      // 滑动结束,触发判断
      // 简单判断滑动宽度超出100像素时触发滑出
      if (Math.abs(this.temporaryData.poswidth) >= 100) {
      // 最终位移简单设定为x轴200像素的偏移
      let ratio = Math.abs(this.temporaryData.posheight / this.temporaryData.poswidth)
      this.temporaryData.poswidth = this.temporaryData.poswidth >= 0 ? this.temporaryData.poswidth + 200 : this.temporaryData.poswidth - 200
      this.temporaryData.posheight = this.temporaryData.posheight >= 0 ? Math.abs(this.temporaryData.poswidth * ratio) : -Math.abs(this.temporaryData.poswidth * ratio)
      this.temporaryData.opacity = 0
      this.temporaryData.swipe = true
      // 记录最终滑动距离
      this.temporaryData.lastPosWidth = this.temporaryData.poswidth
      this.temporaryData.lastPosHeight = this.temporaryData.posheight
      // currentPage+1 引发排序变化
      this.basicdata.currentPage += 1
      // currentPage切换,整体dom进行变化,把第一层滑动置零
      this.$nextTick(() => {
       this.temporaryData.poswidth = 0
       this.temporaryData.posheight = 0
       this.temporaryData.opacity = 1
      })
      // 不满足条件则滑入
      } else {
      this.temporaryData.poswidth = 0
      this.temporaryData.posheight = 0
      this.temporaryData.swipe = false
      }
     },
     onTransitionEnd (index) {
      // dom发生变化后,正在执行的动画滑动序列已经变为上一层
      if (this.temporaryData.swipe && index === this.basicdata.currentPage - 1) {
      this.temporaryData.animation = true
      this.temporaryData.lastPosWidth = 0
      this.temporaryData.lastPosHeight = 0
      this.temporaryData.swipe = false
      }
     },
     // 非首页样式切换
     transform (index) {
      if (index > this.basicdata.currentPage) {
      let style = {}
      let visible = 3
      let perIndex = index - this.basicdata.currentPage
      // visible可见数量前滑块的样式
      if (index <= this.basicdata.currentPage + visible - 1) {
       style[&#39;opacity&#39;] = &#39;1&#39;
       style[&#39;transform&#39;] = &#39;translate3D(0,0,&#39; + -1 * perIndex * 60 + &#39;px&#39; + &#39;)&#39;
       style[&#39;zIndex&#39;] = visible - index + this.basicdata.currentPage
       style[&#39;transitionTimingFunction&#39;] = &#39;ease&#39;
       style[&#39;transitionDuration&#39;] = 300 + &#39;ms&#39;
      } else {
       style[&#39;zIndex&#39;] = &#39;-1&#39;
       style[&#39;transform&#39;] = &#39;translate3D(0,0,&#39; + -1 * visible * 60 + &#39;px&#39; + &#39;)&#39;
      }
      return style
      // 已滑动模块释放后
      } else if (index === this.basicdata.currentPage - 1) {
      let style = {}
      // 继续执行动画
      style[&#39;transform&#39;] = &#39;translate3D(&#39; + this.temporaryData.lastPosWidth + &#39;px&#39; + &#39;,&#39; + this.temporaryData.lastPosHeight + &#39;px&#39; + &#39;,0px)&#39;
      style[&#39;opacity&#39;] = &#39;0&#39;
      style[&#39;zIndex&#39;] = &#39;-1&#39;
      style[&#39;transitionTimingFunction&#39;] = &#39;ease&#39;
      style[&#39;transitionDuration&#39;] = 300 + &#39;ms&#39;
      return style
      }
     },
     // 首页样式切换
     transformIndex (index) {
      // 处理3D效果
      if (index === this.basicdata.currentPage) {
      let style = {}
      style[&#39;transform&#39;] = &#39;translate3D(&#39; + this.temporaryData.poswidth + &#39;px&#39; + &#39;,&#39; + this.temporaryData.posheight + &#39;px&#39; + &#39;,0px)&#39;
      style[&#39;opacity&#39;] = this.temporaryData.opacity
      style[&#39;zIndex&#39;] = 10
      if (this.temporaryData.animation) {
       style[&#39;transitionTimingFunction&#39;] = &#39;ease&#39;
       style[&#39;transitionDuration&#39;] = 300 + &#39;ms&#39;
      }
      return style
      }
     }
     }
    }
    </script>
    로그인 후 복사

    ok~ 위의 4단계를 완료하면 stacking 구성요소의 기본 기능이 구현되었습니다. 와서 효과를 확인하세요

    Stacking 슬라이딩 효과가 출시되었습니다. , 하지만 탄탄은 그것을 경험하고 있습니다. 거기에 터치 각도 오프셋과 슬라이드 아웃 면적 비율 결정도 추가됩니다

    각도 오프셋의 원리는 사용자가 터치할 때마다 사용자의 터치 위치를 기록하여 최대 오프셋 각도를 계산하고, 슬라이딩 변위가 발생하면 각도가 최대 오프셋 각도까지 선형적으로 증가하는 것입니다.

    스택을 사용할 때 특별히 해야 할 일은 다음과 같습니다.

    • touchmove에서 필요한 각도와 방향을 계산합니다

    • touchend와 onTransitionEnd를 사용하여 각도를 0으로 설정

    슬라이드 아웃을 결정 주로 면적 비율을 통해 오프셋을 사용하여 면적 비율을 구하고 판단을 완료합니다. 소스 코드는 여기에 게시되지 않습니다. 이 글이 마음에 드신다면 github에서 보실 수 있습니다. :star:️를 눌러주세요. 그리고 마지막으로 여러분 모두가 Tantan:green_heart:

    에서 전 여자친구를 찾으실 수 있기를 바랍니다. , 앞으로도 도움이 되길 바랍니다.

    관련 기사:

    Vue 프로젝트에서 프로젝트 구조를 초기화하기 위해 vue-cli 스캐폴딩을 사용하는 방법에 대한 자세한 설명

    vue에서 요청한 데이터의 특정 항목 값을 변경하는 방법

    JavaScript Starry Navigation Column 구현 방법


    위 내용은 vue를 사용하여 슬라이딩 스택 구성 요소 만들기(자세한 튜토리얼)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

PPT에서 필름 움직임 효과를 만드는 구체적인 방법 PPT에서 필름 움직임 효과를 만드는 구체적인 방법 Mar 26, 2024 pm 04:00 PM

1. PPT를 시작하고 새 빈 문서를 만든 다음 모든 텍스트 상자를 선택하고 삭제합니다. 2. Insert-Shape 명령을 실행하고 문서에서 직사각형을 드래그한 다음 도형을 검정색으로 채웁니다. 3. 직사각형을 드래그하여 늘린 다음, Insert-Shape 명령을 실행하고, 작은 정사각형을 드래그한 후 채우기 색상을 흰색으로 설정합니다. 4. 필름 양면에 상단과 하단이 고르게 분포되도록 작은 사각형을 하나씩 복사하여 붙여넣습니다. Ctrl+A로 모두 선택한 후 마우스 오른쪽 버튼을 클릭하고 그룹을 선택합니다. 5. 삽입-그림 명령을 실행하여 팝업 대화 상자에서 삽입할 그림을 찾아 클릭하여 열고 그림의 크기와 위치를 조정합니다. 6. 필름 사진을 만들기 위해 5단계를 반복하여 나머지 사진을 삽입하고 설정합니다. 7. 영화를 선택하고 애니메이션 추가 명령을 실행합니다.

토마토 소설 표지 만드는 법 토마토 소설 표지 만드는 법 Feb 23, 2024 pm 01:55 PM

토마토 소설 표지 만드는 법 토마토 소설에서만 단독 소설 표지를 만들 수 있는데, 대부분의 친구들은 토마토 소설 표지 만드는 법을 모릅니다. 다음은 에서 가져온 토마토 소설 표지 만드는 방법 사진입니다. 편집자가 플레이어에게 텍스트 튜토리얼을 전달합니다. 관심 있는 플레이어가 와서 살펴보세요! 토마토 소설 활용 튜토리얼 토마토 소설 표지 만드는 방법 1. 먼저 토마토 소설 APP을 열고 작품 관리 페이지에 들어가 새 책을 만든 후 아래 화살표와 같이 [표지 템플릿]을 선택합니다. 표지 템플릿 페이지에서 마음에 드는 표지 템플릿을 선택하세요. 3. 최종 표지 선택 후 오른쪽 상단의 [확인]을 클릭하세요.

모바일 엑셀 테이블 생성 조작 가이드 모바일 엑셀 테이블 생성 조작 가이드 Feb 18, 2024 pm 02:41 PM

모바일 엑셀 테이블 생성 튜토리얼 모바일 기기의 대중화와 기술의 지속적인 발전으로 인해 휴대폰은 일상생활과 업무에 없어서는 안 될 도구 중 하나가 되었습니다. 휴대폰에서 Excel 스프레드시트를 사용하면 데이터를 쉽게 기록, 계산, 분석할 수 있어 업무 효율성이 향상됩니다. 이 기사에서는 휴대폰에서 Excel 표를 만드는 기본 작업 및 기술을 공유합니다. 1. 적합한 애플리케이션을 선택하세요. GoogleSheets, Micro 등 선택할 수 있는 모바일 Excel 애플리케이션이 많이 있습니다.

휴대폰 화면이 미끄러지거나 건조해지면 어떻게 해야 하나요? 휴대폰 화면이 미끄러지거나 건조해지면 어떻게 해야 하나요? Dec 04, 2023 pm 03:51 PM

미끄러지거나 건조되기 어려운 휴대폰 화면에 대한 솔루션: 1. 화면을 정기적으로 청소합니다. 3. 손가락의 미끄러짐 강도를 높입니다. 4. 휴대폰 화면 보호 장치를 교체합니다. 6. 손을 촉촉하게 유지하십시오. 7. 필름을 붙일 때 깨끗하게 다루십시오. 8. 윤활제를 사용하십시오. 10. 화면 밝기를 조정하십시오. 자세한 소개: 1. 화면을 가습하고 화면 옆에 가습기를 두거나 물을 뿌려 공기 중 습도를 높여 화면의 건조함을 줄입니다. 2. 화면을 정기적으로 청소하고 전문 화면 세척제를 사용합니다.

CSS를 사용하여 카운트다운 효과를 만드는 방법 CSS를 사용하여 카운트다운 효과를 만드는 방법 Oct 26, 2023 am 10:36 AM

CSS를 사용하여 카운트다운 효과를 만드는 방법 카운트다운 효과는 사용자에게 카운트다운의 동적 효과를 제공하고 사람들에게 긴박감과 기대감을 줄 수 있습니다. 이 문서에서는 CSS를 사용하여 카운트다운 효과를 얻는 방법을 소개하고 자세한 구현 단계와 코드 예제를 제공합니다. 구현 단계는 다음과 같습니다. 1단계: HTML 구조 구성 먼저 HTML로 div 컨테이너를 만들어 카운트다운 콘텐츠를 래핑합니다. 예: &lt;divclass="countd

가르쳐 드릴게요! PPT로 애니메이션 효과를 만드는 방법! 가르쳐 드릴게요! PPT로 애니메이션 효과를 만드는 방법! Mar 20, 2024 pm 06:40 PM

PPT를 만들 때 애니메이션 효과를 사용하지 않는 것보다 애니메이션 효과를 사용하면 더 생동감 있고 귀엽게 보일 수 있습니다. 애니메이션 효과를 추가하면 사람들이 이 PPT를 보고 싶어할 수도 있으므로 PPT에 애니메이션 효과를 만드는 방법을 배워야 합니다. 다음으로는 PPT에 애니메이션 효과를 추가하는 방법을 자세히 소개하겠습니다. 계속해서 이 단계를 주의 깊게 읽고 연구해 보시기 바랍니다. 도움이 될 것입니다. 먼저 우리가 직접 만든 PPT를 열어보세요. 현재 이 PPT에는 애니메이션 효과가 없습니다(아래 그림의 빨간색 화살표 참조). 2. 그런 다음 사진에 애니메이션 효과를 추가해야 합니다. 먼저 사진을 선택한 다음 메뉴 바 상단의 [애니메이션] 버튼을 클릭합니다(아래 그림의 빨간색 원 참조). 3. 다음으로 애니메이션 내부를 클릭합니다.

단어 표지를 만드는 방법 단어 표지를 만드는 방법 Mar 19, 2024 pm 06:50 PM

졸업논문에는 표지, 목차, 끝 등이 있어야 논문이 완성됩니다. 지난 호에서는 편집자가 Word에서 목차를 만드는 방법을 친구들과 공유했습니다. 이번 호에서는 단어 표지를 만드는 방법을 알려 드리겠습니다. ! 1. 먼저 아래 그림과 같이 표지를 만들려는 워드 문서를 엽니다. 2. 그런 다음 메뉴 바에서 [Chapter] 버튼을 클릭하고 표지를 선택하는 기능과 동일합니다. 아래 그림의 빨간색 원 부분과 같이 적절하고 아름다운 표지를 직접 선택할 수 있는 표지 라이브러리: 3. 클릭하면 업종, 회사 계약에 적합한 표지, 서류; 이력서 유형, 취업 활동 및 이력서 제출에 적합 친구, 잠깐만요, 알았죠?

JavaScript를 사용하여 이미지의 위아래 슬라이딩 전환 효과를 얻고 페이드인 및 페이드아웃 애니메이션을 추가하는 방법은 무엇입니까? JavaScript를 사용하여 이미지의 위아래 슬라이딩 전환 효과를 얻고 페이드인 및 페이드아웃 애니메이션을 추가하는 방법은 무엇입니까? Oct 20, 2023 am 11:19 AM

JavaScript는 어떻게 이미지의 위아래 슬라이딩 전환 효과를 달성하고 페이드인 및 페이드아웃 애니메이션을 추가할 수 있습니까? 웹 개발에서는 이미지 전환 효과를 구현해야 하는 경우가 많습니다. JavaScript를 사용하여 위아래 슬라이딩 전환을 구현하고 페이드인 및 페이드아웃 애니메이션 효과를 추가할 수 있습니다. 먼저, 여러 이미지를 포함하는 컨테이너가 필요합니다. HTML에서 div 태그를 사용하여 이미지를 호스팅할 수 있습니다. 예를 들어, "image-container"라는 ID를 가진 div를 생성합니다.

See all articles