最近遇到一个需求, 要求项目中的轮播图随着屏幕大小,等比例缩放。实现思路是使用自定义指令去修改图片的宽度和高度。在细节处理上我们给图面设置了最大的宽高1350*450 按3:1的比例显示。图片无法覆盖到的区域使用背景色填充。
代码片段
图片的宽高徐亚修改,轮播图的容器高度也需要修改。否则高度小于450的时候图片会变形。我这是使用的页面较多, 所以在APP.vue页面去获取高度并传递给子页面进行修改, 使用provide和inject来实现
app.vue文件
provide(){ 、
return {
bannerHeight: ()=> ({
height:this.swiperHeight
})
}
},
data(){
return {
swiperHeight:450
}
},
mounted(){
const that = this
window.addEventListener('resize', function() {
that.setHeight();
}, false);
},
methods:{
setHeight(){
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
this.swiperHeight = width >= 1350 ? 450: ((width - 140) / 1350) * 450
}
},
destroyed(){
const that = this
window.removeEventListener('resize', function() {
that.setHeight();
}, false);
}
使用页面html部分
<el-carousel :height="`${actHeight}px`">
<el-carousel-item v-imgScale v-for="(item, index) in swiperList" :key="index" :style="{ backgroundColor: `#${item.bgColor}` }">
<img :src="item.imageUrl" alt="" @click="skipNews(item)">
</el-carousel-item>
</el-carousel>
js部分
// 引入 自定义组件
import { imgScale } from '@/utils/directives'
export default {
inject:['bannerHeight'],
directives: {
imgScale
},
computed: {
actHeight() {
return this.bannerHeight().height;
},
},
}
自定义指令
/**
* @params cover | 修饰符,缩放类型:cover表示缩放至铺满父元素并居中,contain表示图片缩放至能在父元素看到图片所有内容并居中
* @params stop | 修饰符,默认是false,有stop: true修饰符代表不处理图片
* @params options :{
* imgWidth : Number | 图片的宽度width,单位px
* imgHeight :Number | 图片的高度height,单位px
* panelWidth :Number | 图片容器的宽度,单位px
* panelHeight :Number | 图片容器的高度,单位px
* scale :Boolean | 默认是true ,是否缩放
* resizeType :String | 缩放类型:contain | cover
* unit: String | 宽高的单位,默认‘px’
* }
*/
export const imgScale = {
inserted(el, binding, vnode) {
let isJson = (obj) => {
return typeof obj === 'object' && Object.prototype.toString.call(obj) == "[object Object]"
}
let imgScale = (options) => {
let defaults = {
imgWidth: el.width|| 1350,
imgHeight: el.height || 450,
panelWidth: el?.parentNode?.offsetWidth,
panelHeight: el?.parentNode?.offsetHeight ,
scale: !binding?.modifiers?.stop,
resizeType: binding?.modifiers?.contain ? "contain" : "cover",
unit: 'px'
}
options = isJson(options) ? options : {}
options = Object.assign({}, defaults, options || {})
if (options.scale) {
if (options.imgWidth > 0 && options.imgHeight > 0) {
// el.parentNode.style.width = options.panelWidth + options.unit
// el.parentNode.style.maxHeight = options.panelHeight + options.unit
switch (options.resizeType) {
case "cover":
// 默认 cover 方式,处理后的宽或高超过容器的宽高,用margin负值使之上下或左右居中
// 如果图片比容器扁
if (options.imgWidth / options.imgHeight >= options.panelWidth / options.panelHeight) {
let toWidth = options.imgWidth * (options.panelHeight / options.imgHeight)
el.style.width = toWidth > 1350?1350:toWidth + options.unit
el.style.height = options.panelHeight> 450?450:options.panelHeight + options.unit//等比缩放,保持清晰度
}
// 如果图片比容器瘦
else {
let toHeight = options.imgHeight * (options.panelWidth / options.imgWidth)
el.style.width = options.panelWidth > 1350?1350:options.panelWidth + options.unit
el.style.height = toHeight > 450?450:toHeight + options.unit//等比缩放,保持清晰度
}
break
case "contain":
// contain方式,处理后的宽或高不足容器的宽高,用margin正值使之上下或左右居中
if (options.imgWidth / options.imgHeight >= options.panelWidth / options.panelHeight) {
let toHeight = (options.imgHeight * (options.panelWidth / options.imgWidth))
el.style.width = options.panelWidth > 1350?1350:options.panelWidth + options.unit
el.style.height = toHeight > 450?450:toHeight + options.unit
} else {
let toWidth = options.imgWidth * (options.panelHeight / options.imgHeight)
el.style.width = toWidth > 1350?1350:toWidth + options.unit
el.style.height = options.panelHeight> 450?450:options.panelHeight + options.unit
}
break
}
}
}
}
//已经加载过了
if (el.complete && el.width > 0) {
imgScale(binding.value)
return
}
//没加载过则监听load事件
el.addEventListener("load", () => {
imgScale(binding.value)
}, false)
}
}