現(xiàn)實問題
我們在寫Vue組件時想诅,我們希望當組件的父級寬度一定時纪吮,組件能根據(jù)固定的寬高比例進行自適應狡赐,或者一些背景的自適應腐螟,以提高組件的復用性愿汰。
實現(xiàn)思路
- 在當前組件最外層元素設置ref。
- 組件Props中傳入?yún)?shù)width(當傳入值為100% 父級組件存在寬度時乐纸,高度即是自適應衬廷。),并通過一個computed變量和v-bind方法綁定至最外層元素CSS的width中汽绢。
- 在組件的onMounted生命周期中通過ref獲取當前組件的clientWidth(此生命周期中吗跋,組件已渲染完畢)。再通過ref去修改style中的height達到一個寬高比固定的自適應。
- Vue2無法使用v-bind綁定CSS變量跌宛,但是可通過一個computed計算出樣式和 :style綁定樣式中酗宋。
Vue3 + TS 實現(xiàn)代碼
此樣例中的background也是通過傳入的兩個變量計算漸變獲得。
組件代碼如下:
<template>
<!-- ref綁定 -->
<div ref="card" class="card-container">
</div>
</template>
<style lang="scss" scoped>
.card-container {
width: v-bind(width); // 綁定width
border-radius: 8px;
background: v-bind(background); // 綁定background
}
</style>
<script lang="ts" setup>
import { ref, onMounted, Ref, computed } from 'vue';
const props = defineProps({
// 傳入高度
width: {
type: String,
default: '200px'
},
// 背景漸變開始的顏色
beginColor: {
type: String,
default: '#4996FF'
},
// 背景漸變結束的顏色疆拘,用于linear-gradient
endColor: {
type: String,
default: '#358CFF'
}
})
// 綁定HTML元素
const card: Ref<null> | Ref<HTMLElement> = ref(null);
// computed綁定傳入寬度
const width = computed(() => {
return props.width;
})
// computed 計算背景
const background = computed(() => {
return `linear-gradient(104.37deg,${props.beginColor} 4.7%, ${props.endColor} 100%)`;
})
onMounted(() => {
if(!card.value ) return
// 獲取渲染完成的元素寬度
const nowWidth = (card as Ref<HTMLElement>).value.clientWidth;
// 更改元素高度蜕猫,此處比例 16 : 9
(card as Ref<HTMLElement>).value.style.height = `${nowWidth / 16 * 9}px`;
})
</script>
代碼效果
測試代碼:
<template>
<div class="width-fit-cards">
<div v-for="(item,index) in 4" :style="{width: `${(index + 1) * 100}px`}" class="width-card" >
<width-fit-card width="100%"/>
</div>
</div>
</template>
<style lang="scss" scoped>
.width-fit-cards {
display: flex;
.width-card + .width-card {
margin-left: 20px;
}
}
</style>
<script lang="ts" setup>
// 引入組件
import widthFitCard from './widthFitCard.vue';
</script>
測試效果
Vue2
Vue2通過以下代碼綁定CSS樣式:
computed: {
getCardStyle() {
return {
width: this.width
}
}
}
<div :style="getCardStyle" ref="card" class="card-container">
</div>
具體可以自行實現(xiàn)