实现vue栅格系统Row,Col组件

748 阅读5分钟

概述

在前端布局中,栅格系统还是很常见的,对于响应式布局,尤为重要,下面记录一下实现vue栅格系统组件。 我们采用了24栅格系统,将区域进行24等分,这样可以轻松应对大部分布局问题。使用栅格系统进行网页布局,可以使页面排版美观、舒适。(参考多数组件库的实现以及经典的bootstrap)

定义了两个概念,行row和列col,具体使用方法如下:

  • 使用row在水平方向创建一行
  • 将一组col插入在row
  • 在每个col中,键入自己的内容
  • 通过设置colspan参数,指定跨越的范围,其范围是1到24
  • 每个row中的col总和应该为24

image.png 下面的实现,参考iview组件库的栅格系统插件中的使用来实现的,多数情况下,使用方式是一致的。无非是实现方式的不同。

实现

文件目录

image.png

Row.vue

<template>
  <div class="g-row" :style="rowStyle">
    <slot></slot>
  </div>
</template>

<script>
export default {
  // 将Row组件注入到col组件中
  provide() {
    return {
      rowInstance: this,
    };
  },
  props: {
    // 间隙
    gutter: {
      type: [String, Number],
    },
    // 对应弹性布局justify-content
    justify: {
      type: String,
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return [
          "start",
          "end",
          "center",
          "space-around",
          "space-between",
        ].includes(value);
      },
    },
    // 对应弹性布局中align-items
    align: {
      type: String,
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ["flex-start", "center", "flex-end", "stretch"].includes(value);
      },
    },
  },
  computed: {
    // style属性
    rowStyle() {
      return {
        marginLeft: -this.gutter / 2 + "px",
        marginRight: -this.gutter / 2 + "px",
        justifyContent: this.justify,
        alignItems: this.align,
      };
    },
  },
};
</script>

<style lang="less">
.g-row {
  display: flex;
  flex-wrap: wrap;
}
</style>

Col.vue

<template>
  <div :class="colClass" :style="colStyle">
    <slot></slot>
  </div>
</template>

<script>
export default {
  // Row组件的实例
  inject: ["rowInstance"],
  props: {
    // 所占具体空间份数
    span: {
      type: [String, Number],
    },
    // 对应弹性布局汇中的order属性
    order: {
      type: [String, Number],
    },
    // 偏移量
    offset: {
      type: [String, Number],
    },
    // 对应弹性布局flex属性
    flex: {
      type: [String, Number],
    },
    // 下面为响应式布局属性
    xs: {
      // <576px
      type: [String, Number],
    },
    sm: {
      // ≥576px
      type: [String, Number],
    },
    md: {
      // 	≥768px
      type: [String, Number],
    },
    lg: {
      // 	≥992px
      type: [String, Number],
    },
    xl: {
      // ≥1200px
      type: [String, Number],
    },
    xxl: {
      // 	≥1600px
      type: [String, Number],
    },
  },
  data() {
    return {};
  },
  computed: {
    colClass() {
      return [
        "g-col",
        this.xs ? `g-col-xs-${this.xs}` : "",
        this.sm ? `g-col-sm-${this.sm}` : "",
        this.md ? `g-col-md-${this.md}` : "",
        this.lg ? `g-col-lg-${this.lg}` : "",
        this.xl ? `g-col-xl-${this.xl}` : "",
        this.xxl ? `g-col-xxl-${this.xxl}` : "",
      ];
    },
    // style
    colStyle() {
      return {
        flex: this.span
          ? `calc(100% / 24 * ${this.span})`
          : this.flex
          ? this.flex
          : "",
        maxWidth: this.span ? `calc(100% / 24 * ${this.span})` : "none",
        paddingLeft: this.rowInstance.gutter / 2 + "px",
        paddingRight: this.rowInstance.gutter / 2 + "px",
        order: this.order * 1,
        marginLeft: this.offset ? `calc(100% / 24 * ${this.offset})` : "",
      };
    },
  },
};
</script>

index.js

import Row from "./Row.vue";
import Col from "./Col.vue";

export { Row, Col };

使用

App.vue

