Bootstrap

Element-UI源码——Layout布局

Layout布局

el-row

文件位置

  • Element-ui>packages>row>src>row.js
  • Element-ui>packages>theme-chalk>src>row.scss

Js代码

export default {
  //组件的名字
  name: 'ElRow',
	//element-ui自定义的属性可以通过this.$options.componentName获得
  componentName: 'ElRow',

  props: {
    tag: {
      //自定义元素标签 默认为div标签 可以修改
      type: String,
      default: 'div'
    },
    //栅格间隔 px
    gutter: Number,
    //布局模式
    type: String,
    //flex 布局下的水平排列方式
    justify: {
      type: String,
      default: 'start'
    },
  	//flex 布局下的垂直排列方式
    align: String
  },

  computed: {
    style() {
      const ret = {};
      if (this.gutter) {
        //左右设置一个-gutter/2的值 因为gutter在左右加上了padding-left和padding-right
       // 这样会导致两边没有对齐父元素,所以加上负margin,对齐两侧
        ret.marginLeft = `-${this.gutter / 2}px`;
        ret.marginRight = ret.marginLeft;
      }
      return ret;
    }
  },
//通过渲染函数的形式编写
  render(h) {
    //第一个参数:标签
    //第二个参数:配置 与模板中属性对应的数据对象
    //第三个参数:子虚拟节点 插槽中的内容 写在el-row标签内部的部分
    return h(this.tag, {
      //class el-row is-justify-xx is-align-xx el-row--flex
      class: [
        'el-row',
        this.justify !== 'start' ? `is-justify-${this.justify}` : '',
        this.align ? `is-align-${this.align}` : '',
        { 'el-row--flex': this.type === 'flex' }
      ],
      //上面的计算属性
      style: this.style
    }, this.$slots.default);
  }
};

Row Attributes

参数说明类型可选值默认值
gutter栅格间隔number0
type布局模式,可选 flex,现代浏览器下有效string
justifyflex 布局下的水平排列方式stringstart/end/center/space-around/space-betweenstart
alignflex 布局下的垂直排列方式stringtop/middle/bottom
tag自定义元素标签string*div

样式文件

@import "common/var";
@import "mixins/mixins";
@import "mixins/utils";
@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;
    }

    @include when(align-top) {
      align-items: flex-start;
    }

    @include when(align-middle) {
      align-items: center;
    }
    @include when(align-bottom) {
      align-items: flex-end;
    }
  }

}


@include b 混入了mixins/mixins中的b其中在config.scss定义了 BEM的Class命名风格

$namespace: 'el';  组件名 el-row 
$element-separator: '__';  元素子元素 加上__ el-input__inner
$modifier-separator: '--';  修饰符 el-button-primary
$state-prefix: 'is-'; 状态的前缀 is-disabled
mixins/mixins文件
@mixin b($block) {
  定义变量
  $B: $namespace+'-'+$block !global;
	使用变量
  .#{$B} {
    @content;
  }
}

@include utils-clearfix 混入utils.scss 中的utils-clearfix 清除浮动

@mixin utils-clearfix {
  $selector: &;

  @at-root {
    #{$selector}::before,
    #{$selector}::after {
      display: table;
      content: "";
    }
    #{$selector}::after {
      clear: both
    }
  }
}

@include m 混入mixins中的m

@mixin m($modifier) {
  $selector: &;
  $currentSelector: "";
  遍历修饰符 生成class名并拼接 el-row--flex
  @each $unit in $modifier {
    $currentSelector: #{$currentSelector + & + $modifier-separator + $unit + ","};
  }

  @at-root {
    #{$currentSelector} {
      @content;
    }
  }
}

@include when的混入,其实就是用来生成is-开头表示状态用的class

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

el-col

文件位置

  • Element-ui>packages>row>src>col.js
  • Element-ui>packages>theme-chalk>src>col.scss

js代码

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: {
    gutter() {
      //获取父对象
      let parent = this.$parent;
      //一直向上寻找父对象 直到找到父对象名字为ElRow也就是el-row
      while (parent && parent.$options.componentName !== 'ElRow') {
        parent = parent.$parent;
      }
      //获取父对象上的gutter 栅格间隔
      return parent ? parent.gutter : 0;
    }
  },
  render(h) {
    let classList = [];
    let style = {};
		//给左右两侧加上padding
    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);
  }
};

Col Attributes

参数说明类型可选值默认值
span栅格占据的列数number24
offset栅格左侧的间隔格数number0
push栅格向右移动格数number0
pull栅格向左移动格数number0
xs<768px 响应式栅格数或者栅格属性对象number/object (例如: {span: 4, offset: 4})
sm≥768px 响应式栅格数或者栅格属性对象number/object (例如: {span: 4, offset: 4})
md≥992px 响应式栅格数或者栅格属性对象number/object (例如: {span: 4, offset: 4})
lg≥1200px 响应式栅格数或者栅格属性对象number/object (例如: {span: 4, offset: 4})
xl≥1920px 响应式栅格数或者栅格属性对象number/object (例如: {span: 4, offset: 4})
tag自定义元素标签string*div

样式文件

@import "./common/var.scss";
@import "./mixins/mixins.scss";
每一个el-col开头的元素设置了左浮动和border-box属性
[class*="el-col-"] {
  float: left;
  box-sizing: border-box;
}

.el-col-0 {
  display: none;
}
循环从0-24设置span、offset、pull、push的样式
@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%;
  }
}

@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%;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

res的混入接收两个参数,$key表示传入响应式的key值(xs、sm等)

/* Break-points
 -------------------------- */
@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 ,会使用默认值 map,会使用默认值map,会使用默认值–breakpoints

/* Break-point
--------------------------*/
$--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)
);

;