element-ui源碼閱讀-Layout 布局

Layout 布局通過(guò)基礎(chǔ)的 24 分欄,迅速簡(jiǎn)便地創(chuàng)建布局。只需引用rowcol組件,就能快速的創(chuàng)建布局,基于24等分的原理,可以設(shè)置各個(gè)col所占的等分,使布局變得更簡(jiǎn)單。Layout 還參照了 Bootstrap 的 響應(yīng)式設(shè)計(jì),預(yù)設(shè)了五個(gè)響應(yīng)尺寸:xssm、mdlgxl。通過(guò)源碼閱讀,來(lái)了解下element-ui源碼中是怎么實(shí)現(xiàn)分欄布局和響應(yīng)式布局的。

<el-row>
  <el-col :span="12"><div class="grid-content bg-purple"></div></el-col>
  <el-col :span="12"><div class="grid-content bg-purple-light"></div></el-col>
</el-row>

1. row組件

el-row組件的代碼相對(duì)比較簡(jiǎn)單,使用的是函數(shù)式組件,根據(jù)傳入的標(biāo)簽來(lái)創(chuàng)建一個(gè)容器,默認(rèn)為div容器,然后再根據(jù)傳入的布局類(lèi)型,排列方式柵格間隔等參數(shù)來(lái)設(shè)置對(duì)應(yīng)的CSS。代碼如下所示:

export default {
  name: 'ElRow',

  componentName: 'ElRow',

  props: {
    tag: {
      type: String,
      default: 'div'
    },
    gutter: Number,
    type: String,
    justify: {
      type: String,
      default: 'start'
    },
    align: {
      type: String,
      default: 'top'
    }
  },

  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',
        this.justify !== 'start' ? `is-justify-${this.justify}` : '',
        this.align !== 'top' ? `is-align-${this.align}` : '',
        { 'el-row--flex': this.type === 'flex' }
      ],
      style: this.style
    }, this.$slots.default);
  }
};

2.col組件

2.1組件介紹

el-row可以理解成一個(gè)容器,在element-ui中將窗口劃分24等分,每一等分可以用一個(gè)el-col來(lái)添加內(nèi)容,也可以為每一個(gè)el-col設(shè)置占多少等份,或者偏移多少份。其js的源碼相對(duì)比較簡(jiǎn)單,就是簡(jiǎn)單的創(chuàng)建元素,為元素設(shè)置對(duì)應(yīng)的樣式。其核心主要是CSS代碼。

export default {
  name: 'ElCol',

  props: {
    span: {
      type: Number,
      default: 24
    },
    tag: {
      type: String,
      default: 'div'
    },
    offset: Number,
    pull: Number,
    push: Number,
    xs: [Number, Object],
    sm: [Number, Object],
    md: [Number, Object],
    lg: [Number, Object],
    xl: [Number, Object]
  },

  computed: {
    /**
     * 獲取父組件'el-row'的柵格間格
     */
    gutter() {
      let parent = this.$parent;
      while (parent && parent.$options.componentName !== 'ElRow') {
        parent = parent.$parent;
      }
      return parent ? parent.gutter : 0;
    }
  },
  render(h) {
    let classList = [];
    let style = {};

    // 設(shè)置柵格間隔的樣式
    if (this.gutter) {
      style.paddingLeft = this.gutter / 2 + 'px';
      style.paddingRight = style.paddingLeft;
    }

    //根據(jù)傳遞的,span,offset,pull,push等屬性值,生成相應(yīng)的樣式名稱(chēng)
    ['span', 'offset', 'pull', 'push'].forEach(prop => {
      if (this[prop] || this[prop] === 0) {
        classList.push(
          prop !== 'span'
            ? `el-col-${prop}-${this[prop]}`
            : `el-col-${this[prop]}`
        );
      }
    });

    //根據(jù)傳遞的響應(yīng)式屬性生成相應(yīng)的樣式名稱(chēng)
    ['xs', 'sm', 'md', 'lg', 'xl'].forEach(size => {
      if (typeof this[size] === 'number') {
        classList.push(`el-col-${size}-${this[size]}`);
      } else if (typeof this[size] === 'object') {
        let props = this[size];
        Object.keys(props).forEach(prop => {
          classList.push(
            prop !== 'span'
              ? `el-col-${size}-${prop}-${props[prop]}`
              : `el-col-${size}-${props[prop]}`
          );
        });
      }
    });

    // 創(chuàng)建元素,并設(shè)置樣式
    return h(this.tag, {
      class: ['el-col', classList],
      style
    }, this.$slots.default);
  }
};

2.2 樣式介紹

el-col組件的重點(diǎn)主要是樣式相關(guān)的,實(shí)現(xiàn)分欄和響應(yīng)式的核心都是由樣式來(lái)決定的,下面主要講下怎么進(jìn)行分欄和實(shí)現(xiàn)響應(yīng)式。

2.1 24等份

el-col的核心是將el-row分成 24 等份來(lái)迅速簡(jiǎn)便地創(chuàng)建布局。其平分原理主要是使用百分比來(lái)做為元素的寬度,使用sass中的for來(lái)循環(huán)的生成24等分,如下所示:

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

  .el-col-offset-#{$i} {
    margin-left: (1 / 24 * $i * 100) * 1%;
  }

  .el-col-pull-#{$i} {
    position: relative;
    right: (1 / 24 * $i * 100) * 1%;
  }

  .el-col-push-#{$i} {
    position: relative;
    left: (1 / 24 * $i * 100) * 1%;
  }
}

for:該指令可以在限制的范圍內(nèi)重復(fù)輸出格式,每次按要求(變量的值)對(duì)輸出結(jié)果做出變動(dòng)。這個(gè)指令包含兩種格式:@for $var from <start> through <end>,或者@for $var from <start> to <end>,區(qū)別在于 throughto 的含義:當(dāng)使用 through 時(shí),條件范圍包含<start><end>的值,而使用 to時(shí)條件范圍只包含 <start> 的值不包含 <end>的值。

2.2 響應(yīng)式布局

響應(yīng)式布局主要是使用media,在不同屏幕下設(shè)置對(duì)應(yīng)的樣式,el-col主要設(shè)置了768px、992px、1200px1920px等4種寬度的屏幕:

$--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)
);

$--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),
);

設(shè)置好對(duì)應(yīng)的屏幕尺寸后,再根據(jù)傳入的參數(shù)來(lái)生成對(duì)應(yīng)的css樣式代碼,源碼中使用的是一個(gè)res的混合器來(lái)生成的,如下所示:

@mixin res($key, $map: $--breakpoints) {
  // 循環(huán)斷點(diǎn)Map,如果存在則返回
  @if map-has-key($map, $key) {
    @media only screen and #{inspect(map-get($map, $key))} {
      @content;
    }
  } @else {
    @warn "Undefeined points: `#{$map}`";
  }
}
  • map-has-key:用于判斷字典中是否包含了對(duì)應(yīng)的key。
  • inspect:返回一個(gè)字符串的表示形式,value 是一個(gè) sass 表達(dá)式。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容