element-ui源码阅读-Layout 布局

Layout 布局通过基础的 24 分栏,迅速简便地创建布局。只需引用rowcol组件,就能快速的创建布局,基于24等分的原理,可以设置各个col所占的等分,使布局变得更简单。Layout 还参照了 Bootstrap 的 响应式设计,预设了五个响应尺寸:xssmmdlgxl。通过源码阅读,来了解下element-ui源码中是怎么实现分栏布局和响应式布局的。


  

1. row组件

el-row组件的代码相对比较简单,使用的是函数式组件,根据传入的标签来创建一个容器,默认为div容器,然后再根据传入的布局类型排列方式栅格间隔等参数来设置对应的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可以理解成一个容器,在element-ui中将窗口划分24等分,每一等分可以用一个el-col来添加内容,也可以为每一个el-col设置占多少等份,或者偏移多少份。其js的源码相对比较简单,就是简单的创建元素,为元素设置对应的样式。其核心主要是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 = {};

    // 设置栅格间隔的样式
    if (this.gutter) {
      style.paddingLeft = this.gutter / 2 + 'px';
      style.paddingRight = style.paddingLeft;
    }

    //根据传递的,span,offset,pull,push等属性值,生成相应的样式名称
    ['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]}`
        );
      }
    });

    //根据传递的响应式属性生成相应的样式名称
    ['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]}`
          );
        });
      }
    });

    // 创建元素,并设置样式
    return h(this.tag, {
      class: ['el-col', classList],
      style
    }, this.$slots.default);
  }
};

2.2 样式介绍

el-col组件的重点主要是样式相关的,实现分栏和响应式的核心都是由样式来决定的,下面主要讲下怎么进行分栏和实现响应式。

2.1 24等份

el-col的核心是将el-row分成 24 等份来迅速简便地创建布局。其平分原理主要是使用百分比来做为元素的宽度,使用sass中的for来循环的生成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:该指令可以在限制的范围内重复输出格式,每次按要求(变量的值)对输出结果做出变动。这个指令包含两种格式:@for $var from through ,或者@for $var from to ,区别在于 throughto 的含义:当使用 through 时,条件范围包含的值,而使用 to时条件范围只包含 的值不包含 的值。

2.2 响应式布局

响应式布局主要是使用media,在不同屏幕下设置对应的样式,el-col主要设置了768px992px1200px1920px等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),
);

设置好对应的屏幕尺寸后,再根据传入的参数来生成对应的css样式代码,源码中使用的是一个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}`";
  }
}
  • map-has-key:用于判断字典中是否包含了对应的key
  • inspect:返回一个字符串的表示形式,value 是一个 sass 表达式。

你可能感兴趣的:(element-ui源码阅读-Layout 布局)