Element-ui Layout布局(Row和Col组件)的实现

目录
  • 基本说明以及用法
  • Row组件的分析
    • render函数
    • 源码分析
  • Col组件的分析
    • 组件分析
    • 响应式布局

我们在实际开发中遇到一些布局的时候会用到Layout布局,这个布局只要配置一些参数就能够达到很好的布局效果甚至可以响应式,那里面的具体是怎么实现的呢,让我们去剖开Element-UI的源码,学习里面的一些细节吧。

基本说明以及用法

Element-UI的Layout布局是通过基础的24分栏,迅速简便地创建布局。根据不同的组合,很快的就能够生成一个很美观的响应式布局。具体的用法如下:

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

由上述的示例代码可以看出Row组件主要是创建每行分栏的布局方式,比如之间的一些间隔、对齐方式等。而Col则创建每个分栏,分栏的长度、偏移量等。我们可以进行自由组合每个分栏,从而达到一种响应式效果。

Row组件的分析

render函数

我们都知道vue除了可以使用template模板编写组件外,有时候我们还可以直接使用render函数去编写一个组件。因为template模板最终也是编译成了render函数。
为什么会有render函数的写法?比如现在有个需求:根据动态的level生成从h1-h6字体大小的标题的时候,我们如果使用template去实现的话我们页面中可能会出现很多类似这样的伪代码:

<template>
   <h1 v-if="level === 1">
    <slot></slot>
  </h1>
  <h2 v-else-if="level === 2">
    <slot></slot>
  </h2>
  <h3 v-else-if="level === 3">
    <slot></slot>
  </h3>
  <h4 v-else-if="level === 4">
    <slot></slot>
  </h4>
  <h5 v-else-if="level === 5">
    <slot></slot>
  </h5>
  <h6 v-else-if="level === 6">
    <slot></slot>
  </h6>
</template>

但是如果是使用render函数则是比较简单:

Vue.component('anchored-heading', {
  render: function (createElement) {
    return createElement(
      'h' + this.level,   // 标签名称
      this.$slots.default // 子节点数组
    )
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})

这里还有一个代码优化点是。this.$slots.default存储的就是插槽内容,不需要写那么多遍。

源码分析

Row组件的源码比较简单,因为我们可以通过tag这个prop对其指定一个渲染标签,所以组件是直接使用render渲染函数进行编写。 render函数部分如下:

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

如上的源码可以得出Row主要是控制class名来进行控制内容布局的。这里有gutter属性能够控制行内列的间隔数。如果说我们设置为gutter=20,那么每个列项都进行左右间距10px,那么就会出现个问题:第一个列项跟最后一个列项会出现左右的间距。那该如何让第一个跟最后一个左右间隔去掉这个10px呢?Row的处理方案是这个行左右各偏-10px,所以用了一个计算属性来设置样式:

computed: {
    style() {
      const ret = {};
      if (this.gutter) {
        ret.marginLeft = `-${this.gutter / 2}px`;
        ret.marginRight = ret.marginLeft;
      }
      return ret;
    }
  },

Col组件的分析

组件分析

Col主要是为了设置每一列的长度以及偏移量。主要的属性是span、offset;同样这个组件也是采用render函数去编写,首先我们看如何通过span、offset去控制列的,源码如下:

render(h) {
    let classList = [];
    let style = {};
    ...

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

    ...

    return h(this.tag, {
      class: ['el-col', classList],
      style
    }, this.$slots.default);
  }

从这可以看出,col的列宽是通过不同class名去做控制的。我们找到对应的.scss文件,发现他使用了sass@for循环语句去计算不同格子的宽度:

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

同理offset也是使用相同的逻辑。这样我们就可以根据不同的span、跟offset混合组合不同风布局了,是不是感觉背后的逻辑是如此的简单呢。我们再思考一个问题就是如果我们要控制一组相同的列宽间隔,需要一个个的去做设置么?答案是不用的,我们可以借助上述的Row组件中的gutter属性去做统一设置。那怎么实现的呢?源码如下:

 computed: {
    gutter() {
      let parent = this.$parent;
      while (parent && parent.$options.componentName !== 'ElRow') {
        parent = parent.$parent;
      }
      return parent ? parent.gutter : 0;
    }
  }

我们通过往上遍历父组件,如果父组件的组件名为ElRow,则取到gutter值,然后让组件左右内边距设置对应的值就好了:

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

这样我们就解决了统一列宽设置的问题;

响应式布局

这里我们用到了css3中的媒体查询来进行响应式布局,相应尺寸分别是xs、sm、md、lg 和 xl。使用代码如下:

<el-row :gutter="10">
  <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1"><div class="grid-content bg-purple"></div></el-col>
  <el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11"><div class="grid-content bg-purple-light"></div></el-col>
  <el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11"><div class="grid-content bg-purple"></div></el-col>
  <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1"><div class="grid-content bg-purple-light"></div></el-col>
</el-row>

说明:xs:<768px 响应式栅格数或者栅格属性对象,sm:≥768px 响应式栅格数或者栅格属性对象,md:≥992px 响应式栅格数或者栅格属性对象,lg:≥1200px 响应式栅格数或者栅格属性对象,xl:≥1920px 响应式栅格数或者栅格属性对象.

背后的逻辑就是不同屏幕尺寸所展示的格子数是不一样的,而且是根据屏幕宽度进行响应式。首先,我们看是如何进行不同的class绑定的:

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

这里面xs等属性也是可以使用对象。所以会有个处理对象的逻辑;以上的js处理的逻辑比较简单,我们再看一下css是怎么处理这个媒体查询的逻辑的。
在分析css的时候,我们先了解一个概念,那就是sass中的内置方法map-get。map-get($map,$key)函数的作用就是可以通过$key取到对应的value值,可以理解为就是一个映射关系。如果不存在则不会编译对应的css。举个:

$social-colors: (
    dribble: #ea4c89,
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
);
.btn-dribble{
  color: map-get($social-colors,facebook);
}
// 编译后
.btn-dribble {
  color: #3b5998;
}

第二个是sass内置方法inspect(value),这个方法就是一个返回一个字符串的表示形式,value是一个sass表达式。举个:

$--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)
);
@mixin res($breakpoint){
  $query:map-get($--breakpoints,$breakpoint)
  @if not $query {
    @error 'No value found for `#{$breakpoint}`. Please make sure it is
    defined in `$breakpoints` map.';
  }
  @media #{inspect($query)}
   {
    @content;
   }
}
.element {
  color: #000;

  @include res(sm) {
    color: #333;
  }
}
// 编译后的css

