整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          「ThinkPHP5開發連載66」tp5連載模板-模板布局之動態方法布局

          一篇文章講解“模型-模板布局之模板標簽方式”,本篇文章講解“模板-模板布局之動態方法布局”。


          動態方法布局

          使用內置的layout方法可以更靈活的在程序中控制模板輸出的布局功能,尤其適用于局部需要布局或者關閉布局的情況,這種方式也不需要在配置文件中開啟layout_on。

          1)基本使用

          ①在Index控制器中,新建dynamic方法

          ②index.html模板與layout.html布局模板的內容

          index.html模板:

          layout.html布局模板:

          預覽:

          2)使用其他的布局模板

          如果當前輸出需要使用不同的布局模板,可以動態的指定布局模板名稱,例如:

          ①在dynamic方法中指定使用其他的布局模板

          ②在view/public/下新建lay.html布局模板

          預覽:

          3)動態關閉當前模板的布局功能

          使用layout方法動態關閉當前模板的布局功能(這種用法可以配合第一種布局方式,例如全局配置已經開啟了布局,可以在某個頁面單獨關閉):

          ①在dynamic方法中動態關閉模板的布局功能

          ②開啟全局配置方式的模板布局

          預覽:

          注意:

          1. 三種模板布局方式中,第一種和第三種是在程序中配置實現模板布局,第二種方式則是單純通過模板標簽在模板中使用布局。具體選擇什么方式,需要根據項目的實際情況來了。

          2. 模板布局默認布局模板位置為“view/layout.html”

          3. 默認替換的特定字符串為{__CONTENT__}

          ?ThinkPHP5連載為卓象程序員原創,轉載請聯系卓象程序員

          關注卓象程序員,定期發布技術文章

          下一篇講解“模板-包含文件”

          一篇文章講解“模型-原樣輸出+模板注釋”,本篇文章講解“模板-模板布局之全局配置方式”。


          模板布局

          ThinkPHP的模板引擎內置了布局模板功能支持,可以方便的實現模板布局以及布局嵌套功能。

          有三種布局模板的支持方式:

          ①全局配置方式

          ②模板標簽方式

          ③動態方法布局


          全局配置方式

          這種方式僅需在項目配置文件中添加相關的布局模板配置,就可以簡單實現模板布局功能,比較適用于全站使用相同布局的情況,需要配置開啟layout_on參數(默認不開啟),并且設置布局入口文件名layout_name(默認為layout)。

          1)開啟模板布局,在config/template.php文件中開啟模板布局,并設置布局入口文件名

          2)新建Index控制器,并新建index方法,渲染index.html模板

          預覽:

          3)模板布局文件

          在不開啟layout_on布局模板之前,會直接渲染application/index/view/index/index.html模板文件,開啟之后,首先會渲染application/index/view/layout.html模板,布局模板的寫法和其他模板的寫法類似,本身也可以支持所有的模板標簽以及包含文件,區別在于有一個特定的輸出替換變量{__CONTENT__},例如,下面是一個典型的layout.html模板的寫法:

          讀取layout模板之后,會再解析index/index.html模板文件,并把解析后的內容替換到layout布局模板文件的{__CONTENT__}特定字符串。

          ①新建layout.html布局模板

          ②在index/index.html模板中添加要輸出的內容

          注意:

          1. index.html模板內容解析后會替換到layout.html布局模板的{__CONTENT__}字符串位置,因此index.html模板可以不加html的頭和底,layout.html中有頭和底,加也不會錯。

          預覽:

          4)修改特定替換字符串{__CONTENT__}的名字

          默認在模板布局layout.html模板中{__CONTENT__}為替換字符串,也可以進行自定義。

          在config/template.php文件中設置:

          設置后重新訪問index控制器的index方法,預覽:

          修改layout.html中的特定替換字符串:

          預覽:

          注意:

          1. 一個布局模板同時只能有一個特定替換字符串。

          2. 采用這種布局方式的情況下,一旦user/add.html模板文件或者layout.html布局模板文件發生修改,都會導致模板重新編譯。

          5)修改布局模板位置

          如果需要指定其他位置的布局模板,可以設置layout_name:

          在view/public下新建layout.html模板:

          預覽:

          6)某些頁面不需要使用布局模板

          如果某些頁面不需要使用布局模板功能,可以在模板文件開頭加上{__NOLAYOUT__}字符串。

          ①假設index.html模板不需要使用布局模板功能

          在index.html模板開頭加{__NOLAYOUT__}

          預覽:

          ThinkPHP5連載為卓象程序員原創,轉載請聯系卓象程序員

          關注卓象程序員,定期發布技術文章

          下一篇講解“模板-模板布局之模板標簽方式”


          當我們拿到一個 PC 端頁面的設計稿的時候,往往會發現頁面的布局并不是隨意的,而是遵循的一定的規律:行與行之間會以某種方式對齊。對于這樣的設計稿,我們可以使用柵格布局來實現。

          早在 Bootstrap 一統江湖的時代,柵格布局的概念就已深入人心,整個布局就是一個二維結構,包括列和行, Bootstrap 會把屏幕分成 12 列,還提供了一些非常方便的 CSS 名讓我們來指定每列占的寬度百分比,并且還通過媒體查詢做了不同屏幕尺寸的適應。

          element-ui 也實現了類似 Bootstrap 的柵格布局系統,那么基于 Vue 技術棧,它是如何實現的呢?

          需求分析

          和 Bootstrap 12 分欄不同的是,element-ui 目標是提供的是更細粒度的 24 分欄,迅速簡便地創建布局,寫法大致如下:

          <el-row>
           <el-col>aaa</el-col>
           <el-col>bbb</el-col>
          </el-row>
          <el-row>
           ...
          </el-row>
          復制代碼
          

          這就是二維布局的雛形,我們會把每個列的內容寫在 <el-col></el-col> 之間,除此之外,我們還需要支持控制每個 <el-col> 所占的寬度自由組合布局;支持分欄之間存在間隔;支持偏移指定的欄數;支持分欄不同的對齊方式等。

          了解了 element-ui Layout 布局組件的需求后,我們來分析它的設計和實現。

          設計和實現

          組件的渲染

          回顧前面的例子,從寫法上看,我們需要設計 2 個組件,el-row 和 el-col 組件,分別代表行和列;從 Vue 的語法上看,這倆組件都要支持插槽(因為在自定義組件標簽內部的內容都分發到組件的 slot 中了);從 HTML 的渲染結果上看,我們希望模板會渲染成:

          <div class="el-row">
           <div class="el-col">aaa</div>
           <div class="el-col">bbb</div>
          </div>
          <div class="el-row">
           ...
          </div>
          復制代碼
          

          想達到上述需求,組件的模板可以非常簡單。

          el-row 組件模板代碼如下:

          <div class="el-row">
           <slot></slot>
          </div>
          復制代碼
          

          el-col 組件代碼如下:

          <div class="el-col">
           <slot></slot>
          </div>
          復制代碼
          

          這個時候,新需求來了,我希望 el-row 和 el-col 組件不僅能渲染成 div,還可以渲染成任意我想指定的標簽。 那么除了我們要支持一個 tag 的 prop 之外,僅用模板是難以實現了。

          我們知道 Vue 的模板最終會編譯成 render 函數,Vue 的組件也支持直接手寫 render 函數,那這個需求用 render 函數實現就非常簡單了。

          el-row 組件:

          render(h) {
           return h(this.tag, {
           class: [
           'el-row',
           ]
           }, this.$slots.default);
          }
          復制代碼
          

          el-col 組件:

          render(h) {
           return h(this.tag, {
           class: [
           'el-col',
           ]
           }, this.$slots.default);
          }
          復制代碼
          

          其中,tag 是定義在 props 中的,h 是 Vue 內部實現的 $createElement 函數,如果對 render 函數語法還不太懂的同學,建議去看 Vue 的官網文檔 render 函數部分。

          了解了組件是如何渲染之后,我們來給 Layout 組件擴展一些 feature 。

          分欄布局

          Layout 布局的主要目標是支持 24 分欄,即一行能被切成 24 份,那么對于每一個 el-col ,我們想要知道它的占比,只需要指定它在 24 份中分配的份數即可。

          于是我們給剛才的示例加上一些配置:

          <el-row>
           <el-col :span="8">aaa</el-col>
           <el-col :span="16">bbb</el-col>
          </el-row>
          <el-row>
           ...
          </el-row>
          復制代碼
          

          來看第一行,第一列 aaa 占 8 份,第二列 bbb 占 16 份。總共寬度是 24 份,經過簡單的數學公式計算,aaa 占總寬度的 1/3,而 bbb 占總寬度的 2/3,進而推導出每一列指定 span 份就是占總寬度的 span/24。

          默認情況下 div 的寬度是 100% 獨占一行的,為了讓多個 el-col 在一行顯示,我們只需要讓每個 el-col 的寬占一定的百分比,即實現了分欄效果。設置不同的寬度百分比只需要設置不同的 CSS 即可實現,比如當某列占 12 份的時候,那么它對應的 CSS 如下:

          .el-col-12 {
           width: 50%
          }
          復制代碼
          

          為了滿足 24 種情況,element-ui 使用了 sass 的控制指令,配合基本的計算公式:

          .el-col-0 {
           display: none;
          }
          @for $i from 0 through 24 {
           .el-col-#{$i} {
           width: (1 / 24 * $i * 100) * 1%;
           }
          }
          復制代碼
          

          所以當我們給 el-col 組件傳入了 span 屬性的時候,只需要給對應的節點渲染生成對應的 CSS 即可,于是我們可以擴展 render 函數:

          render(h) {
           let classList = [];
           classList.push(`el-col-${this.span}`);
           
           return h(this.tag, {
           class: [
           'el-col',
           classList
           ]
           }, this.$slots.default);
          }
          復制代碼
          

          這樣只要指定 span 屬性的列就會添加 el-col-${span} 的樣式,實現了分欄布局的需求。

          分欄間隔

          對于柵格布局來說,列與列之間有一定間隔空隙是常見的需求,這個需求的作用域是行,所以我們應該給 el-row 組件添加一個 gutter 的配置,如下:

          <el-row :gutter="20">
           <el-col :span="8">aaa</el-col>
           <el-col :span="16">bbb</el-col>
          </el-row>
          <el-row>
           ...
          </el-row>
          復制代碼
          

          有了配置,接下來如何實現間隔呢?實際上非常簡單,想象一下,2 個列之間有 20 像素的間隔,如果我們每列各往一邊收縮 10 像素,是不是看上去就有 20 像素了呢。

          先看一下 el-col 組件的實現:

          computed: {
           gutter() {
           let parent = this.$parent;
           while (parent && parent.$options.componentName !== 'ElRow') {
           parent = parent.$parent;
           }
           return parent ? parent.gutter : 0;
           }
          },
          render(h) {
           let classList = [];
           classList.push(`el-col-${this.span}`);
           
           let style = {};
           
           if (this.gutter) {
           style.paddingLeft = this.gutter / 2 + 'px';
           style.paddingRight = style.paddingLeft;
           }
           
           return h(this.tag, {
           class: [
           'el-col',
           classList
           ]
           }, this.$slots.default);
          }
          復制代碼
          

          這里使用了計算屬性去計算 gutter,其實是比較有趣的,它通過 $parent 往外層查找 el-row,獲取到組件的實例,然后獲取它的 gutter 屬性,這樣就建立了依賴關系,一旦 el-row 組件的 gutter 發生變化,這個計算屬性再次被訪問的時候就會重新計算,獲取到新的 gutter。

          其實,想在子組件去獲取祖先節點的組件實例,我更推薦使用 provide/inject 的方式去把祖先節點的實例注入到子組件中,這樣子組件可以非常方便地拿到祖先節點的實例,比如我們在 el-row 組件編寫 provide:

          provide() {
           return {
           row: this
           };
          }
          復制代碼
          

          然后在 el-col 組件注入依賴:

          inject: ['row']
          復制代碼
          

          這樣在 el-col 組件中我們就可以通過 this.row 訪問到 el-row 組件實例了。

          使用 provide/inject 的好處在于不論組件層次有多深,子孫組件可以方便地訪問祖先組件注入的依賴。當你在編寫組件庫的時候,遇到嵌套組件并且子組件需要訪問父組件實例的時候,避免直接使用 this.$parent,盡量使用 provide/inject,因為一旦你的組件嵌套關系發生變化,this.$parent 可能就不符合預期了,而 provide/inject 卻不受影響(只要祖先和子孫的關系不變)。

          在 render 函數中,我們會根據 gutter 計算,給當前列添加了 paddingLeft 和 paddingRight 的樣式,值是 gutter 的一半,這樣就實現了間隔 gutter 的效果。

          那么這里能否用 margin 呢,答案是不能,因為設置 margin 會占用外部的空間,導致每列的占用空間變大,會出現折行的情況。

          render 過程也是有優化的空間,因為 style 是根據 gutter 計算的,那么我們可以把 style 定義成計算屬性,這樣只要 gutter 不變,那么 style 就可以直接拿計算屬性的緩存,而不用重新計算,對于 classList 部分,我們同樣可以使用計算屬性。組件 render 過程的一個原則就是能用計算屬性就用計算屬性。

          再來看一下 el-row 組件的實現:

          computed: {
           style() {
           const ret = {};
           if (this.gutter) {
           ret.marginLeft = `-${this.gutter / 2}px`;
           ret.marginRight = ret.marginLeft;
           }
           return ret;
           }
          },
          render(h) {
           return h(this.tag, {
           class: [
           'el-row',
           ],
           style: this.style
           }, this.$slots.default);
          }
          復制代碼
          

          由于我們是通過給每列添加左右 padding 的方式來實現列之間的間隔,那么對于第一列和最后一列,左邊和右邊也會多出來 gutter/2 大小的間隔,顯然是不符合預期的,所以我們可以通過設置左右負 margin 的方式填補左右的空白,這樣就完美實現了分欄間隔的效果。

          偏移指定的欄數

          如圖所示,我們也可以指定某列的偏移,由于作用域是列,我們應該給 el-col 組件添加一個 offset 的配置,如下:

          <el-row :gutter="20">
           <el-col :offset="8" :span="8">aaa</el-col>
           <el-col :span="8">bbb</el-col>
          </el-row>
          <el-row>
           ...
          </el-row>
          復制代碼
          

          直觀上我們應該用 margin 來實現偏移,并且 margin 也是支持百分比的,因此實現這個需求就變得簡單了。

          我們繼續擴展 el-col 組件:

          render(h) {
           let classList = [];
           classList.push(`el-col-${this.span}`);
           classList.push(`el-col-offset-${this.offset}`);
           
           let style = {};
           
           if (this.gutter) {
           style.paddingLeft = this.gutter / 2 + 'px';
           style.paddingRight = style.paddingLeft;
           }
           
           return h(this.tag, {
           class: [
           'el-col',
           classList
           ]
           }, this.$slots.default);
          }
          復制代碼
          

          其中 offset 是定義在 props 中的,我們根據傳入的 offset 生成對應的 CSS 添加到 DOM 中。element-ui 同樣使用了 sass 的控制指令,配合基本的計算公式來實現這些 CSS 的定義:

          @for $i from 0 through 24 {
           .el-col-offset-#{$i} {
           margin-left: (1 / 24 * $i * 100) * 1%;
           }
          }
          復制代碼
          

          對于不同偏移的分欄數,會有對應的 margin 百分比,就很好地實現分欄偏移需求。

          對齊方式

          當一行分欄的總占比和沒有達到 24 的時候,我們是可以利用 flex 布局來對分欄做靈活的對齊。

          對于不同的對齊方式 flex 布局提供了 justify-content 屬性,所以對于這個需求,我們可以對 flex 布局做一層封裝即可實現。

          由于對齊方式的作用域是行,所以我們應該給 el-row 組件添加 type 和 justify 的配置,如下:

          <el-row type="flex" justify="center">
           <el-col :span="8">aaa</el-col>
           <el-col :span="8">bbb</el-col>
          </el-row>
          <el-row>
           ...
          </el-row>
          復制代碼
          

          由于我們是對 flex 布局的封裝,我們只需要根據傳入的這些 props 去生成對應的 CSS,在 CSS 中定義 flex 的布局屬性即可。

          我們繼續擴展 el-row 組件:

          render(h) {
           return h(this.tag, {
           class: [
           'el-row',
           this.justify !== 'start' ? `is-justify-${this.justify}` : '',
           { 'el-row--flex': this.type === 'flex' }
           ],
           style: this.style
           }, this.$slots.default);
          }
          復制代碼
          

          其中 type 和 justify 是定義在 props 中的,我們根據它們傳入的值生成對應的 CSS 添加到 DOM 中,接著我們需要定義對應的 CSS 樣式:

          @include b(row) {
           position: relative;
           box-sizing: border-box;
           @include utils-clearfix;
           @include m(flex) {
           display: flex;
           &:before,
           &:after {
           display: none;
           }
           @include when(justify-center) {
           justify-content: center;
           }
           @include when(justify-end) {
           justify-content: flex-end;
           }
           @include when(justify-space-between) {
           justify-content: space-between;
           }
           @include when(justify-space-around) {
           justify-content: space-around;
           }
           }
          }
          復制代碼
          

          element-ui 在編寫 sass 的時候主要遵循的是 BEM 的命名規則,并且編寫了很多自定義 @mixin 來配合樣式名的定義。

          這里我們來花點時間來學習一下它們,element-ui 的自定義 @mixin 定義在 pacakages/theme-chalk/src/mixins/ 目錄中,我并不會詳細解釋這里面的關鍵字,如果你對 sass 還不熟悉,我建議在學習這部分內容的時候配合 sass 的官網文檔看。

          mixins/config.scss 中定義了一些全局變量:

          $namespace: 'el';
          $element-separator: '__';
          $modifier-separator: '--';
          $state-prefix: 'is-';
          復制代碼
          

          mixins/mixins.scss 中定義了 BEM 的自定義 @mixin,先來看一下定義組件樣式的 @mixin b:

          @mixin b($block) {
           $B: $namespace+'-'+$block !global;
           .#{$B} {
           @content;
           }
          }
          復制代碼
          

          這個 @mixin 很好理解,$B 是內部定義的變量,它的值通過 $namespace+'-'+$block 計算得到,注意這里有一個 !global 關鍵字,它表示把這個局部變量變成全局的,意味著你也可以在其它 @mixin 中引用它。

          通過 @include 我們就可以去引用這個 @mixin,結合我們的 case 來看:

          @include b(row) {
           // xxx content
          }
          復制代碼
          

          會編譯成:

          .el-row {
           // xxx content
          }
          復制代碼
          

          再來看表示修飾符的 @mixin m:

          @mixin m($modifier) {
           $selector: &;
           $currentSelector: "";
           @each $unit in $modifier {
           $currentSelector: #{$currentSelector + & + $modifier-separator + $unit + ","};
           }
           @at-root {
           #{$currentSelector} {
           @content;
           }
           }
          }
          復制代碼
          

          這里是允許傳入的 $modifier 有多個,所以內部用了 @each,& 表示父選擇器,$selector 和 $currentSelector 是內部定義的 2 個局部變量,結合我們的 case 來看:

          @mixin b(row) {
           @include m(flex) {
           // xxx content
           }
          } 
          復制代碼
          

          會編譯成:

          .el-row--flex {
           // xxx content
          }
          復制代碼
          

          有同學可能會疑問,難道不是:

          .el-row {
           .el-row--flex {
           // xxx content
           }
          }
          復制代碼
          

          其實并不是,因為我們在該 @mixin 的內部使用了 @at-root 指令,它會把樣式規則定義在根目錄下,而不是嵌套在其父選擇器下。

          最后來看一下表示同級樣式的 @mixin when:

          @mixin when($state) {
           @at-root {
           &.#{$state-prefix + $state} {
           @content;
           }
           }
          }
          復制代碼
          

          這個 @mixin 也很好理解,結合我們的 case 來看:

          @mixin b(row) {
           @include m(flex) {
           @include when(justify-center) {
           justify-content: center;
           }
           }
          }
          復制代碼
          

          會編譯成:

          .el-row--flex.is-justify-center {
           justify-content: center;
          }
          復制代碼
          

          關于 BEM 的 @mixin,常用的還有 @mixin e,用于定義組件內部一些子元素樣式的,感興趣的同學可以自行去看。

          再回到我們的 el-row 組件的樣式,我們定義了幾種flex 布局的對齊方式,然后通過傳入不同的 justify 來生成對應的樣式,這樣我們就很好地實現了靈活對齊分欄的需求。

          響應式布局

          element-ui 參照了 Bootstrap 的響應式設計,預設了五個響應尺寸:xs、sm、md、lg 和 xl。

          允許我們在不同的屏幕尺寸下,設置不同的分欄配置,由于作用域是列,所以我們應該給 el-col 組件添加 xs xs、sm、md、lg 和 xl 的配置,如下:

          <el-row type="flex" justify="center">
           <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1">aaa</el-col>
           <el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11">bbb</el-col>
           <el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11">ccc</el-col>
           <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1">ddd</el-col>
          </el-row>
          <el-row>
           ...
          </el-row>
          復制代碼
          

          同理,我們仍然是通過這些傳入的 props 去生成對應的 CSS,在 CSS 中利用媒體查詢去實現響應式。

          我們繼續擴展 el-col 組件:

          render(h) {
           let classList = [];
           classList.push(`el-col-${this.span}`);
           classList.push(`el-col-offset-${this.offset}`);
           
           ['xs', 'sm', 'md', 'lg', 'xl'].forEach(size => {
           classList.push(`el-col-${size}-${this[size]}`); 
           });
           
           let style = {};
           
           if (this.gutter) {
           style.paddingLeft = this.gutter / 2 + 'px';
           style.paddingRight = style.paddingLeft;
           }
           
           return h(this.tag, {
           class: [
           'el-col',
           classList
           ]
           }, this.$slots.default);
          }
          復制代碼
          

          其中,xs、sm、md、lg 和 xl 是定義在 props 中的,實際上 element-ui 源碼還允許傳入一個對象,可以配置 span 和 offset,但這部分代碼我就不介紹了,無非就是對對象的解析,添加對應的樣式。

          我們來看一下對應的 CSS 樣式,以 xs 為例:

          @include res(xs) {
           .el-col-xs-0 {
           display: none;
           }
           @for $i from 0 through 24 {
           .el-col-xs-#{$i} {
           width: (1 / 24 * $i * 100) * 1%;
           }
           .el-col-xs-offset-#{$i} {
           margin-left: (1 / 24 * $i * 100) * 1%;
           }
           }
          }
          復制代碼
          

          這里又定義了表示響應式的 @mixin res,我們來看一下它的實現:

          @mixin res($key, $map: $--breakpoints) {
           // 循環斷點Map,如果存在則返回
           @if map-has-key($map, $key) {
           @media only screen and #{inspect(map-get($map, $key))} {
           @content;
           }
           } @else {
           @warn "Undefeined points: `#{$map}`";
           }
          }
          復制代碼
          

          這個 @mixns 主要是查看 $map 中是否有 $key,如果有的話則定義一條媒體查詢規則,如果沒有則拋出警告。

          $map 參數的默認值是 $--breakpoints,定義在 pacakges/theme-chalk/src/common/var.scss 中:

          $--sm: 768px !default;
          $--md: 992px !default;
          $--lg: 1200px !default;
          $--xl: 1920px !default;
          $--breakpoints: (
           'xs' : (max-width: $--sm - 1),
           'sm' : (min-width: $--sm),
           'md' : (min-width: $--md),
           'lg' : (min-width: $--lg),
           'xl' : (min-width: $--xl)
          );
          復制代碼
          

          結合我們的 case 來看:

          @include res(xs) {
           .el-col-xs-0 {
           display: none;
           }
           @for $i from 0 through 24 {
           .el-col-xs-#{$i} {
           width: (1 / 24 * $i * 100) * 1%;
           }
           .el-col-xs-offset-#{$i} {
           margin-left: (1 / 24 * $i * 100) * 1%;
           }
           }
          }
          復制代碼
          

          會編譯成:

          @media only screen and (max-width: 767px) {
           .el-col-xs-0 {
           display: none;
           }
           .el-col-xs-1 {
           width: 4.16667%
           }
           .el-col-xs-offset-1 {
           margin-left: 4.16667%
           }
           // 后面循環的結果太長,就不貼了
          }
          復制代碼
          

          其它尺寸內部的樣式定義規則也是類似,這樣我們就通過媒體查詢定義了各個屏幕尺寸下的樣式規則了。通過傳入 xs、sm 這些屬性的值不同,從而生成不同樣式,這樣在不同的屏幕尺寸下,可以做到分欄的占寬不同,很好地滿足了響應式需求。

          基于斷點的隱藏類

          Element 額外提供了一系列類名,用于在某些條件下隱藏元素,這些類名可以添加在任何 DOM 元素或自定義組件上。

          我們可以通過引入單獨的 display.css:

          import 'element-ui/lib/theme-chalk/display.css';
          復制代碼
          

          它包含的類名及其含義如下:

          • hidden-xs-only - 當視口在 xs 尺寸時隱藏
          • hidden-sm-only - 當視口在 sm 尺寸時隱藏
          • hidden-sm-and-down - 當視口在 sm 及以下尺寸時隱藏
          • hidden-sm-and-up - 當視口在 sm 及以上尺寸時隱藏
          • hidden-md-only - 當視口在 md 尺寸時隱藏
          • hidden-md-and-down - 當視口在 md 及以下尺寸時隱藏
          • hidden-md-and-up - 當視口在 md 及以上尺寸時隱藏
          • hidden-lg-only - 當視口在 lg 尺寸時隱藏
          • hidden-lg-and-down - 當視口在 lg 及以下尺寸時隱藏
          • hidden-lg-and-up - 當視口在 lg 及以上尺寸時隱藏
          • hidden-xl-only - 當視口在 xl 尺寸時隱藏

          我們來看一下它的實現,看一下 display.scss:

          .hidden {
           @each $break-point-name, $value in $--breakpoints-spec {
           &-#{$break-point-name} {
           @include res($break-point-name, $--breakpoints-spec) {
           display: none !important;
           }
           }
           }
          }
          復制代碼
          

          實現很簡單,對 $--breakpoints-spec 遍歷,生成對應的 CSS 規則,$--breakpoints-spec 定義在 pacakges/theme-chalk/src/common/var.scss 中:

          $--breakpoints-spec: (
           'xs-only' : (max-width: $--sm - 1),
           'sm-and-up' : (min-width: $--sm),
           'sm-only': "(min-width: #{$--sm}) and (max-width: #{$--md - 1})",
           'sm-and-down': (max-width: $--md - 1),
           'md-and-up' : (min-width: $--md),
           'md-only': "(min-width: #{$--md}) and (max-width: #{$--lg - 1})",
           'md-and-down': (max-width: $--lg - 1),
           'lg-and-up' : (min-width: $--lg),
           'lg-only': "(min-width: #{$--lg}) and (max-width: #{$--xl - 1})",
           'lg-and-down': (max-width: $--xl - 1),
           'xl-only' : (min-width: $--xl),
          );
          復制代碼
          

          我們以 xs-only 為例,編譯后生成的 CSS 規則如下:

          .hidden-xs-only {
           @media only screen and (max-width:767px) {
           display: none !important;
           }
          }
          復制代碼
          

          本質上還是利用媒體查詢定義了這些 CSS 規則,實現了在某些屏幕尺寸下隱藏的功能。

          總結

          其實 Layout 布局還支持了其它一些特性,我不一一列舉了,感興趣的同學可以自行去看。Layout 布局組件充分利用了數據驅動的思想,通過數據去生成對應的 CSS,本質上還是通過 CSS 滿足各種靈活的布局。

          學習完這篇文章,你應該徹底弄懂 element-ui Layout 布局組件的實現原理,并且對 sass 的 @mixin 以及相關使用到的特性有所了解,對組件實現過程中可以優化的部分,應該有自己的思考。

          把不會的東西學會了,那么你就進步了,如果你覺得這類文章有幫助,也歡迎把它推薦給你身邊的小伙伴。


          主站蜘蛛池模板: 福利一区二区三区视频在线观看 | 91精品一区二区综合在线| 国产一区二区四区在线观看| 国产suv精品一区二区33| 欧美日韩综合一区二区三区| 成人免费一区二区三区| 成人免费视频一区二区三区| 日韩亚洲AV无码一区二区不卡| 国产精品一区二区AV麻豆| 无码人妻久久一区二区三区免费| 日韩一区二区三区视频| 亚洲日韩AV一区二区三区四区| 大屁股熟女一区二区三区| 日韩一区二区免费视频| 精品人妻AV一区二区三区| 99国产精品一区二区| 一区二区三区四区国产| 日本一区二三区好的精华液 | 一区二区三区在线|日本| 亚洲日韩精品国产一区二区三区| 亚洲av无码一区二区三区乱子伦| 中文字幕日韩人妻不卡一区| 无码精品久久一区二区三区| 夜夜高潮夜夜爽夜夜爱爱一区| 久久国产精品无码一区二区三区| 日本在线一区二区| 久久99热狠狠色精品一区| 久久国产精品免费一区二区三区| 鲁大师成人一区二区三区| 国产萌白酱在线一区二区| 天堂Av无码Av一区二区三区| 亚洲AV一区二区三区四区| 亚洲AV噜噜一区二区三区 | 日韩一区二区电影| 国产一区麻豆剧传媒果冻精品 | 无码aⅴ精品一区二区三区| 久久无码AV一区二区三区| 精品国产乱子伦一区二区三区| 亚洲欧美一区二区三区日产| 精品成人乱色一区二区| 亲子乱av一区区三区40岁|