element-ui[2.15.x]源码从开始到放弃(二)-布局和容器

238 阅读1分钟

上一章咱们说到哪了,md-loader那是十分了得,将markdown语法搞得是方便简洁,灵活多便。

我们接着上一章继续道来,咱们细说element-ui组件

布局

作为本章的开场组件el-rowel-col,他们的作用主要是对块进行分割排布

我来说说具体是怎么实现的

Row

Row组件是通过render函数来渲染

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

栅格间距gutter:通过计算属性定义了一个style属性,返回左右外边距为负gutterpx的对象,这样div的整体宽度就为width+gutter * 2,Col也是均分着额外的gutter

包裹标签tag:从上面的代码也能看出它是用来定义Row组件最外层标签类型的

type:是否定义为flex

justify:定义相关的class,来进行flex横轴布局

align:定义相关的class,来进行flex纵轴布局

Col

Col组件是通过render函数来渲染,这个布局组件好多样式都是通过class定义的,通过vue的$parent获取到外层Row组件的gutter,以gutterpx为Col最外层标签的左右内边距

if (this.gutter) {
      style.paddingLeft = this.gutter / 2 + 'px';
      style.paddingRight = style.paddingLeft;
}

栅格占据的列数span栅格左侧的间隔格数offset栅格向右移动格数push栅格向左移动格数pull被定义到数组,通过遍历以class属性添加到Col最外层标签上

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

<768px xs≥768px sm≥992px md≥1200px lg≥1920px xl首先判断是不是数值,如果不是数值走另一套生成class的规则,最后根据props和Row的gutter属性,生成相应的dom返回

 ['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);

容器

容器的制作非常简单,简单到我不想单独讲

Container

根据父组件传过来的direction和默认插槽中的组件是否有Header或Footer,来决定是否将标签<section>用flex的基准线改为y轴

isVertical() {
        if (this.direction === 'vertical') {
          return true;
        } else if (this.direction === 'horizontal') {
          return false;
        }
        return this.$slots && this.$slots.default
          ? this.$slots.default.some(vnode => {
            const tag = vnode.componentOptions && vnode.componentOptions.tag;
            return tag === 'el-header' || tag === 'el-footer';
          })
          : false;
      }

Header,Main,Aside,Footer

其他组件没有太多的东西,应该主要是为了语义化,使用了<header><main><aside><footer>标签,通过父组件传入的height,width决定它的整体大小