这个问题可真是研究了好几天,时间跨度很大了,涉及好多个小细节知识点
问题产生
问题来源于我想通过ElementUI框架中的Carousel 走马灯
实现轮播图片效果,但是由于carousel
默认高度是300,一旦图片宽度发生改变(如窗口变化,侧边栏变化等导致),整个图片就会变形或者显示不全。
解决方案1
既然是高度不适配产生的问题,我首先想到的解决方案就是移除掉组件的默认高度,但是明显是我想的太简单了,高度已经被默认设置了,无论是设置为空还是设置为0都是没有用的。
解决方案2
到这步思考了一会儿就去网上查阅资料了,发现网上的解决方案清奇的一致,那就是操作DOM元素!!
网上的解决方案总结起来就是两种,一个是通过vue的ref操作,还有就是通过document.getElementXXX
这种原生js操作。
最开始两种方法都试过之后发现对于我的项目根本不管用,参考了很多相关示例,才发现我的图片是通过循环遍历得到的,不管是那种方法都需要注意操作方式。
这里插入一下ref的用法
-
ref 加在普通的元素上 用
this.$refs.name
获取DOM元素 -
ref 加在子组件上 用
this.$refs.(ref值)
获取到的就是组件实例 ,可以用组件的所有方法。 在使用方法的时候直接用this.$refs.(ref值).方法()
就能直接用了 -
如果ref绑定在v-for 那么获取得到的就是一组对象(数组)的DOM节点
这歩搞清楚后就开始设置页面监听器等方法,终于解决了问题,可以实现组件高度随着图片高度的变化而变化。
window.onresize = () =>
虽然这个可以监听页面并且可以根据图片改变组件大小,但是如果我是通过点击侧边栏按钮缩放页面的,就不会被这个方法监听到,因此我又加入了新的方法,来监听元素变化。
const elementResizeDetectorMaker = require('element-resize-detector')
let erd = elementResizeDetectorMaker();
erd.listenTo(document.getElementsByClassName('app-container'), () => {
this.XXX
})
但是新的问题也随之而来,由于我的项目是通过两层循环遍历的图片,第一层遍历所有的标签栏和内容,第二层是在每个内容下面遍历属于这个内容的图片。
而我是通过给所有图片设置ref,然后获取时是获取的所有图片中的第一个图片的高度。这样就会导致当我点击别的标签栏下面的内容时,下面的图片并不会发送改变,而是用了第一个标签中的第一个图片。
这个问题的解决方案是通过在遍历图片时根据属于哪个大标签来设置ref加索引
:ref="'imgHeight' + i"
到了这时,大大小小的问题算是全部解决了!!
总结
本项目的代码结构如下
<!-- 最外层标签栏 -->
<el-tabs @tab-click="handleClick">
<!-- 遍历出来的页签名称和里面内容 -->
<el-tab-pane :label="item.tab" v-for="item, i in productList">
<!-- 在每个内容里面再次遍历轮播图 -->
<el-carousel :height="imgHeight">
<!-- 轮播图 -->
<el-carousel-item v-for="img in imgList(item.image)">
<!-- 动态添加ref -->
<img :src="img" width="100%" :ref="'imgHeight' + i" @load="imgLoad" />
</el-carousel-item>
</el-carousel>
</el-tab-pane>
</el-tabs>
const elementResizeDetectorMaker = require('element-resize-detector')
export default {
name: "Product",
data() {
return {
imgHeight: '',
tabIndex: '0'
};
},
created() {
this.getList() //获取数据
},
destroyed() {
window.onresize = null
},
mounted() {
let erd = elementResizeDetectorMaker();
// 监听页面变化
this.$nextTick(() => {
erd.listenTo(document.getElementsByClassName('app-container'), () => {
this.imgLoad()
})
})
// 监听窗口变化
window.onresize = () => {
this.imgLoad()
}
},
methods: {
// 获取tab栏
handleClick(tab) {
//设置标签栏索引
this.tabIndex = tab.index;
this.imgLoad()
},
imgLoad() {
// 获取图片高度
this.$nextTick(() => {
this.imgHeight = eval('this.$refs.imgHeight' + this.tabIndex)['0'].height + 'px'
})
},
}
}
注意功能点:
-
引入
element-resize-detector
监听元素变化 -
通过设置标签栏索引来动态获取每个内容的下面的图片
-
通过js内置函数
eval()
计算字符串表达式的值