代码重构,网格布局组件VueJS

时间:2019-07-14 22:08:36

标签: javascript vue.js vuejs2 nuxt.js

我正在研究vue.js / nuxt.js项目,应用Atomic Design方法,我需要做一个设置网格布局并使用CSS Grid Layout

我已经做了组件

GridLayout.vue

<template>
  <div class="grid">
    <style>
    {{ css }}
    </style>
    <slot />
  </div>
</template>

<script>
export default {
  props: {
    columns: String,
    rows: String,
    areas: String,
    gap: String,
    columnGap: String,
    rowGap: String,
    // breakpoints
    small: Object,
    medium: Object,
    large: Object
  },
  computed: {
    css () {
      let large = ''
      let finalStyle = ''

      // generic
      let generic = ''
      if (this.columns) generic += `grid-template-columns: ${this.columns};`
      if (this.rows) generic += `grid-template-rows: ${this.rows};`
      if (this.areas) generic += `grid-template-areas: "${this.areas}";`
      if (this.gap) generic += `grid-gap: ${this.gap};`
      if (this.columnGap) generic += `grid-column-gap: ${this.columnGap};`
      if (this.rowGap) generic += `grid-row-gap: ${this.rowGap};`
      finalStyle += ` .grid { ${generic} }`

      // small
      let small = ''
      if (this.small) {
        if (this.small.columns) small += `grid-template-columns: ${this.small.columns};`
        if (this.small.rows) small += `grid-template-rows: ${this.small.rows};`
        if (this.small.areas) small += `grid-template-areas: "${this.small.areas}";`
        if (this.small.gap) small += `grid-gap: ${this.small.gap};`
        if (this.small.columnGap) small += `grid-column-gap: ${this.small.columnGap};`
        if (this.small.rowGap) small += `grid-row-gap: ${this.small.rowGap};`
        finalStyle += `@media (max-width: 600px) { .grid { ${small} } } `
      }

      // medium
      let medium = ''
      if (this.medium) {
        if (this.medium.columns) medium += `grid-template-columns: ${this.medium.columns};`
        if (this.medium.rows) medium += `grid-template-rows: ${this.medium.rows};`
        if (this.medium.areas) medium += `grid-template-areas: "${this.medium.areas}";`
        if (this.medium.gap) medium += `grid-gap: ${this.medium.gap};`
        if (this.medium.columnGap) medium += `grid-column-gap: ${this.medium.columnGap};`
        if (this.medium.rowGap) medium += `grid-row-gap: ${this.medium.rowGap};`
        finalStyle += `@media (min-width: 600px) and (max-width: 992px) { .grid { ${medium} } } `
      }

      return finalStyle
    },
  },
}
</script>

<style lang="scss" scoped>
.grid {
  display: grid;
}
</style>

在任何页面上使用组件。vue

<template>
  <GridLayout
    columns="1fr 1fr 1fr 1fr"
    rows="auto"
    gap="10px"
    :medium="{
      columns: '1fr 1fr',
      rows:'auto auto'
    }"
    :small="{
      columns: '1fr',
      rows: 'auto auto auto auto',
    }"
  >
    <h1>1</h1>
    <h1>2</h1>
    <h1>3</h1>
    <h1>3</h1>
  </GridLayout>
</template>

<script>
import { GridLayout } from '@/components/bosons'

export default {
  components: {
    GridLayout
  }
}
</script>

问题

1-<style>中的样式标签<template>需要确定范围,仅应用于组件本身

2-每当我想要GridLayout组件的新属性(例如child align)时,都必须在计算的所有位置添加genericsmall,{{ 1}},medium

我该如何解决这些问题?也许让我的代码更小,更智能,更少重复

预先感谢

1 个答案:

答案 0 :(得分:0)

  1. 将样式标签放在模板中会产生警告;该警告说明了为什么应避免使用它:

      

    模板仅应负责将状态映射到UI。避免在模板中放置带有副作用的标签,例如<style>,因为它们不会被解析。

    您有一个SFC(单个文件组件),它已经定义了作用域样式块-将其用于任何预定义样式。对于动态生成的样式,您将必须使用样式绑定,例如:

    <div class="grid" :style="css">
      <slot />
    </div>
    ...
      computed: {
        css () {
          let generic = {}
          if (this.columns) generic['grid-template-columns'] = this.columns;
          if (this.columns) generic['grid-template-rows'] = this.rows;
          ...
          return [generic, large, mediumn, small];
    

    您可以在以下https://vuejs.org/v2/guide/class-and-style.html#Binding-Inline-Styles的Vue文档中了解有关此内容的更多信息。

    您还可以查看vue-styled-componentshttps://github.com/styled-components/vue-styled-components。我只将它用于React,但我认为它对在Vue中使用情况同样有用。

  2. 将重复的代码提取到一个函数中,并根据需要多次调用该代码。这称为制作代码DRY。例如:

    methods: {
      generateGridStyles(options) {
        return {
          'grid-template-columns': options.columns || this.columns,
          'grid-template-rows': options.rows || this.rows,
          'grid-template-areas': options.areas || this.areas,
          'grid-gap': options.gap || this.gap,
          'grid-column-gap': options.columnGap || this.columnGap,
          'grid-row-gap': options.rowGap || this.rowGap,
        }
      }
    }
    

    以下是该功能的使用方式:

    let small;
    if (this.small) {
      small = generateGridStyles(this.small);
    }
    

抽象是有开销的:另一个要维护和推理的组件。考虑一下您的总体设计以及GridLayout组件的目标是什么。

在我看来,CSS网格布局已经相当简单了,您的组件似乎只是通过CSS网格属性并将它们映射到包装器中。它并没有抽象出使用CSS网格的任何工作。当更容易维护和阅读“原始” CSS网格样式并使用媒体查询来调整样式时,我看不到这样做的好处。