Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build a dynamic CSS grid with Vue?

Background

I would like to build a Vue.js component which will be reused twice - the components being next to each other, governed by the CSS Grid (display: grid;). They will take an equal space on the width of the screen.

The components will themselves will be grids of rows, dynamically generated in Vue.

This is how this is supposed to look like:

enter image description here

Plain HTML/CSS solution (works fine)

The following code correctly generates what I am expecting: on the left three rows of time/content pairs, and on the right two such rows (Codepen version)

.grid {
  display: grid;
  grid-template-columns: 6ch auto;
}

#app {
  width: 400px;
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.hour {
  text-align: right;
  padding: 3px 5px 3px 3px;
}

.name {
  text-align: left;
  padding: 3px 5px 3px 3px;
}
<div id="app">

  <div class="grid">
    <span class="hour">9:10</span> <span class="name">Acituf haih bim nizec ziohra uvi utucivsew koukeji fip kene ejviv wiel oj paphewan ilo newut.</span>
    <span class="hour">19:40</span> <span class="name">Macun dahhis cekdiwvug iti fieldu ab rewki pa ruoti abfonon cagoh codsi zadufi pu jurwut urmo owzew cawub.</span>
    <span class="hour">23:18</span> <span class="name">Zerba clegsns dgdrelm cevblrh.</span>
  </div>

  <div class="grid">
    <span class="hour">12:17</span> <span class="name">Hevkeek pe niwwat omkodo hapwas fepono azahawop ir bilbuel kame usipe cato icakori rosi sommawo.</span>
    <span class="hour">14:10</span> <span class="name">Hocmaizi weipe low rit todzup evtepcot zesaif unebojmug bageta ri fop sec ibti kukdo caukuocu fugocofo.</span>
  </div>

</div>

HTML/CSS/JS+Vue version (does not work as expected)

The same content is now generated through Vue upon the mount of the component. Please note that the result is different: the boxes are all mixed up.

I suppose that this is due to the fact that the content is appearing, then rendered and placed in the relevant places by CSS Grid, but then new content appears and this is not handled the way I expect by Grid (wildly speculating here)

(Codepen version)

new Vue({
  el: '#app',
  data: {
    els1: [],
    els2: []
  },
  mounted() {
    // content of the left box
    this.els1.push({
      first: '9:10',
      last: 'Acituf haih bim nizec ziohra uvi utucivsew koukeji fip kene ejviv wiel oj paphewan ilo newut.'
    })
    this.els1.push({
      first: '19:40',
      last: 'Macun dahhis cekdiwvug iti fieldu ab rewki pa ruoti abfonon cagoh codsi zadufi pu jurwut urmo owzew cawub.'
    })
    this.els1.push({
      first: '23:18',
      last: 'Zerba clegsns dgdrelm cevblrh.'
    })
    // content of the right box
    this.els2.push({
      first: '12:17',
      last: 'Hevkeek pe niwwat omkodo hapwas fepono azahawop ir bilbuel kame usipe cato icakori rosi sommawo.'
    })
    this.els2.push({
      first: '14:10',
      last: 'Hocmaizi weipe low rit todzup evtepcot zesaif unebojmug bageta ri fop sec ibti kukdo caukuocu fugocofo.'
    })
  }
})
.grid {
  display: grid;
  grid-template-columns: 6ch auto;
}

#app {
  width: 400px;
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.hour {
  text-align: right;
  padding: 3px 5px 3px 3px;
}

.name {
  text-align: left;
  padding: 3px 5px 3px 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">

  <div class="grid" v-for="e1 in els1">
    <span class="hour">{{e1.first}}</span> <span class="name">{{e1.last}}</span>
  </div>

  <div class="grid" v-for="e2 in els2">
    <span class="hour">{{e2.first}}</span> <span class="name">{{e2.last}}</span>
  </div>

</div>

What is the correct way to instruct CSS Grid of such dynamic content?

like image 946
WoJ Avatar asked Apr 19 '18 22:04

WoJ


People also ask

Does Opera support CSS grid?

The supporting browsers Other than in Internet Explorer, CSS Grid Layout is unprefixed in Safari, Chrome, Opera, Firefox and Edge. Support for all the properties and values detailed in these guides is interoperable across browsers.

How do I add custom CSS to Vue?

In Vue. js, we can add an inline style to our element by binding the style attribute in the HTML tag. For reference, :style is shorthand for v-bind:style . Inline styling can be done in two ways: using object syntax or array syntax.


1 Answers

You are repeating the grid instead of the content. You need to wrap the content into a <template> or <div>:

new Vue({
  el: '#app',
  data: {
    els1: [],
    els2: []
  },
  mounted() {
    // content of the left box
    this.els1.push({
      first: '9:10',
      last: 'Acituf haih bim nizec ziohra uvi utucivsew koukeji fip kene ejviv wiel oj paphewan ilo newut.'
    })
    this.els1.push({
      first: '19:40',
      last: 'Macun dahhis cekdiwvug iti fieldu ab rewki pa ruoti abfonon cagoh codsi zadufi pu jurwut urmo owzew cawub.'
    })
    this.els1.push({
      first: '23:18',
      last: 'Zerba clegsns dgdrelm cevblrh.'
    })
    // content of the right box
    this.els2.push({
      first: '12:17',
      last: 'Hevkeek pe niwwat omkodo hapwas fepono azahawop ir bilbuel kame usipe cato icakori rosi sommawo.'
    })
    this.els2.push({
      first: '14:10',
      last: 'Hocmaizi weipe low rit todzup evtepcot zesaif unebojmug bageta ri fop sec ibti kukdo caukuocu fugocofo.'
    })
  }
})
.grid {
  display: grid;
  grid-template-columns: 6ch auto;
}

#app {
  width: 400px;
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.hour {
  text-align: right;
  padding: 3px 5px 3px 3px;
}

.name {
  text-align: left;
  padding: 3px 5px 3px 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>

<div id="app">
  
  <div class="grid">
    <template v-for="e1 in els1">
      <span class="hour">{{e1.first}}</span> <span class="name">{{e1.last}}</span>
    </template>
  </div>
  
  <div class="grid" >
    <template v-for="e2 in els2">
      <span class="hour">{{e2.first}}</span> <span class="name">{{e2.last}}</span>
    </template>
    
  </div>
 
</div>
like image 151
puelo Avatar answered Oct 24 '22 03:10

puelo