0、废话部分可以不看
在用uniapp开发小程序过程中,想写一个某红薯详情页面的轮播图,开始用来uview3的swiper组件,非常简洁。但是,存在图片显示不完全或者很小,或者又不能很美观。因为什么呢?
主要是图片原尺寸基本上都是9:16或者16:9的比例,想要按比例将图片显示完整,尽可能效果好点试了很多方式,都不能很好的按照图片高度动态一个最大值设置为swiper高度。总有显示不完整的情况。就很丑。记得当时这个height属性弄得我很麻烦。看官方图
二、最终方案:uniapp的swiper
直接上代码:
1、详情 detail.vue 页面:
:style="{height: swiperHeight + 'px'}" //该属性用来动态绑定计算后的swiper高度
其他属性参考官方:https://uniapp.dcloud.net.cn/component/swiper.html
mode="widthFix"是图片的裁剪方式
定义看官方:https://uniapp.dcloud.net.cn/component/image.html
<template>
<view class="container">
<swiper class="swiper-box" :style="{height: swiperHeight + 'px'}" :indicator-dots="indicatorDots"
:autoplay="autoplay" :interval="interval" :duration="duration">
<swiper-item class="swiper-item" v-for="(item, index) in swiperItem" :key="index">
<image class="image" :src="item.image" mode="widthFix" @load="onImageLoad($event, item)" />
</swiper-item>
</swiper>
</view>
</template>
<script>
import { mapState } from 'vuex';
export default {
// name: 'DetailPage',
computed: {
...mapState(['list', 'swiperItem']),
indicatorDots() {
return true;
},
autoplay() {
return true;
},
interval() {
return 3000;
},
duration() {
return 500;
},
},
data() {
return {
imagesInfo: [], // 存储所有图片尺寸信息的数组
portraitImages: [], // 存储竖屏图片信息的数组
imagesLoadedCount: 0, // 已加载图片的数量
swiperHeight: 0, // 计算后的最高竖屏图片的高度
};
},
methods: {
onImageLoad(event, item) {
const detail = event.detail;
const { width, height } = detail;
const entry = {
url: item.image,
width,
height,
aspectRatio: height / width,
};
this.imagesInfo.push(entry);
// 检查是否为竖屏比例
if (entry.aspectRatio > 1) {
this.portraitImages.push(entry);
}
console.log('高宽:', entry.height, entry.width);
this.imagesLoadedCount++;
if (this.imagesLoadedCount === this.list.length) {
this.calculateAveragePortraitHeight();
}
},
calculateAveragePortraitHeight() {
if (this.portraitImages.length === 0) {
console.warn('没有竖屏图片');
return;
}
const totalHeight = this.portraitImages.reduce((sum, image) => sum + image.height, 0);
const averageHeight = totalHeight / this.portraitImages.length;
const {
windowWidth
} = uni.getSystemInfoSync(); // 这里可能需要改为异步调用
console.log("屏幕宽度:", windowWidth); // 输出屏幕宽度
this.swiperHeight = Math.round((averageHeight * windowWidth) / this.portraitImages[0].width);
console.log("计算后swiper高度:", this.swiperHeight); // 计算后swiper高度
},
},
mounted() {
// 在这里可以监听窗口大小变化等操作
},
beforeDestroy() {
// 清除标记
}
};
</script>
<style>
.container {
width: 100%;
position: relative;
}
.swiper {
width: 100%;
height: 500px; /* 使用计算属性 */
}
.image {
width: 100%;
height: auto;
}
</style>
...mapState(['list']),//这是导入store中的list数组。只有list一个数组用这句就行。
...mapState(['list','swiperItem']),//这是导入store中的list数组,和swiperItem。
大致实现逻辑思路
method里面的内容,大致逻辑是:
加载数组图片,并将图片的宽高信息储存,判断是不是竖屏的图片类型。
是,将其图片高度储存在一个新数组。
找出竖屏图片数组中高度最高的图片的宽高,用于计算是swiper的最终高度,使其能够以最大高度显示完整图片,比起尺寸小的图片也能显示完整。
计算逻辑:
这里swiper可以理解为屏幕,即屏幕宽高。
swiper高度 swiper宽度
—————— = ———————
原图高度 原图宽度
swiper宽度 *原图高度
swiper高度 = ———————
原图宽度
const {windowWidth} = uni.getSystemInfoSync();
console.log("屏幕宽度:", windowWidth); // 输出屏幕宽度
这句用来获取屏幕宽度,也就是swiper的宽度。
2、需要的数组:list
list数组定义在vuex也就是uniapp的store中 ,上完整代码:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex); // Vue 的插件机制
// Vuex.Store 构造器选项
const store = new Vuex.Store({
state: {
// 图片数组
//下方的连接是cdn图片地址,cdn图片可以自行搜索。
list: [
{ image: 'https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.jpg' },
{ image: 'https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.jpg'},
{ image: 'https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.jpg' },
{ image: 'https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.jpg' },
{ image: 'https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.jpg' },
]
},
mutations: {},
actions: {},
});
export default store;
思路二:
取竖屏图片数组高度的平均值作为swiper的高度。(推荐)
这样对于一组图片,显示效果会
<template>
<view class="container">
<!-- 该页面逻辑将竖屏图片数组高度的平均值作为容器高度 -->
<swiper class="swiper-box" :style="{height: swiperHeight + 'px'}" :indicator-dots="indicatorDots"
:autoplay="autoplay" :interval="interval" :duration="duration">
<swiper-item class="swiper-item" v-for="(item, index) in swiperItem" :key="index">
<image class="image" :src="item.image" mode="widthFix" @load="onImageLoad($event, item)" />
</swiper-item>
</swiper>
</view>
</template>
<script>
import { mapState } from 'vuex';
export default {
// name: 'DetailPage',
computed: {
...mapState(['list', 'swiperItem']),
indicatorDots() {
return true;
},
autoplay() {
return true;
},
interval() {
return 3000;
},
duration() {
return 500;
},
},
data() {
return {
imagesInfo: [], // 存储所有图片尺寸信息的数组
portraitImages: [], // 存储竖屏图片信息的数组
imagesLoadedCount: 0, // 已加载图片的数量
swiperHeight: 0, // 计算后的最高竖屏图片的高度
};
},
methods: {
onImageLoad(event, item) {
const detail = event.detail;
const { width, height } = detail;
const entry = {
url: item.image,
width,
height,
aspectRatio: height / width,
};
this.imagesInfo.push(entry);
// 检查是否为竖屏比例
if (entry.aspectRatio > 1) {
this.portraitImages.push(entry);
}
console.log('高宽:', entry.height, entry.width);
this.imagesLoadedCount++;
if (this.imagesLoadedCount === this.list.length) {
this.calculateAveragePortraitHeight();
}
},
calculateAveragePortraitHeight() {
if (this.portraitImages.length === 0) {
console.warn('没有竖屏图片');
return;
}
const totalHeight = this.portraitImages.reduce((sum, image) => sum + image.height, 0);
const averageHeight = totalHeight / this.portraitImages.length;
const {
windowWidth
} = uni.getSystemInfoSync(); // 这里可能需要改为异步调用
console.log("屏幕宽度:", windowWidth); // 输出屏幕宽度
this.swiperHeight = Math.round((averageHeight * windowWidth) / this.portraitImages[0].width);
console.log("计算后swiper高度:", this.swiperHeight); // 计算后swiper高度
},
},
mounted() {
// 在这里可以监听窗口大小变化等操作
},
beforeDestroy() {
// 清除标记
}
};
</script>
<style>
.container {
width: 100%;
position: relative;
}
.swiper {
width: 100%;
height: 500px; /* 使用计算属性 */
}
.image {
width: 100%;
height: auto;
}
</style>
好很多。