Vue动态获取浏览器窗口宽度
项目中有一个需求,搜索框需要根据页面宽度动态变化,例如宽度小于等于1280时搜索框的宽度为280px,大于1920时宽度为360px,在1280和1920之间则根据比例缩放。由于页面是flex布局,并且靠两端对齐的,所以min-width和max-width基本上是排不上用场了。当时首先想到的是媒体查询,但是媒体查询不能实现按比例缩放的效果。后来想到通过JS获取页面宽度,然后根据宽度来判断搜索框应
项目中有一个需求,搜索框的宽度需要根据页面宽度动态变化,例如宽度小于等于1280时搜索框的宽度为280px,大于1920时宽度为360px,在1280和1920之间则根据比例缩放。
由于页面是flex布局,并且靠两端对齐的,所以给搜索框设置 min-width
和 max-width
基本上是排不上用场了。当时首先想到的是 媒体查询
,但是 媒体查询
不能实现按比例缩放的效果。后来想到通过 JS 获取页面的 innerWidth
,然后根据这个值来判断搜索框应该取多少宽度。
那么这个逻辑应该放在什么位置呢?先在计算属性里面试了下,代码如下:
<template>
<el-input v-model="search" :style="{'width': `${searchFormWidth}px`}"
</template>
<script>
export default {
computed: {
searchFormWidth() {
let w = window.innerWidth;
if(w <= 1280) {
return 280
} else if (w < 1920) {
return ((w - 1280)*80)/640 + 280
} else {
return 360
}
}
}
}
</script>
计算属性具有缓存,并且依赖改变后,会重新计算,所以经常用于动态样式绑定。但是经过试验后发现, searchFormWidth
只会在组件初始化的时候调用一次,之后页面缩放无法改变搜索框宽度。
看来计算属性只能监听响应式依赖的变化,对于 window 对象属性的变化无法检测。那就另辟蹊径,通过监听浏览器的窗口缩放事件 window.onresize
,在组件的 mounted 钩子里面绑定监听回调,然后在 methods 中定义 searchFormWidth
方法动态计算宽度。
<template>
<el-input v-model="search" :style="{'width': `${searchWidth}px`}"
</template>
<script>
export default {
data() {
return {
searchWidth: 280
}
}
mounted() {
this.searchFormWidth(); // 组件初始化的时候不会触发onresize事件,这里强制执行一次
window.onresize = () => {
if(!this.timer){ // 使用节流机制,降低函数被触发的频率
this.timer = true;
let that = this; // 匿名函数的执行环境具有全局性,为防止this丢失这里用that变量保存一下
setTimeout(function(){
that.searchFormWidth();
that.timer = false;
},400)
}
}
}
destroyed() {
// 组件销毁后解绑事件
window.onresize = null;
}
methods: {
searchFormWidth() {
let w = window.innerWidth;
if(w <= 1280) {
this.searchWidth = 280
} else if (w < 1920) {
this.searchWidth = ((w - 1280)*80)/640 + 280
} else {
this.searchWidth = 360
}
}
}
}
</script>
这边有个注意点,也就是在组件销毁后需要手动解绑事件。
在 Vue 中通过
v-on
绑定的事件,在组件销毁后会自动解绑。
而 window
对象上的事件,例如 window.onresize
、window.addEventListener
,组件销毁后是不会解绑的,必须手动在 destroyed
钩子中解绑。还有一些定时器也是一样操作。
至于为什么建议在 destroyed
钩子而不是 beforeDestroy
,因为通常组件中可能还嵌套了很多子组件,我们知道父子组件生命周期顺序:
1. 加载渲染过程
父组件 beforeCreate -> 父组件 created -> 父组件 beforeMount -> 子组件 beforeCreate -> 子组件 created -> 子组件 beforeMount -> 子组件 mounted -> 父组件 mounted
2. 子组件更新过程
父组件 beforeUpdate -> 子组件 beforeUpdate -> 子组件 updated -> 父组件 updated
3. 父组件更新过程
父组件 beforeUpdate -> 父组件 updated
4. 销毁过程
父组件 beforeDestroy -> 子组件 beforeDestroy -> 子组件 destroyed -> 父组件 destroyed
从上面就可以看出,父组件进入 beforeDestroy ,子组件此时并没有销毁,在这个时候如果解绑事件,可能会导致子组件出问题,因此建议在 destroyed 钩子中解绑。
更多推荐
所有评论(0)