1

I am looking to create a columns component in VueJS that will look something like this:

<column-i xs="3" md="6" lg="12">
  Some Content
</column-i>

When rendered, I would like the html markup to look like this:

<div class="column xs3 md6 lg12>Some Content</div>

In other words, I want to concatenate the prop name and its value together and then add the concatenated string to the class attribute -- and I'm having a hard time figure out how to do that.

Any ideas?

1 Answer 1

1

If all the properties of the component will be used, you can use Object.entries and this.$props to get an array of all the [key, value] pairs. Then, iterate the array in a computed property to construct the classes which will be bound to the component's element.

const ColumnI = {
  name: 'column-i',

  template: `<div :class="columnClass"><slot /></div>`,

  // Define the props that will be converted into classes
  props: {
    xs: {
      Type: Number,
      default: null,
    },

    md: {
      Type: Number,
      default: null,
    },

    lg: {
      Type: Number,
      default: null,
    },
  },

  computed: {
    columnClass() {
      let result = ['column']
      // Look for all the component props and get an array of all its
      // enumerable [key, value] pairs
      for (let [propKey, propValue] of Object.entries(this.$props)) {
        // If the prop has a value
        if (propValue) {
          // Add the prop to the class as '<key><value>'
          // ie. xs prop with a value of 3 results in 'xs3'
          result.push(`${propKey}${propValue}`)
        }
      }
      return result
    },
  },
}

new Vue({
  el: '#app',

  components: {
    ColumnI,
  }
})
/*
 Random styles just for illustration purposes
*/

.column {
  padding: 10px;
}

.xs3 {
  color: dodgerblue;
}

.md6 {
  background-color: whitesmoke;
}

.lg12 {
  border: 2px solid tomato;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <column-i xs="3" md="6" lg="12">
    Some Content
  </column-i>
</div>


The above solution does not handle adding props, that will not be bound as a class, to the component.

To handle that, we can create an array of the breakpoints we want to convert to a class.

const ColumnI = {
  name: 'column-i',

  template: `<component :is="tag" :class="columnClass"><slot /></component>`,

  props: {
    // This prop will not be converted into a class
    tag: {
      Type: String,
      default: 'div',
    },

    xs: {
      Type: Number,
      default: null,
    },

    md: {
      Type: Number,
      default: null,
    },

    lg: {
      Type: Number,
      default: null,
    },
  },

  data() {
    return {
      breakpoints: ['xs', 'md', 'lg'],
    }
  },

  computed: {
    columnClass() {
      let result = ['column']
      // Look for all the component props and get an array of all its
      // enumerable [key, value] pairs
      for (let [propKey, propValue] of Object.entries(this.$props)) {
        // If the prop is a breakpoint and it has a value
        if (this.breakpoints.includes(propKey) && propValue) {
          // Add the prop to the class as '<key><value>'
          // ie. xs prop with a value of 3 results in 'xs3'
          result.push(`${propKey}${propValue}`)
        }
      }
      return result
    },
  },
}

new Vue({
  el: '#app',

  components: {
    ColumnI,
  }
})
/*
 Random styles just for illustration purposes
*/

.tagdiv {
  /* This will not be applied */
  text-decoration: underline;
}

.column {
  padding: 10px;
}

.xs3 {
  color: dodgerblue;
}

.md6 {
  background-color: whitesmoke;
}

.lg12 {
  border: 2px solid tomato;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <column-i xs="3" md="6" lg="12">
    Some Content
  </column-i>
</div>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.