<template>
  <div class="app">
    <div class="row">
      <Row :gutter="100" align="bottom" justify="end">
        <Col span="6" order="4"><div class="content one">1</div></Col>
        <Col span="6" order="3"><div class="content two">2</div></Col>
        <Col span="6" order="6"><div class="content three">3</div></Col>
      </Row>
    </div>
    <div class="row">
      <Row>
        <Col :xs="24" :sm="4" :md="2" :lg="8" :xxl="24"
          ><div class="content one">1</div></Col
        >
        <Col :xs="24" :sm="16" :md="12" :lg="8" :xxl="24"
          ><div class="content two">2</div></Col
        >
        <Col :xs="24" :sm="4" :md="6" :lg="8" :xxl="24"
          ><div class="content three">3</div></Col
        >
      </Row>
    </div>
  </div>
</template>

<script>
import { Row, Col } from "./components/Row/index.js";
export default {
  components: { Row, Col },
};
</script>

<style lang="less">
* {
  margin: 0;
  padding: 0;
}
.row {
  width: 70%;
  margin: 20px auto;
  border: 1px solid #000;
  overflow: hidden;
  height: 300px;
  .content {
    height: 30px;
    line-height: 30px;
  }
  .one {
    background-color: pink;
  }
  .two {
    background-color: #008c8c;
  }
  .three {
    background-color: greenyellow;
  }
  .four {
    background-color: rgb(122, 122, 218);
  }
}
</style>

common.less

//只要做响应式的配置,只列出部分类名


