Vue自定義指令實現(xiàn)卡片翻轉(zhuǎn)功能
效果預(yù)覽

1 原理介紹
1.1 前置知識
backface-visibility
backface-visibility 是一個用于控制元素的背面是否可見的 CSS 屬性。該屬性通常用于在進(jìn)行 3D 轉(zhuǎn)換時,控制元素背面的可見性。
當(dāng)元素進(jìn)行 3D 轉(zhuǎn)換時,其背面可能會變得可見,backface-visibility 屬性就是用來控制這種可見性的。屬性有兩個可能的值:
visible:默認(rèn)值。背面可見。hidden:背面不可見,即不會顯示。
如果設(shè)置了 backface-visibility: hidden; 盒子背面將不可見,把盒子繞 y 軸進(jìn)行3d 旋轉(zhuǎn) 180° 后,我們將看到盒子的背面。
backface-visibility 主要用于處理 3D 轉(zhuǎn)換的情況,如果沒有使用 3D 轉(zhuǎn)換,該屬性的效果可能不會顯著。
transform-style: preserve-3d
transform-style: preserve-3d 主要用于配合 CSS 3D 變換,它告訴瀏覽器在進(jìn)行 3D 變換時應(yīng)該如何處理子元素。當(dāng)給父元素應(yīng)用 transform-style: preserve-3d 時,其子元素將以三維的方式定位,而不是被扁平化到同一個平面。
必須在父盒子上加上這個屬性,因為這里是父盒子翻轉(zhuǎn)帶動子盒子,如果不加上這個屬性,子盒子中的back背面將顯示不出來!
1.2 步驟分析
首先你需要一個大盒子,里面包含兩個小盒子,這里第一個小盒子為正面內(nèi)容,第二個小盒子為反面內(nèi)容。結(jié)構(gòu)如下:
<div class="card">
<div class="front">front</div>
<div class="back">back</div>
</div>
.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;
}
加上上面樣式后得到如下效果:

上面的效果顯然不滿足翻轉(zhuǎn)卡片的前置條件,思考一下我們想要達(dá)到的效果:
首先,正面和背面應(yīng)該疊在一起。
實現(xiàn):絕對定位。
疊在一起的初始狀態(tài)應(yīng)該只顯示正面,隱藏背面。
實現(xiàn):
默認(rèn)將正面css設(shè)置為:transform: rotateY(0deg); backface-visibility: hidden;
默認(rèn)將背面css設(shè)置為:transform: rotateY(180deg); backface-visibility: hidden;
這樣初始狀態(tài)下只顯示正面內(nèi)容,背面會自動隱藏。
翻轉(zhuǎn)后應(yīng)該顯示背面,隱藏正面。
實現(xiàn):將父盒子沿y軸翻轉(zhuǎn) 180度,這樣子盒子 front 會旋轉(zhuǎn)到背面去,從而隱藏。子盒子 back 會旋轉(zhuǎn)到正面,從而顯示。通過點擊父盒子 添加移除 flipped 類名,從而實現(xiàn)翻轉(zhuǎn)功能。
完整代碼如下:
<!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>卡片旋轉(zhuǎn)效果</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 自定義指令實現(xiàn)卡片翻轉(zhuǎn)
這里自定義指令的用法就不再介紹了,直接貼上實現(xiàn)代碼:
Vue.directive('flip', {
bind: function (el, binding) {
// console.log('bind', el.children.length, binding.value)
el.style.position = 'relative'
el.style.transformStyle = 'preserve-3d'
el.style.transition = 'transform 0.5s'
el.initChidren = (el, binding) => {
// console.log(el.children.length)
if (el.children.length !== 2) {
return
}
if (binding.value) {
el.style.transform = 'rotateY(180deg)'
} else {
el.style.transform = 'rotateY(0deg)'
}
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)'
}
}
}
el.initChidren(el, binding)
},
// inserted: function (el, binding) {
// console.log('inserted', el, binding.value)
// },
// update: function (el, binding) {
// console.log('update', el, binding)
// },
componentUpdated: function (el, binding) {
// console.log('componentUpdated', el, binding.value)
console.log(el.children.length)
// el.innerHTML 更新之后先重置子元素css屬性,再初始化
for (let i = 0; i < el.children.length; i++) {
const element = el.children[i]
element.style.backfaceVisibility = 'visible'
element.style.transform = 'rotateY(0deg)'
}
el.initChidren(el, binding)
},
// unbind(el) {
// 在解綁時移除事件
// },
})
組件中使用(注意 html 結(jié)構(gòu)必須如下):
<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>
以上就是Vue自定義指令實現(xiàn)卡片翻轉(zhuǎn)功能的詳細(xì)內(nèi)容,更多關(guān)于Vue實現(xiàn)卡片翻轉(zhuǎn)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue中Npm run build 根據(jù)環(huán)境傳遞參數(shù)方法來打包不同域名
這篇文章主要介紹了vue項目中Npm run build 根據(jù)環(huán)境傳遞參數(shù)方法來打包不同域名,使用npm run build --xxx,根據(jù)傳遞參數(shù)xxx來判定不同的環(huán)境,給出不同的域名配置,具體內(nèi)容詳情大家參考下本文2018-03-03
vue+iview框架實現(xiàn)左側(cè)動態(tài)菜單功能的示例代碼
這篇文章主要介紹了vue+iview框架實現(xiàn)左側(cè)動態(tài)菜單功能,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07
vue3 provide和inject底層組件的值不是響應(yīng)式的處理詳解
這篇文章主要為大家介紹了vue3 provide和inject底層組件的值不是響應(yīng)式的處理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
Vue數(shù)組響應(yīng)式操作及高階函數(shù)使用代碼詳解
這篇文章主要介紹了Vue數(shù)組響應(yīng)式操作及高階函數(shù)使用代碼詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-08-08

