技术描述
- 这个技术用来干嘛?
- 响应式布局用于使页面在不同的设备上都能有一个正常的样式显示,支持用户不同显示规格的设备上访问页面且仍有良好体验。
- 为什么要学这个?
- 随着移动端的普及,现在的页面最基础也需要达到PC端和手机端的样式能够让人在接受的程度。如果用户手机打开页面整个样式崩溃了,那他也没有理由继续选用你的应用了。
- 技术难点在哪?
- 页面的CSS不能再写死了,要使用百分比,或者直接使用flex弹性布局(我自己采用了这种方式)
- 要多写好多类的样式,搞清楚类的包含关系,这里我推荐可以简单学一下CSS的预处理语言包括.less和.sass,这样写CSS的嵌套关系、参数关系都会更加清楚
技术详述
背景以及环境
- 当前使用方法仅限于vue项目开发时使用(由于vue要求使用webpack所以下面不再赘述)
- 当前方法是vueCLI4.0版本下使用,vue没有保证完全向前兼容,但是基础的方法应该不会改变。
- 当前方法写CSS的时候使用了.less的预处理语言,如果查看代码有困难画3-5分钟熟悉一下预处理语言即可看懂。
- 当前方法使用vuex本地化保存窗口大小,如果你想使用localstorage保存原理是类似的。
- 当前方法使用了v-bind的绑定样式逻辑编写,如果还有其他实现方法欢迎讨论。
流程图
1.基础类的CSS样式
<div>
<div :class="personInfoClass">
<div class="Avatar">
<el-avatar
:size="180"
:src="avatarUrl">
</el-avatar>
</div>
……………………
这里只展示一个基础的div。此处将外围DIV的class通过v-bind
动态绑定了一个personInfoClass的类名。此处建议将personInforClass作为computed属性配置,否则每次都重新判断会导致页面效率降低。
computed:{
personInfoClass(){
if(this.windowWidth > 500) {
return "PersonInfo"
} else {
return "mobile_person_info_content"
}
},
}
这里可以看到配置的personInfoClass的类会返回两种情况,一种是在窗口大于500px的时候返回PersonInfo类,一种是在窗口小于500px的时候调用我们移动端的类。那么显然的,在一般情况下都会调用PersonInfo类,所以我们在vue对应组件内使用局部性CSS写好这部分基础类的样式
<style lang="less" scoped>
@import "~@/CSS/Common.less";
.PersonInfo {
.setSize(925px, 230px);
padding: 20px 20px;
background-color: white;
display: flex;
justify-content: right;
.Avatar {
display: flex;
flex-direction: column;
justify-content: center;
}
.UserName {
display: flex;
font-size: 32px;
}
}
}
这样项目就保证了这个div在窗口>500px的时候使用该类的样式。
2.编写其他情况的CSS样式
那么另一个移动端的CSS样式写在哪里呢?
我们新建一个CSS文件下存放我们的mobile状态的CSS,命名为mobile.less(我这里还有小窗的样式,所以还有smallWIndow.less)
我们刚才命名的小窗下的类名为mobile_person_info_content
,所以我们这里直接写一个对应的类样式
.mobile_person_info_content {
calc(100% - 20px);
margin: 20px auto;
background-color: white;
display: flex;
flex-direction: column;
justify-content: center;
.Avatar{
display: flex;
justify-content: center;
flex-direction: row;
}
.UserName {
display: flex;
justify-content: center;
flex-direction: row;
font-size: 32px;
}
}
在你的需要引用的地方引入这个.less
文件即可,我这里由于整个程序都需要适应配置,所以全局引入在了最顶端的根组件CSS内。当然既然是全局引入,这里不需要加scoped
限定范围。
<style lang="less">
@import "~@/CSS/mobile.less";
@import "~@/CSS/smallWindow.less";
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
}
}
这样在全局范围内的vue就可以使用我们在这两个文件内写的类样式了。
3.监控窗口大小
当我们完成了类的配置之后,我们需要监控窗口大小,让computed属性中的类可以进行切换,来使得div的绑定类切换,进而通过改变类的样式实现不同情况下的样式显示。
首先在vuex中增加窗口大小的state
。(关于vuex的引入和属性的操作不做说明了)
const state = {
screenWidth:document.documentElement.clientWidth, //屏幕宽度
screenHeight:document.documentElement.clientHeight, //屏幕高度
}
与上面类似的,如果需要局部引入则在对应的组件内使用下述方法即可,如果要全局引入,按部就班就行。
在最顶层的根组件下使用mounted
生命周期函数,用dom
原生的window.onresize
监听窗口的大小变化。(为什么全局只在根组件引入呢?因为整个程序周期中只允许一个window.onresize
监听,此外多余的都是没有反应的,所以如果你在多个组件重复引入window.onresize
是没有作用的,只能通过根目录的监听使得整个项目都能监听到窗口大小)
mounted() {
let that = this;
window.onresize=function() {
that.$store.state.screenWidth = document.documentElement.clientWidth; //窗口宽度
that.$store.state.screenHeight = document.documentElement.clientHeight; //窗口高度
}
}
随后的,就需要监听这个vuex里的窗口大小参数了,在需要的组件内使用watch
函数监听参数,比如我这里就是刚才的div组件中。这里的windowWidth已经定义在data中,这里不做演示了
watch: {
'$store.state.screenWidth': function (val) { //监听屏幕宽度变化
this.windowWidth = val;
}
},
可能会遇到的问题
- 窗口一打开样式不正确
可能是因为你在data中的windowWidth没有赋初值,需要在窗口建立的时候就让它获得初始的窗口大小数值,否则无法进入判断循环。
data() {
return {
windowWidth:document.documentElement.clientWidth
}
}
- 切换时只有一部分样式切换了,另一部分样式没有切换
要注意你的样式的嵌套,有可能切换的时候只有被嵌套包含的部分完成了切换,而在嵌套外的没有完成。
.mobile_person_info_content {
calc(100% - 20px);
margin: 20px auto;
background-color: white;
display: flex;
flex-direction: column;
justify-content: center;
.Avatar{
display: flex;
justify-content: center;
flex-direction: row;
}
}
.UserName {
display: flex;
justify-content: center;
flex-direction: row;
font-size: 32px;
}
比如上文的样式如果写成这样。则.UserName的类的样式是不会改变的,因为优先级的原因,vue会优先使用局部的同名CSS样式。类似的,如果你还有其他的全局.CSS样式,你也需要保证把所有要修改样式的类都嵌套进去。否则全局的样式也会被局部的同名CSS样式覆盖。
3.样式完全没有改变
不要用严格的属性比如px来限定窗口,使用百分比属性或者相对属性来进行样式编写。尽量使用flex的弹性布局,它本身就包含相对的布局。如果使用了px来进行限定也不要影响到相对的布局。
总结
最终响应式配置的逻辑链就形成了,根组件事实监听窗口大小->将窗口大小保存在本地->组件监听本地的窗口大小数据变化->赋值给组件参数->组件参数变化,进入切换类的判断->根据判断决定返回的类名->通过类名在CSS中找到对应的样式->样式改变。
参考博客
概述:简单介绍了一下如何显示样式的理论知识。
概述:实际操作了vue中监听窗口大小的方法,包括了局部引入和全局引入
概述:实现时提供了一个思路,按照v-if或者v-show控制,后续经过思考采取了绑定类的方式进行切换。