@media (max-width: 576px) {
  .g-col-xs-1 {
    flex: calc(100% / 24 * 1);
    max-width: calc(100% / 24 * 1);
  }
  .g-col-xs-2 {
    flex: calc(100% / 24 * 2);
    max-width: calc(100% / 24 * 2);
  }
  .g-col-xs-3 {
    flex: calc(100% / 24 * 3);
    max-width: calc(100% / 24 * 3);
  }
  .g-col-xs-4 {
    flex: calc(100% / 24 * 4);
    max-width: calc(100% / 24 * 4);
  }
  .g-col-xs-6 {
    flex: calc(100% / 24 * 6);
    max-width: calc(100% / 24 * 6);
  }
  .g-col-xs-8 {
    flex: calc(100% / 24 * 8);
    max-width: calc(100% / 24 * 8);
  }
  .g-col-xs-12 {
    flex: calc(100% / 24 * 12);
    max-width: calc(100% / 24 * 12);
  }
  .g-col-xs-16 {
    flex: calc(100% / 24 * 16);
    max-width: calc(100% / 24 * 16);
  }
  .g-col-xs-24 {
    flex: calc(100% / 24 * 24);
    max-width: calc(100% / 24 * 24);
  }
}
@media (min-width: 577px) {
  .g-col-sm-1 {
    flex: calc(100% / 24 * 1);
    max-width: calc(100% / 24 * 1);
  }
  .g-col-sm-2 {
    flex: calc(100% / 24 * 2);
    max-width: calc(100% / 24 * 2);
  }
  .g-col-sm-3 {
    flex: calc(100% / 24 * 3);
    max-width: calc(100% / 24 * 3);
  }
  .g-col-sm-4 {
    flex: calc(100% / 24 * 4);
    max-width: calc(100% / 24 * 4);
  }
  .g-col-sm-6 {
    flex: calc(100% / 24 * 6);
    max-width: calc(100% / 24 * 6);
  }
  .g-col-sm-8 {
    flex: calc(100% / 24 * 8);
    max-width: calc(100% / 24 * 8);
  }
  .g-col-sm-12 {
    flex: calc(100% / 24 * 12);
    max-width: calc(100% / 24 * 12);
  }
  .g-col-sm-16 {
    flex: calc(100% / 24 * 16);
    max-width: calc(100% / 24 * 16);
  }
  .g-col-sm-24 {
    flex: calc(100% / 24 * 24);
    max-width: calc(100% / 24 * 24);
  }
}
@media (min-width: 768px) {
  .g-col-md-1 {
    flex: calc(100% / 24 * 1);
    max-width: calc(100% / 24 * 1);
  }
  .g-col-md-2 {
    flex: calc(100% / 24 * 2);
    max-width: calc(100% / 24 * 2);
  }
  .g-col-md-3 {
    flex: calc(100% / 24 * 3);
    max-width: calc(100% / 24 * 3);
  }
  .g-col-md-4 {
    flex: calc(100% / 24 * 4);
    max-width: calc(100% / 24 * 4);
  }
  .g-col-md-6 {
    flex: calc(100% / 24 * 6);
    max-width: calc(100% / 24 * 6);
  }
  .g-col-md-8 {
    flex: calc(100% / 24 * 8);
    max-width: calc(100% / 24 * 8);
  }
  .g-col-md-12 {
    flex: calc(100% / 24 * 12);
    max-width: calc(100% / 24 * 12);
  }
  .g-col-md-16 {
    flex: calc(100% / 24 * 16);
    max-width: calc(100% / 24 * 16);
  }
  .g-col-md-24 {
    flex: calc(100% / 24 * 24);
    max-width: calc(100% / 24 * 24);
  }
}
@media (min-width: 992px) {
  .g-col-lg-1 {
    flex: calc(100% / 24 * 1);
    max-width: calc(100% / 24 * 1);
  }
  .g-col-lg-2 {
    flex: calc(100% / 24 * 2);
    max-width: calc(100% / 24 * 2);
  }
  .g-col-lg-3 {
    flex: calc(100% / 24 * 3);
    max-width: calc(100% / 24 * 3);
  }
  .g-col-lg-4 {
    flex: calc(100% / 24 * 4);
    max-width: calc(100% / 24 * 4);
  }
  .g-col-lg-6 {
    flex: calc(100% / 24 * 6);
    max-width: calc(100% / 24 * 6);
  }
  .g-col-lg-8 {
    flex: calc(100% / 24 * 8);
    max-width: calc(100% / 24 * 8);
  }
  .g-col-lg-12 {
    flex: calc(100% / 24 * 12);
    max-width: calc(100% / 24 * 12);
  }
  .g-col-lg-16 {
    flex: calc(100% / 24 * 16);
    max-width: calc(100% / 24 * 16);
  }
  .g-col-lg-24 {
    flex: calc(100% / 24 * 24);
    max-width: calc(100% / 24 * 24);
  }
}
@media (min-width: 1200px) {
  .g-col-xl-1 {
    flex: calc(100% / 24 * 1);
    max-width: calc(100% / 24 * 1);
  }
  .g-col-xl-2 {
    flex: calc(100% / 24 * 2);
    max-width: calc(100% / 24 * 2);
  }
  .g-col-xl-3 {
    flex: calc(100% / 24 * 3);
    max-width: calc(100% / 24 * 3);
  }
  .g-col-xl-4 {
    flex: calc(100% / 24 * 4);
    max-width: calc(100% / 24 * 4);
  }
  .g-col-xl-6 {
    flex: calc(100% / 24 * 6);
    max-width: calc(100% / 24 * 6);
  }
  .g-col-xl-8 {
    flex: calc(100% / 24 * 8);
    max-width: calc(100% / 24 * 8);
  }
  .g-col-xl-12 {
    flex: calc(100% / 24 * 12);
    max-width: calc(100% / 24 * 12);
  }
  .g-col-xl-16 {
    flex: calc(100% / 24 * 16);
    max-width: calc(100% / 24 * 16);
  }
  .g-col-xl-24 {
    flex: calc(100% / 24 * 24);
    max-width: calc(100% / 24 * 24);
  }
}
@media (min-width: 1600px) {
  .g-col-xxl-1 {
    flex: calc(100% / 24 * 1);
    max-width: calc(100% / 24 * 1);
  }
  .g-col-xxl-2 {
    flex: calc(100% / 24 * 2);
    max-width: calc(100% / 24 * 2);
  }
  .g-col-xxl-3 {
    flex: calc(100% / 24 * 3);
    max-width: calc(100% / 24 * 3);
  }
  .g-col-xxl-6 {
    flex: calc(100% / 24 * 6);
    max-width: calc(100% / 24 * 6);
  }
  .g-col-xxl-8 {
    flex: calc(100% / 24 * 8);
    max-width: calc(100% / 24 * 8);
  }
  .g-col-xxl-12 {
    flex: calc(100% / 24 * 12);
    max-width: calc(100% / 24 * 12);
  }
  .g-col-xxl-24 {
    flex: calc(100% / 24 * 24);
    max-width: calc(100% / 24 * 24);
  }
}

总结

栅格系统组件,更多在于css的用法,以及弹性布局和盒模型的运用。