Skip to content

立體包裝器 wrapper

可以讓元素有酷酷的 3D 偏轉效果。ˋ( ° ▽、° )

使用範例

基本用法

可以隨手關閉,不過沒辦法省電。乁( ◔ ௰◔)「

安安
漂起來惹
酷酷的漂浮
安安
查看範例原始碼
vue
<template>
  <div class="w-full flex flex-col gap-4 border border-gray-300 p-6">
    <div class="flex gap-4 border rounded p-4">
      <base-checkbox
        v-model="enable"
        label="懸浮開關"
        class="w-full"
      />
    </div>

    <div class="flex flex-col items-start gap-4">
      <wrapper-stereoscopic :enable="enable">
        <div class="h-80 w-80 flex-center rounded bg-gray-300">
          <div class="h-40 w-40 flex-center rounded bg-gray-100">
            <div class="text-xl text-gray-600 font-bold">
              安安
            </div>
          </div>
        </div>
      </wrapper-stereoscopic>

      <div class="flex flex-col items-start justify-start gap-4">
        <wrapper-stereoscopic :enable="enable">
          <div class="border rounded-full p-4 text-xl text-gray-600 font-bold">
            漂起來惹
          </div>
        </wrapper-stereoscopic>

        <wrapper-stereoscopic :enable="enable">
          <div class="border rounded-full p-4 text-xl text-gray-600 font-bold">
            酷酷的漂浮
          </div>
        </wrapper-stereoscopic>

        <wrapper-stereoscopic :enable="enable">
          <div class="border rounded-full p-4 text-xl text-gray-600 font-bold">
            安安
          </div>
        </wrapper-stereoscopic>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

import BaseCheckbox from '../../base-checkbox.vue'
import WrapperStereoscopic from '../wrapper-stereoscopic.vue'

const enable = ref(true)
</script>

<style lang="sass" scoped>
.flex-center
  display: flex
  justify-content: center
  align-items: center
</style>

多層視差

多層 layer 可以產生多層立體效果

安安
查看範例原始碼
vue
<template>
  <div class="w-full flex flex-col gap-4 border border-gray-300 p-6">
    <div class="content flex items-start gap-4">
      <wrapper-stereoscopic v-slot="wrapper">
        <div
          class="h-80 w-80 flex-center rounded bg-gray-300"
          :style="wrapper.style"
        >
          <wrapper-stereoscopic-layer v-slot="layer01">
            <div
              class="h-40 w-40 flex-center rounded bg-gray-200"
              :style="layer01.style"
            >
              <wrapper-stereoscopic-layer v-slot="layer02">
                <div
                  class="rounded bg-gray-100 p-4 text-xl font-bold"
                  :style="layer02.style"
                >
                  安安
                </div>
              </wrapper-stereoscopic-layer>
            </div>
          </wrapper-stereoscopic-layer>
        </div>
      </wrapper-stereoscopic>
    </div>
  </div>
</template>

<script setup lang="ts">
import WrapperStereoscopic from '../wrapper-stereoscopic.vue'
import WrapperStereoscopicLayer from '../wrapper-stereoscopic-layer.vue'
</script>

<style lang="sass" scoped>
.content
  perspective: 2000px
.flex-center
  display: flex
  justify-content: center
  align-items: center
</style>

最大偏轉角

可以設定最大偏轉角度

( •̀ ω •́ )✧
查看範例原始碼
vue
<template>
  <div class="w-full flex flex-col gap-4 border border-gray-300 p-6">
    <div class="flex gap-4 border rounded p-4">
      <base-input
        v-model="x"
        type="range"
        :label="`X 最大角度: ${x} 度`"
        class="w-full"
        :min="0"
        :max="90"
      />

      <base-input
        v-model="y"
        type="range"
        :label="`Y 軸最大角度: ${y} 度`"
        class="w-full"
        :min="0"
        :max="90"
      />
    </div>

    <div class="content flex items-start gap-4">
      <wrapper-stereoscopic
        :x-max-angle="x"
        :y-max-angle="y"
      >
        <div class="border rounded-full p-4 text-xl text-gray-600 font-bold">
          ( •̀ ω •́ )✧
        </div>
      </wrapper-stereoscopic>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

import BaseInput from '../../base-input.vue'
import WrapperStereoscopic from '../wrapper-stereoscopic.vue'

const x = ref(15)
const y = ref(15)
</script>

<style lang="sass" scoped>
.content
  perspective: 2000px
.flex-center
  display: flex
  justify-content: center
  align-items: center
</style>

漂浮距離

可以設定每層之間的漂浮距離,想躺平就躺平。_(:3」ㄥ)_

安安
查看範例原始碼
vue
<template>
  <div class="w-full flex flex-col gap-4 border border-gray-300 p-6">
    <div class="flex gap-4 border rounded p-4">
      <base-input
        v-model="zOffset"
        type="range"
        :label="`懸浮距離: ${zOffset} px`"
        class="w-full"
        :min="0"
        :max="200"
      />
    </div>

    <div class="content flex items-start gap-4">
      <wrapper-stereoscopic
        v-slot="wrapper"
        :z-offset="zOffset"
      >
        <div
          class="h-80 w-80 flex-center rounded bg-gray-300"
          :style="wrapper.style"
        >
          <wrapper-stereoscopic-layer v-slot="layer01">
            <div
              class="h-40 w-40 flex-center rounded bg-gray-200"
              :style="layer01.style"
            >
              <wrapper-stereoscopic-layer v-slot="layer02">
                <div
                  class="rounded bg-gray-100 p-4 text-xl font-bold"
                  :style="layer02.style"
                >
                  安安
                </div>
              </wrapper-stereoscopic-layer>
            </div>
          </wrapper-stereoscopic-layer>
        </div>
      </wrapper-stereoscopic>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

import BaseInput from '../../base-input.vue'
import WrapperStereoscopic from '../wrapper-stereoscopic.vue'
import WrapperStereoscopicLayer from '../wrapper-stereoscopic-layer.vue'

const zOffset = ref(100)
</script>

<style lang="sass" scoped>
.content
  perspective: 2000px
.flex-center
  display: flex
  justify-content: center
  align-items: center
</style>

原理

利用 CSS 的 perspective 與 transform3d,產生 3D 旋轉與透視變形效果。

其中 perspective 尤為重要,此屬性負責讓物體產生透視變形效果。

沒設定的話,物體看起來像莫名其妙扁掉。...('◉◞⊖◟◉` )

📚 CSS perspective

📚 CSS translate3d

知道如何偏轉後,剩下的部分就簡單惹。( •̀ ω •́ )✧

計算從物體中心到滑鼠位置的向量,分別將向量的 x、y 分量映射到設定的角度範圍,最後套用到 transform 上即可。

不過這裡有個小技巧,我們不把「目前角度」直接設為「目標角度」,而是逐漸趨近「目標角度」。

這樣無論「目標角度」怎麼亂跳,都可以保證偏轉效果都有動畫呈現,看起來更自然、舒服。◝(≧∀≦)◟

原始碼

API

Props

interface Props {
  /** 是否開啟 */
  enable?: boolean;
  /** x 最大偏轉角度 */
  xMaxAngle?: number;
  /** y 最大偏轉角度 */
  yMaxAngle?: number;
  /** 懸浮高度 */
  zOffset?: number;
}

v0.23.1