Vue自定义指令实现卡片翻转功能

效果预览

1 原理介绍

1.1 前置知识

backface-visibility

backface-visibility 是一个用于控制元素的背面是否可见的 CSS 属性。该属性通常用于在进行 3D 转换时,控制元素背面的可见性。

当元素进行 3D 转换时,其背面可能会变得可见,backface-visibility 属性就是用来控制这种可见性的。属性有两个可能的值:

  1. visible:默认值。背面可见。
  2. hidden:背面不可见,即不会显示。

如果设置了 backface-visibility: hidden; 盒子背面将不可见,把盒子绕 y 轴进行3d 旋转 180° 后,我们将看到盒子的背面。

backface-visibility 主要用于处理 3D 转换的情况,如果没有使用 3D 转换,该属性的效果可能不会显著。

transform-style: preserve-3d

transform-style: preserve-3d 主要用于配合 CSS 3D 变换,它告诉浏览器在进行 3D 变换时应该如何处理子元素。当给父元素应用 transform-style: preserve-3d 时,其子元素将以三维的方式定位,而不是被扁平化到同一个平面。

必须在父盒子上加上这个属性,因为这里是父盒子翻转带动子盒子,如果不加上这个属性,子盒子中的back背面将显示不出来!

1.2 步骤分析

首先你需要一个大盒子,里面包含两个小盒子,这里第一个小盒子为正面内容,第二个小盒子为反面内容。结构如下:

html 复制代码
    <div class="card">
      <div class="front">front</div>
      <div class="back">back</div>
    </div>
css 复制代码
      .card {
        height: 270px;
        width: 270px;
        margin: 40px auto;
        border: 1px solid #f00;
        position: relative;
      }
      .front,.back {
        width: 100%;
        height: 100%;
      }

      .front {
        background-image: url(./imgs/youli.png);
        background-repeat: no-repeat;
        background-size: cover;
      }

      .back {
        background-image: url(./imgs/erha.jpg);
        background-repeat: no-repeat;
        background-size: cover;
      }

加上上面样式后得到如下效果:

上面的效果显然不满足翻转卡片的前置条件,思考一下我们想要达到的效果:

  1. 首先,正面和背面应该叠在一起。

    实现:绝对定位。

  2. 叠在一起的初始状态应该只显示正面,隐藏背面。

    实现:

    默认将正面css设置为:transform: rotateY(0deg); backface-visibility: hidden;

    默认将背面css设置为:transform: rotateY(180deg); backface-visibility: hidden;

    这样初始状态下只显示正面内容,背面会自动隐藏。

  3. 翻转后应该显示背面,隐藏正面。

    实现:将父盒子沿y轴翻转 180度,这样子盒子 front 会旋转到背面去,从而隐藏。子盒子 back 会旋转到正面,从而显示。通过点击父盒子 添加移除 flipped 类名,从而实现翻转功能。

完整代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>卡片旋转效果</title>
    <style>

      .card {
        height: 270px;
        width: 270px;
        margin: 40px auto;
        border: 1px solid #f00;
        position: relative;

        transform-style: preserve-3d;
        transition: transform 0.5s;
        perspective: 0px;
      }

      .card.flipped {
        transform: rotateY(180deg);
      }

      .front,.back {
        width: 100%;
        height: 100%;
        position: absolute;
        left: 0;
        top: 0;
      }

      .front {
        background-image: url(./imgs/youli.png);
        background-repeat: no-repeat;
        background-size: cover;

        backface-visibility: hidden;
        transform: rotateY(0deg);
      }

      .back {
        background-image: url(./imgs/erha.jpg);
        background-repeat: no-repeat;
        background-size: cover;

        transform: rotateY(180deg);
        backface-visibility: hidden;
      }
    </style>
  </head>
  <body>
    <div class="card">
      <div class="front">front</div>
      <div class="back">back</div>
    </div>

    <script>
      const card = document.querySelector('.card')
      card.addEventListener('click', function() {
        this.classList.toggle('flipped')
 
      })
    </script>
  </body>
</html>

2 用 Vue 自定义指令实现卡片翻转

这里自定义指令的用法就不再介绍了,直接贴上实现代码:

js 复制代码
Vue.directive('flip', {
  	bind: function (el, binding) {
        console.log('bind', el, binding.value)
        el.style.position = 'relative'
        el.style.transformStyle = 'preserve-3d'
        el.style.transition = 'transform 0.5s'

        for (let i = 0; i < el.children.length; i++) {
          const element = el.children[i]
          element.style.position = 'absolute'
          element.style.position = 'absolute'
          element.style.width = '100%'
          element.style.height = '100%'
          element.style.left = 0
          element.style.top = 0
          if (i === 0) {
            element.style.backfaceVisibility = 'hidden'
            element.style.transform = 'rotateY(0deg)'
          }
          if (i === 1) {
            element.style.backfaceVisibility = 'hidden'
            element.style.transform = 'rotateY(180deg)'
          }
        }
    },

    // inserted: function (el, binding) {
    //   console.log('inserted', el, binding.value)
    // },
    
    update: function (el, binding) {
        console.log('update', el, binding.value)
        if (binding.value) {
            el.style.transform = 'rotateY(180deg)'
        } else {
            el.style.transform = 'rotateY(0deg)'
        }
    },
    
    //componentUpdated: function (el, binding) {
        //console.log('componentUpdated', el, binding.value)
    //},

    // unbind(el) {
    // },
    
})

组件中使用(注意 html 结构必须如下):

js 复制代码
<template>
    <div class="flipped_card" v-flip="isFlipped" @click="handleFlippedClick">
        <div class="front">front</div>
        <div class="back">back</div>
    </div>
</template>
<script>
  data() {
    return {
      isFlipped: false,
    }
  },
  
  methods: {
    handleFlippedClick() {
      if (!this.isFlipped) {
        this.isFlipped = true
      } else {
        this.isFlipped = false
      }
    },
  }    
</script>
相关推荐
DT——2 小时前
Vite项目中eslint的简单配置
前端·javascript·代码规范
学习ing小白4 小时前
JavaWeb - 5 - 前端工程化
前端·elementui·vue
一只小阿乐4 小时前
前端web端项目运行的时候没有ip访问地址
vue.js·vue·vue3·web端
计算机学姐4 小时前
基于python+django+vue的旅游网站系统
开发语言·vue.js·python·mysql·django·旅游·web3.py
真的很上进4 小时前
【Git必看系列】—— Git巨好用的神器之git stash篇
java·前端·javascript·数据结构·git·react.js
胖虎哥er4 小时前
Html&Css 基础总结(基础好了才是最能打的)三
前端·css·html
qq_278063714 小时前
css scrollbar-width: none 隐藏默认滚动条
开发语言·前端·javascript
.ccl4 小时前
web开发 之 HTML、CSS、JavaScript、以及JavaScript的高级框架Vue(学习版2)
前端·javascript·vue.js
小徐不会写代码5 小时前
vue 实现tab菜单切换
前端·javascript·vue.js
2301_765347545 小时前
Vue3 Day7-全局组件、指令以及pinia
前端·javascript·vue.js