A grid layout for Vue.js using CSS Grid Layout.
This library was created since both vue-grid-layout and gridstack.js didn't fit the requirements for the use in the AAC application AsTeRICS Grid. The main features are:
- uses the native CSS Grid Layout instead of absolute positioning
- automatically fills the whole container with same-sized grid elements (not easily possible in gridstack.js)
- uses native Vue List Move Transitions for animations
- predictable collision handling: either swapping elements by dropping an element onto another element or move other elements to the right, by dropping it in-between two elements
- not moving other elements until dropping the moved element (not messing up of the layout while moving)
- easy way to move all elements
Note
Currently only Vue 2.7
is supported, but it should be no problem to make the library compatible with Vue 3
There are the following examples (see folder examples):
- minimum-example.html: minimum working example
- basic-options.html: try all options
- responsive.html: responsive grid using full viewport size
- different-element-types.html: render different types of elements
- insert-new.html: insert new elements at a specific location by click / tap
- move-all.html: move all elements to top / right / bottom / left
- switch-layouts.html: switch between predefined layouts
To use this library via npm and with Vue's Single-File Components (SFC), follow these steps:
First install via npm install vue-css-grid-layout --save
or yarn add vue-css-grid-layout
.
Create a custom component for rendering a single grid element like this, e.g. as render-component.vue
:
<template>
<div class="render-component">{{ element.id }}</div>
</template>
<script>
export default {
props: {
element: Object
}
}
</script>
<style scoped>
.render-component {
border: 1px solid black;
display: flex;
flex-grow: 1;
}
</style>
Use GridLayout
from this library in order to render a grid:
<template>
<grid-layout :elements="elements" :render-component="RenderComponent"/>
</template>
<script>
import { GridLayout } from 'vue-css-grid-layout';
import RenderComponent from './render-component.vue';
export default {
components: { GridLayout, RenderComponent},
data() {
return {
RenderComponent: RenderComponent,
elements: [
{ x: 0, y: 0, width: 1, height: 1, id: 1 },
{ x: 1, y: 1, width: 1, height: 1, id: 2 }
]
}
}
}
</script>
<style src="vue-css-grid-layout/dist/vue-css-grid-layout.css"></style>
You can also use the files from CDN (or use the files from the dist
folder of this repository).
Include the CSS:
<link rel="stylesheet" href="https://unpkg.com/vue-css-grid-layout/dist/vue-css-grid-layout.css">
Create some HTML using the grid-layout
element`:
<div id="app">
<grid-layout :elements="elements" render-component="render-component"/>
</div>
Import the GridLayout
class in a script and use it:
<script type="module">
import { GridLayout } from 'https://unpkg.com/vue-css-grid-layout/dist/vue-css-grid-layout.es.js';
Vue.component('render-component', {
template: '<div class="render-component">{{ element.id }}</div>',
props: {
element: Object
}
});
new Vue({
el: '#app',
components: { GridLayout },
data() {
return {
elements: [
{ x: 0, y: 0, width: 1, height: 1, id: 1 },
{ x: 1, y: 1, width: 1, height: 1, id: 2 }
]
};
}
});
</script>
See minimum-example.html for the full example.
There are two components that can be used:
GridLayout
: the Vue component rendering a grid using CSS GridgridLayoutUtil
: a collection of utils for actions on the grid elements, e.g. collision handling or moving multiple elements. This component is used internally byGridLayout
, but can also be used externally for manual collision handling or moving of multiple elements.
The GridLayout
Vue component has the following props and events.
renderComponent: [Object, String]
: a Vue component that renders a single element of the grid. A propelement
is passed to this component containing the data of the current element to render.elements: Array
: an array of elements to render in the grid. Every element must have the propertiesid, x, y, width, height
where theid
must be unique. The single elements are passed torenderComponent
as propelement
.rows: Number
: the minimum number of rows of the grid. Actual shown rows are the maximum ofrows
androws defined by given elements
.columns: Number
: the minimum number of columns of the grid. Actual shown columns are the maximum ofcolumns
andcolumns defined by given elements
.backgroundColor: String
: the background color of the grid in any format valid in CSS (e.g.lightblue
or#f5f5f5
).baseTag: String
: the name of the HTML tag the base element of the grid should have, e.g.div
, defaults to an ordered list (ol
).elementTag: String
: the name of the HTML tag the grid elements should have, e.g.div
, defaults to a list item (li
).editable: Boolean
: iftrue
the grid can be edited, elements can be dragged and resized.resizeHandleSelector: String
: a CSS selector for selecting resize handles (at the bottom right) of the elements which make it clearer / easier to resize elements. Resize handles have to be added to therenderComponent
, if desired.backgroundLines: Boolean
: iftrue
the grid shows lines in the background indicating the rows and columns of the gridanimationDurationMs: Number
: the duration of the animations when elements are dragged / resized (editable: true
), defaults to200ms
.
Any additional props can be passed to GridLayout
which are passed on to the renderComponent
. So e.g. if passing some generic options to grid-layout
like this:
<grid-layout :elements="elements" render-component="render-component" :generic-options="{ color: 'green' }"/>
These options can be used within the render-component
along with the element
passed by default:
props: {
element: Object,
genericOptions: Object
}
Two events can be emitted by GridLayout
with editable: true
:
changed (newElements)
: the eventchanged
is emitted after the layout has changed by dragging or resizing. In the handler the rendered elements should be set to the new elements likethis.elements = newElements
.interacted (x,y)
: the eventinteracted
is emitted after a click or tap anywhere on the grid returning the coordinates of this event. This makes it easily possible to create new elements at the position of the last user interaction.
The component gridLayoutUtil
can be used for manually doing actions on the grid elements like moving all elements or resolving conflicts.
Import it along with GridLayout
, if needed:
import { GridLayout, gridLayoutUtil } from 'vue-css-grid-layout';
// or
import { GridLayout, gridLayoutUtil } from 'https://unpkg.com/vue-css-grid-layout/dist/vue-css-grid-layout.es.js';
These are the most important methods, for more details look at the JSDoc comments in the implementation:
gridLayoutUtil.moveAsPossible = function(allElements = [], moveElements = [], direction, options = {})
- moves elements in a specific direction as far as possible (without colliding with another element)
allElements
: array of all elementsmoveElements
: the elements to movedirection
: the direction to move, see gridLayoutUtil.DIR_* or 1-4 (UP, RIGHT, DOWN, RIGHT)options.gridWidth
standard width of the grid, can be overruled by given grid elementsoptions.gridHeight
standard height of the grid, can be overruled by given grid elements
gridLayoutUtil.resolveCollisions = function(gridElements, newElement, options = {})
- resolves collisions based on given grid and a newly added / changed element
gridElements
array of all grid elements (including newElement)newElement
element changed / added (already at new position)
This library was initially developed within a netidee project funding.
This library uses interact.js as dependency.