900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > vue木桶布局(图片自适应浏览器宽度排列)的实现方法

vue木桶布局(图片自适应浏览器宽度排列)的实现方法

时间:2021-08-01 20:52:20

相关推荐

vue木桶布局(图片自适应浏览器宽度排列)的实现方法

先上效果:

基本实现思路:

监听浏览器的resize事件,实时获取到浏览器宽度设置一个图片的基础高度(例如300px),以此为基准把图片都缩放到这个高度把图片依次加入同一行,如果宽度超过浏览器宽度了,开始下一步处理把最后一张导致超出宽度的图片弹出,计算该行已有图片的宽度根据面积相等原则,计算新的高度(新的高度 = 浏览器宽度 * 基础高度 / 总的宽度 )根据新高度和图片原始比例,计算出图片新的宽高最后一行不足以铺满屏幕,进行特殊处理

虽然步骤说起来挺简单,但其实实现起来还是有不少坑的,比如说图片计算新的宽高时记得把边距也算上,最后一行因为不满一行需要特殊处理,图片的比例计算等等

完整的代码如下,已加有注释,可直接当一个组件使用,传入的参数格式如下

imgs:[{id: 1, url:'图片地址', width: '图片宽度', height: '图片高度' }]

<template><div v-if="newList.length>0"><div class="row" v-for="(row,index) in newList" :key="index" style="min-width:1100px;"><div class="img-box" v-for="img in row" :key="img.id" :style="{'width':img.width,'height':img.height}"><a :href="'detail/'+img.id" target="_blank"><el-image :src="img.url" alt="图片加载失败" :style="{'width':img.width,'height':img.height}" lazy></el-image></el-image></a></div></div></div></template><script>export default {props: ['imgs'],data: function () {return {screenWidth: document.body.clientWidth,imgsData: [], // 实际操作的图片列表timer: null}},mounted () {const self = this// 添加监听浏览器resize事件self.$nextTick(() => {self.screenWidth = document.body.clientWidthwindow.addEventListener('resize', function () {self.throttle(() => {self.screenWidth = document.body.clientWidth}, 100)})})// 转存传过来的props里的imgs数据self.imgsData = self.imgs},watch: {// 监听浏览器宽度screenWidth (val) {this.screenWidth = val// 宽度一旦发生变化就开始重新排列this.realignImgs()}},computed: {newList () {// 接收的参数是baseheight,图片的基础高度return this.realignImgs(300)}},methods: {// 节流throttle (fn, wait, scope) {clearTimeout(this.timer)this.timer = setTimeout(function () {fn.apply(scope)}, wait)},// 处理数据realignImgs (baseheight) {// baseheight是设置的基础高度,后面的高度都是根据这个基础上下浮动的const newList = []// 设定一个浏览器宽度的最低值为1000pxconst screenWidth = Number(this.screenWidth) > 1000 ? Number(this.screenWidth) : 1000// 先把设定的基础高度当作行高const rowHeight = baseheightlet arrRow = []let imgsData = []// 深拷贝转储一下imgsData = JSON.parse(JSON.stringify(this.imgsData))// 循环 计算每个图片的宽度for (let i = 0; i < imgsData.length; i++) {const item = imgsData[i]// 计算图片的宽高比item.ratio = Number(item.width) / Number(item.height)// 新的宽度,算法是比例乘以行高const newWidth = parseInt(item.ratio * rowHeight)item.width = newWidthitem.height = rowHeight// 定义该行图片宽度之和let totalWidth = 0arrRow.push(item)for (let i = 0; i < arrRow.length; i++) {totalWidth += arrRow[i].width}// 如果该行加入的图片宽度大于了该行的宽度// 就需要弹出最后一张图片,并更改前面的图片大小比例if (totalWidth > screenWidth) {// 把最后一张弹出,恢复原来的wholeWidthconst lastImg = arrRow.pop()totalWidth -= lastImg.width// 利用面积相等原则,来计算新的高度const newHeight = screenWidth * rowHeight / totalWidth// 这里是根据一行图片的数量,计算需要留出的边距const marginSpace = (arrRow.length - 1) * 20// 重新计算宽高,占满一行for (let i = 0; i < arrRow.length; i++) {// 最后再把每张图片等比例缩小一点,以留出边距arrRow[i].width = newHeight * arrRow[i].ratio - marginSpacearrRow[i].height = newHeight - (marginSpace / arrRow[i].ratio)}// 放置完毕之前的图片之后,清空该图片队列// 并将上一行溢出的图片 作为下一行的第一张newList.push(arrRow)arrRow = []arrRow.push(lastImg)}}// 单独处理未最后一行// 遍历每一行,把每一行的长度都加起来,这样才能得出最后一行的元素数量let tmp = 0for (let i = 0; i < newList.length; i++) {tmp += newList[i].length}const lastRow = []for (let i = tmp; i < imgsData.length; i++) {// 高度就以设置好的基础高度为基准了imgsData[i].height = rowHeight// 宽度也是按照比例算的imgsData[i].width = imgsData[i].ratio * rowHeightlastRow.push(imgsData[i])}newList.push(lastRow)return newList}}}</script><style scoped>.row {margin-top: 20px;display: flex;justify-content: space-around;}a {text-align: center;}.img-box {margin: 0 10px;transition: all 0.5s;}.img-box>img {transition: all 0.5s;}.img-box:hover {transform: scale(1.05);}.img-box:hover>img {transform: scale(1.05);}</style>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。