|
<template> |
|
<div ref="container"> |
|
<transition-group name="flip"> |
|
<div |
|
v-for="item in gridItems" |
|
:key="item.key" |
|
:style="{ backgroundImage: item.css, height: item.height }" |
|
/> |
|
</transition-group> |
|
</div> |
|
</template> |
|
|
|
<script> |
|
/* eslint-disable */ |
|
import { useMedia } from './useMedia.js' |
|
import { useMeasure } from './useMeasure' |
|
import shuffle from 'lodash/shuffle' |
|
import data from './data' |
|
|
|
import { |
|
value, |
|
onMounted, |
|
onDestroy, |
|
} from 'vue' |
|
|
|
function shuffleData() { |
|
// using a value() so we can replace the reference |
|
// Note: vaulue() is still concidered to be too unintuitive |
|
// and we look into possible optimizations |
|
const items = value(shuffle(data)) |
|
let id |
|
onMounted(() => { |
|
id = setInterval(() => items.value = shuffle(data), 2000) |
|
}) |
|
onDestroy(() => { id() }) |
|
return items |
|
} |
|
|
|
export default { |
|
setup(props, { refs }) { |
|
const columns = useMedia( |
|
['(min-width: 1500px)', '(min-width: 1000px)', '(min-width: 600px)'], |
|
[5, 4, 3], |
|
2 |
|
) |
|
const rect = useMeasure(refs, 'container') |
|
|
|
const items = shuffleData() |
|
|
|
const gridItems = computed(() => { |
|
const heights = new Array(columns.value).fill(0) |
|
const { width } = rect.width |
|
return items.value.map((child, i) => { |
|
const column = heights.indexOf(Math.min(...heights)) // Basic masonry-grid placing, puts tile into the smallest column using Math.min |
|
const xy = [(width / columns) * column, (heights[column] += child.height / 2) - child.height / 2] // X = container width / number of columns * column index, Y = it's just the height of the current column |
|
return { ...child, xy, width: width / columns, height: child.height / 2 } |
|
}) |
|
}) |
|
|
|
return { |
|
gridItems |
|
} |
|
} |
|
} |
|
</script> |
|
|
|
<style lang="scss"> |
|
.flip-list-move { |
|
transition: transform 1s; |
|
} |
|
</style> |