技術描述
- 這個技術用來干嘛?
- 響應式布局用於使頁面在不同的設備上都能有一個正常的樣式顯示,支持用戶不同顯示規格的設備上訪問頁面且仍有良好體驗。
- 為什么要學這個?
- 隨着移動端的普及,現在的頁面最基礎也需要達到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 {
width: 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 {
width: 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控制,后續經過思考采取了綁定類的方式進行切換。
