Skip to content

Commit

Permalink
Merge pull request #10 from Mikescops/feature/custom-loading-component
Browse files Browse the repository at this point in the history
Implement custom loading component
  • Loading branch information
Mikescops authored Oct 13, 2020
2 parents 8f7112b + e47e547 commit 68e067e
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 15 deletions.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ _Virtual Scrolling Grid made for VueJS based on CSS grids._
---

- Render any Vue Component (images, iframes, content) of a known width/height inside.
- Variable height items in the same row.
- Variable width items (based on columns).
- Variable height items in the same row and variable width items (based on columns).
- Highly customizable (custom loader, rendering, debug...).
- Rendering is done with virtual scrolling (aka windowing).
- Supports infinite scroll!

Expand Down Expand Up @@ -58,7 +58,7 @@ The `items` property is requeried and should be an array of the following object

You can update the `items` property at any time (and thus decide what can of storage you want to use) and the grid layout will be recomputed.

The `VirtualGrid` also takes multiple custom optional functions/variables as properties
The `VirtualGrid` also takes multiple custom **optional** functions/variables as properties

- **updateFunction**:
An async function that will populate the grid, constructor is the following `updateFunction() => Promise<boolean>`. For synchronous function just return immediately with `Promise.resolve(boolean)` for instance.
Expand All @@ -72,6 +72,10 @@ The `VirtualGrid` also takes multiple custom optional functions/variables as pro
A function that provides a way to adjust the item height by computing the initial height/width ratio and the column width (by default it preserves ratio), constructor is the following `getItemRatioHeight(height: number, width: number, columnWidth: number) => number;`.
- **updateTriggerMargin**:
A number of pixels to the bottom of the page that will trigger the `updateFunction`.
- **loader**:
A VueJS Component to display a loader when waiting for the next batch of data.
- **debug**:
A boolean to activate debug log and monitor when batches are trigger and bottom reached for instance.

Properties are provided with default functions that you can use or get inspired from in `src/utils.ts`.

Expand Down
18 changes: 14 additions & 4 deletions example/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@
<div id="app">
<img alt="Vue logo" src="./assets/logo.png" /> <br />
<a class="button" v-on:click="resetList()">Reset Component</a>
<VirtualGrid :v-if="loaded" ref="virtualgrid" :items="list" :updateFunction="pullData" />
<VirtualGrid
:v-if="loaded"
ref="virtualgrid"
:items="list"
:updateFunction="pullData"
:debug="true"
:loader="loaderComponent"
/>
</div>
</template>

<script lang="ts">
import { Component, Provide, ProvideReactive, Vue } from 'vue-property-decorator';
import VirtualGrid from '../src/VirtualGrid.vue';
import { Item, VirtualGridInterface } from '../src/types';
import Loader from './components/Loader.vue';
// Custom components to render
import * as ImageComponent from './components/Image.vue';
Expand All @@ -20,12 +28,13 @@ type CustomDataTypes = ImageComponent.Image | TitleComponent.Title | MapComponen
@Component({
components: {
VirtualGrid: VirtualGrid,
VirtualGrid,
},
})
export default class App extends Vue {
@Provide() loaded: boolean = false;
@ProvideReactive() loaded: boolean = false;
@Provide() batchSize: number = 50;
@Provide() loaderComponent: Vue.Component = Loader;
@ProvideReactive() list: Item<CustomDataTypes>[] = [];
@ProvideReactive() offset: number = 0;
Expand Down Expand Up @@ -106,7 +115,8 @@ export default class App extends Vue {
this.offset += 1;
return Promise.resolve(false);
// Wait between each response just to see the loader
return new Promise((resolve) => setTimeout(() => resolve(false), 2000));
}
resetList() {
Expand Down
28 changes: 28 additions & 0 deletions example/assets/loader.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions example/components/Loader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<template>
<div class="loader">
<img src="../assets/loader.svg" />
<p>We limit the loading speed for demo purpose only.</p>
</div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class LoaderComponent extends Vue {}
</script>

<style scoped>
.loader {
width: 100%;
text-align: center;
}
</style>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vue-virtual-grid",
"version": "2.0.0",
"version": "2.1.1",
"author": "Corentin Mors <[email protected]>",
"license": "MIT",
"repository": "github:mikescops/vue-virtual-grid",
Expand Down
28 changes: 21 additions & 7 deletions src/VirtualGrid.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
<script lang="ts">
import { Prop, Component, Vue, ProvideReactive } from 'vue-property-decorator';
import { getGridGapDefault, getColumnCountDefault, getWindowMarginDefault, getItemRatioHeightDefault } from './utils';
import {
getGridGapDefault,
getColumnCountDefault,
getWindowMarginDefault,
getItemRatioHeightDefault,
debugLog,
} from './utils';
import { Item } from './types';
interface ContainerData {
Expand Down Expand Up @@ -57,6 +63,8 @@ export default class VirtualGrid<P> extends Vue {
columnWidth: number
) => number;
@Prop({ default: 500 }) updateTriggerMargin: number;
@Prop({ default: null }) loader: Vue.Component;
@Prop({ default: false }) debug: boolean;
@ProvideReactive() updateLock: boolean = false;
Expand All @@ -71,6 +79,10 @@ export default class VirtualGrid<P> extends Vue {
elementSize: { height: 0, width: 0 },
};
get loadingBatch(): boolean {
return this.loader && this.updateLock;
}
get configData(): ConfigData<P> {
return this.computeConfigData(this.containerData, this.items);
}
Expand Down Expand Up @@ -123,11 +135,11 @@ export default class VirtualGrid<P> extends Vue {
if (!this.bottomReached && windowBottom > bottomTrigger && !this.updateLock) {
this.updateLock = true;
console.debug('Loading next batch');
debugLog(this.debug, 'Loading next batch');
const isLastBatch = await this.updateFunction();
if (isLastBatch) {
console.debug('Bottom reached');
debugLog(this.debug, 'Bottom reached');
this.bottomReached = true;
}
Expand Down Expand Up @@ -381,10 +393,11 @@ export default class VirtualGrid<P> extends Vue {
:style="{
boxSizing: 'border-box',
height: `${layoutData.totalHeight}px`,
paddingTop:
paddingTop: `${
renderData !== null && renderData.firstRenderedRowOffset !== null
? `${renderData.firstRenderedRowOffset}px`
: '0px',
? renderData.firstRenderedRowOffset + 'px'
: '0px'
}`,
}"
>
<div
Expand All @@ -404,9 +417,10 @@ export default class VirtualGrid<P> extends Vue {
'grid-row-start': getGridRowStart(item, renderData),
}"
>
<component :is="item.renderComponent" :item="item"></component>
<component :is="item.renderComponent" :item="item" />
</div>
</div>
<component :is="loadingBatch && loader" />
</div>
</template>

Expand Down
8 changes: 8 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,11 @@ export const getItemRatioHeightDefault = (height: number, width: number, columnW
const imageRatio = height / width;
return Math.round(columnWidth * imageRatio);
};

/** Other utils */

export const debugLog = (condition: boolean, ...args: any[]) => {
if (condition) {
console.debug(...args);
}
};

0 comments on commit 68e067e

Please sign in to comment.