.element {
  color: #000;
}
@media (min-width: 768px) {
  .element {
    color: #333;
  }
}

好了,我相信聪明的你已经很好的掌握了这两个方法,那我们去看一下element是怎么去实现的吧。
其实上述的第二个例子已经道出一二,我们看一下源码:

$--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)
);
/* 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}`";
  }
}
@include res(xs) {
  @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%;
    }
  }
}
@include res(sm) {
  ...
}
@include res(md) {
  ...
}
@include res(lg) {
  ...
}
@include res(xl) {
  ...
}

这样我们就会在不同的屏幕尺寸下进行不同的长度以及间隔的展示了,这样去写我们的媒体查询是不是很棒呢?

到此这篇关于Element-ui Layout布局(Row和Col组件)的实现的文章就介绍到这了,更多相关Element Layout布局内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Element-UI 使用el-row 分栏布局的教程

    使用多个卡片显示的时候,并且要求当列数到一定数目的时候,要自动换行,el-container 布局就满足了需求了,就要用到el-row 布局做分栏处理, 代码如下 <template> <el-row :gutter="20" class="el-row" type="flex" > <el-col :span="8" v-for = "(item,index) in apps"

  • element中el-container容器与div布局区分详解

    用于布局的容器组件,方便快速搭建页面的基本结构: el-container:外层容器.当子元素中包含 或 时,全部子元素会垂直上下排列,否则会水平左右排列. el-header:顶栏容器. el-aside:侧边栏容器. el-main:主要区域容器. el-footer:底栏容器. 以上组件采用了 flex 布局,elemen-ui官方文档链接: http://element-cn.eleme.io/#/zh-CN/component/container 此外,el-container 的子元

  • Element-ui Layout布局(Row和Col组件)的实现

    目录 基本说明以及用法 Row组件的分析 render函数 源码分析 Col组件的分析 组件分析 响应式布局 我们在实际开发中遇到一些布局的时候会用到Layout布局,这个布局只要配置一些参数就能够达到很好的布局效果甚至可以响应式,那里面的具体是怎么实现的呢,让我们去剖开Element-UI的源码,学习里面的一些细节吧. 基本说明以及用法 Element-UI的Layout布局是通过基础的24分栏,迅速简便地创建布局.根据不同的组合,很快的就能够生成一个很美观的响应式布局.具体的用法如下: <e

  • 基于element UI input组件自行封装“数字区间”输入框组件的问题及解决

    目录 问题描述 实现效果 实现代码 问题描述 在开发时遇到一个数字区间输入框的需求,如下图: 项目使用的是vue,组件库用的是element UI,但是element UI并没有提供数字区间组件,只提供了InputNumber 计数器输入框,如果用两个计数器输入框进行拼接也能满足需求,但是样式调试起来太过于复杂且不够灵活,不能令人满意,并且该数字区间输入框在其它界面也有这种需求,于是就在element input输入框的基础上自行封装了一个数字区间组件使用. 实现效果 实现效果如下: 使用方式如

  • 通过Element ui往页面上加一个分页导航条的方法

    需求 加入一个分页条,此分页条可以跳转页面,可以根据页码选择具体页面,可以设置当前页面的大小. 在element ui官网选择Pagination分页组件 进入element ui官网,然后选择一个合适的分页组件,如下图: UserList.vue组件的template模板中的分页组件的代码和效果 分页组件的代码如下图: 分页组件的效果如下图: 分页组件牵涉到的data数据和methods方法 分页组件牵涉到的data数据如下图: 分页组件牵涉到的methods方法如下图: 测试 首先进入首页,

  • Vue+Element UI实现下拉菜单的封装

    本文实例为大家分享了Vue+Element UI实现下拉菜单封装的具体代码,供大家参考,具体内容如下 1.效果图 先贴个效果图,菜单项没有做样式美化,图中显示的边框也是没有的(边框是外部容器的边框),其它的根据需要自己修改一下样式即可. 2.组件封装 组件的封装用到了CSS动画.定位.,以及Element UI提供的下拉菜单组件el-dropdown.代码如下, <template> <div class="all" @click="clickFire&qu

  • Vue2.5 结合 Element UI 之 Table 和 Pagination 组件实现分页功能

    2017年底了,总结了这一年多来的前端之路,Vue从入门到放弃,再二进宫,从 Vue1.0 持续跟踪到 Vue2.5.结合公司的一些实际项目,也封装了一些比较实用的组件. 由于现在公司管理平台主要运用Element UI,索性就结合组件Table 和 Pagination 封装了一个支持页面切换的Table组件,不啰嗦,直接上代码. 2.实现思路 2.1.Element UI 引入(整体引入) main.js // Element UI import Element from 'element-

  • React Native可复用 UI分离布局组件和状态组件技巧

    目录 引言 包装 Context.Provider 作为父组件 使用 Context Hook 来实现子组件 使用 React 顶层 API 动态设置样式 复用 Context,实现其它子组件 抽取共同状态逻辑 自由组合父组件与子组件 示例 引言 单选,多选,是很常见的 UI 组件,这里以它们为例,来讲解如何分离布局组件和状态组件,以实现较好的复用性. 假如我们要实现如下需求: 这类 UI 有如下特点: 不管是单选还是多选,都可以有网格布局,我们可以把这个网格布局单独抽离出来,放到一个独立的组件

  • jQuery布局插件UI Layout简介及使用方法

    UI Layout是一种基于jQuery的布局框架,项目主页http://layout.jquery-dev.net/.该框架的参考原型是ExtJS的border-layout,因此十分适用于将原有使用ExtJS的项目改造成jQuery项目.其核心是一个大小自适应的中心面板(必选),面板的上下左右四个方向可以放置可折叠.可缩放的面板(可选),各个面板可以添加任意数量的页眉和页脚面板.UI Layout支持内层布局的嵌套,任意块元素都可以当作布局的容器,最基本的布局容器是body. 基本使用方法:

  • Vue Element UI自定义描述列表组件

    本文实例为大家分享了Vue Element UI自定义描述列表组件的具体代码,供大家参考,具体内容如下 效果图 写在前面 写后台管理经常从列表点击查看详情,展示数据信息,Element UI虽然有表格组件,但是描述组件并没有,之前团队的成员遇到这种情况都自己去写样式,写起来也麻烦,而且每个人写出来的样式也不统一,破坏了项目的整体风格. 像是Ant Design UI就有描述组件,用起来特别舒服,所以索性自己结合Element UI的el-row和el-col自己写了一个. 实现哪些功能 1.每行

  • element UI upload组件上传附件格式限制方法

    如下所示: <el-upload :action="uploadUrl" ref="upload" :multiple="false" :on-change="fileChange" :before-upload="beforeUpload" :on-success="handleAvatarSuccess" :on-preview="file_click" c

  • 使用vue-cli导入Element UI组件的方法

    首先第一步,现在命令行中输入npm i element-ui,如: 接着在mian.js 中添加 import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI) 如:=> 最后在命令行输入npm run dev打开自己创建的项目就可以使用了 总结 以上所述是小编给大家介绍的使用vue-cli导入Element UI组件的方法,希望对大家有所帮助,如果大家有任何疑

随机推荐