UNIAPP 响应式

目的

由于公司老项目只适用于安卓 ios手机端,完全按照 750px 做的适配,现如今公司特殊屏幕需要使用1280*720。
需要进行适配,工期比较端 中间可能还会有各种平板电脑的适配,因此采用的bootstrap 响应式布局,但是uniapp 无法使用媒体查询 故自己实现了响应式布局

思路

使用 uni.onWindowResize(this.onsize) 在app.vue 监听屏幕大小发生变化的是动态响应并把值存储在vuex中方便后续使用

onsize(res) {
    if(res) {
        this.$store.commit("setScreenSize", {
            screenWidth: res.size.windowWidth,
            screenHeight: res.size.windowHeight
        })
        
    } else {
        this.$store.commit("setScreenSize", {
            screenWidth:  uni.getSystemInfoSync().screenWidth,
            screenHeight: uni.getSystemInfoSync().screenHeight
        })
    
    }
},

由于初次进入 app.vue 监听并不会触发 故主动调用一次 根据传入的值来判断是主动调用的还是动态响应的

封装 w-row

<template>
<view class="w-Row" :class="activeClass">
    <slot></slot>
</view>
</template>

<script>
    export default {
        name: 'w-row',
        props: {
            // 两个子item 的间距
            gutter: {
                type: Number,
                default: 0
            }
        },
        data() {
            return {
                screenWidth: 360,
                screenHeight: 360,
            }
        },
        computed: {
            rowStyle() {
                let data = {}
                data.width = this.$store.state.screenWidth + 'px'
                return data
            },
            
            activeClass() {
                // xs	<768px 响应式栅格数或者栅格属性对象
                // sm	≥768px 响应式栅格数或者栅格属性对象
                // md	≥992px 响应式栅格数或者栅格属性对象
                // lg	≥1200px 响应式栅格数或者栅格属性对象
                // xl	≥1920px 响应式栅格数或者栅格属性对象x
                const w = this.$store.state.screenWidth;
                console.log(w)
                if(w < 768) {
                    return "xs"
                } else if(w >= 768 && w < 992) {
                    return "sm"
                } else if(w >= 992 && w < 1200) {
                    return "md"
                } else {
                    return "lg"
                }
            }
            
        },
    
        mounted() {
    
        },
        
        methods: {
        
        }
    }
</script>

<style lang="scss">
    .w-Row {
        width: 100%;
        display: flex;
        flex-wrap: wrap;
        box-sizing: border-box;
    }
    
</style>

w-col 封装

<template>
	<view class="w-Col" :style="colStyle">
		<slot></slot>
	</view>
</template>

<script>
	// xs	<768px 响应式栅格数或者栅格属性对象
	// sm	≥768px 响应式栅格数或者栅格属性对象
	// md	≥992px 响应式栅格数或者栅格属性对象
	// lg	≥1200px 响应式栅格数或者栅格属性对象
	// xl	≥1920px 响应式栅格数或者栅格属性对象
	
	export default {
		props: {
			xs: {
				type: Number
			},
			sm: {
				type: Number
			},
			md: {
				type: Number
			},
			lg: {
				type: Number
			},
			// xl: {
			// 	type: Number
			// }
		},
		data() {
			return {
				screenWidth: 360,
				screenHeight: 360,
				gutter: 0
			}
		},
		computed: {
			colStyle() {
				let data = {}
				const w = this.$store.state.screenWidth;
				let objWidth = 0;
				
				// xs	<768px 响应式栅格数或者栅格属性对象
				// sm	≥768px 响应式栅格数或者栅格属性对象
				// md	≥992px 响应式栅格数或者栅格属性对象
				// lg	≥1200px 响应式栅格数或者栅格属性对象
				// xl	≥1920px 响应式栅格数或者栅格属性对象
				if(w < 768) {
					objWidth = this.xs / 24 * 100
				} else if(w >= 768 && w < 992) {
					objWidth = this.sm / 24 * 100
				} else if(w >= 992 && w < 1200) {
					objWidth = this.md / 24 * 100
				} else {
					objWidth = this.lg / 24 * 100
				}
				data.width = objWidth + '%'
				// #ifdef APP-PLUS
				data.paddingLeft = (this.$parent.gutter || 0 )/ 2 + 'px'
				data.paddingRight = (this.$parent.gutter || 0 )/ 2  + 'px'
				// #endif
				
				// #ifdef H5
				data.paddingLeft = (this.$parent.$parent.gutter || 0 )/ 2 + 'px'
				data.paddingRight = (this.$parent.$parent.gutter || 0 )/ 2  + 'px'
				// #endif
				
				return data
			}
			
			
		},
		
		methods: {
			
		}
	}
</script>

<style lang="scss">
	.w-Col{
		box-sizing: border-box;
	}
</style>

遇到的坑 在 uniapp 中 显示在浏览器时获取父节点gutter时需要往上找两个父节点,在app 中只需要找一个父节点就能找到 父节点的 gutter 代码如下

// #ifdef APP-PLUS
data.paddingLeft = (this.$parent.gutter || 0 )/ 2 + 'px'
data.paddingRight = (this.$parent.gutter || 0 )/ 2  + 'px'
// #endif

// #ifdef H5
data.paddingLeft = (this.$parent.$parent.gutter || 0 )/ 2 + 'px'
data.paddingRight = (this.$parent.$parent.gutter || 0 )/ 2  + 'px'
// #endif

部分屏幕 针对高度也要进行对应的适配 比如登陆,注册时用户协议勾选,在比较低的屏幕中没办法定位在底部,要随着页面进行滚动, 在适当高度的时候需要定位到底部,故我在 vuex 中留了 页面高度进行在不同界面的时候做出更丝滑的操作

为什么没有采用uniapp的多window方案

能快速对app进行横竖屏的适配,因为时间紧凑 能更快的满足公司的业务,比较适合前端响应式布局的理念,使用vuex管理屏幕尺寸 使用动态类名快速解决不同屏幕动态样式的目的

uniapp 推出了多window方案但是对于我们这种屏幕过多页面过于工业复杂的界面不适合使用多window的效果

参考资料

bootstarp