個人技術博客——vue的響應式布局


技術描述

  • 這個技術用來干嘛?
    • 響應式布局用於使頁面在不同的設備上都能有一個正常的樣式顯示,支持用戶不同顯示規格的設備上訪問頁面且仍有良好體驗。
  • 為什么要學這個?
    • 隨着移動端的普及,現在的頁面最基礎也需要達到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;
  }
},

可能會遇到的問題

  1. 窗口一打開樣式不正確

可能是因為你在data中的windowWidth沒有賦初值,需要在窗口建立的時候就讓它獲得初始的窗口大小數值,否則無法進入判斷循環。

data() {
  return {
    windowWidth:document.documentElement.clientWidth
  }
}
  1. 切換時只有一部分樣式切換了,另一部分樣式沒有切換

要注意你的樣式的嵌套,有可能切換的時候只有被嵌套包含的部分完成了切換,而在嵌套外的沒有完成。

.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中監聽窗口大小?

概述:實際操作了vue中監聽窗口大小的方法,包括了局部引入和全局引入

vue框架響應式布局

概述:實現時提供了一個思路,按照v-if或者v-show控制,后續經過思考采取了綁定類的方式進行切換。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM