Element UI Layout源碼解析

前言

layou組件也是使用element框架經常使用的組件,通過24分欄,可以快捷的完成佈局構建。layout組件構成爲el-row和el-col ,分別代表行的容器和列的容器。

el-row

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

el-row的代碼相對較簡單。主要判斷是否是flex佈局,type屬性爲flex 啓用flex佈局。justify屬性是子元素的水平排列方式,與justify支持的屬性相同。 algin子元素垂直排列方式,支持top middle bottom。
計算屬性的style是row的左右margin 通過gutter 屬性計算出組件的負margin 。
gutter的作用是col組件之間產生間距,但是最左最右兩側的間距是0 所以這裏的負margin是抵消子組件col產生的最左和最右間距,最後通過render應用flex屬性和style屬性生成組件。

el-col

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;
      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'].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);
  }
};

計算屬性計算節點的gutter屬性, gutter是從父級el-row節點得到的 ,通過不斷獲取父元素找到el-row的位置。
render函數的gutter計算左右兩側的padding,產生間距。
span offset pull push等屬性主要是el-rol柵格的偏移格數,通過獲取props屬性寫入class改變。
xs sm md 等屬性與響應式佈局有關,也是寫入class去改變。對應的width在var.scss文件可以查看。
渲染函數render主要將的到屬性放入class屬性,然後通過模板字符串的方式將組建渲染。

結論

Layou組件有el-row和el-col組成,本質是將width寬度24等分,然後通過flex gutter offset等屬性計算class調整佈局。有幾個小技巧記錄下,1,在gutter計算時,通過父組件的負margin抵消子組件的padding 2,在css計算時,通過scss 支持的for循環,減少了代碼的重複,感興趣的同學可以自行查看。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章