VueJS 砌体布局
VueJS masonry layout
目前,我正在处理 VueJS 项目及其 vue cli 3。我正在尝试在我的 Vue 项目中实施 MasonryJS,但我被卡住了。我不明白如何为我的 vue 项目实现这种砌体布局。
;
(function(window) {
/**
* GridLoaderFx obj.
*/
function GridLoaderFx(el, options) {
this.el = el;
this.items = this.el.querySelectorAll('.grid__item > .grid__link');
}
/**
* Effects.
*/
GridLoaderFx.prototype.effects = {
'Shu': {
lineDrawing: true,
animeLineDrawingOpts: {
duration: 800,
delay: function(t, i) {
return i * 150;
},
easing: 'easeInOutSine',
strokeDashoffset: [anime.setDashoffset, 0],
opacity: [{
value: [0, 1]
},
{
value: [1, 0],
duration: 200,
easing: 'linear',
delay: 500
}
]
},
animeOpts: {
duration: 800,
easing: [0.2, 1, 0.3, 1],
delay: function(t, i) {
return i * 150 + 800;
},
opacity: {
value: [0, 1],
easing: 'linear'
},
scale: [0.5, 1]
}
}
};
GridLoaderFx.prototype._render = function(effect) {
// Reset styles.
this._resetStyles();
var self = this,
effectSettings = this.effects[effect],
animeOpts = effectSettings.animeOpts
if (effectSettings.perspective != undefined) {
[].slice.call(this.items).forEach(function(item) {
item.parentNode.style.WebkitPerspective = item.parentNode.style.perspective = effectSettings.perspective + 'px';
});
}
if (effectSettings.origin != undefined) {
[].slice.call(this.items).forEach(function(item) {
item.style.WebkitTransformOrigin = item.style.transformOrigin = effectSettings.origin;
});
}
if (effectSettings.lineDrawing != undefined) {
[].slice.call(this.items).forEach(function(item) {
// Create SVG.
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
path = document.createElementNS('http://www.w3.org/2000/svg', 'path'),
itemW = item.offsetWidth,
itemH = item.offsetHeight;
svg.setAttribute('width', itemW + 'px');
svg.setAttribute('height', itemH + 'px');
svg.setAttribute('viewBox', '0 0 ' + itemW + ' ' + itemH);
svg.setAttribute('class', 'grid__deco');
path.setAttribute('d', 'M0,0 l' + itemW + ',0 0,' + itemH + ' -' + itemW + ',0 0,-' + itemH);
path.setAttribute('stroke-dashoffset', anime.setDashoffset(path));
svg.appendChild(path);
item.parentNode.appendChild(svg);
});
var animeLineDrawingOpts = effectSettings.animeLineDrawingOpts;
animeLineDrawingOpts.targets = this.el.querySelectorAll('.grid__deco > path');
anime.remove(animeLineDrawingOpts.targets);
anime(animeLineDrawingOpts);
}
if (effectSettings.revealer != undefined) {
[].slice.call(this.items).forEach(function(item) {
var revealer = document.createElement('div');
revealer.className = 'grid__reveal';
if (effectSettings.revealerOrigin != undefined) {
revealer.style.transformOrigin = effectSettings.revealerOrigin;
}
if (effectSettings.revealerColor != undefined) {
revealer.style.backgroundColor = effectSettings.revealerColor;
}
item.parentNode.appendChild(revealer);
});
var animeRevealerOpts = effectSettings.animeRevealerOpts;
animeRevealerOpts.targets = this.el.querySelectorAll('.grid__reveal');
animeRevealerOpts.begin = function(obj) {
for (var i = 0, len = obj.animatables.length; i < len; ++i) {
obj.animatables[i].target.style.opacity = 1;
}
};
anime.remove(animeRevealerOpts.targets);
anime(animeRevealerOpts);
}
if (effectSettings.itemOverflowHidden) {
[].slice.call(this.items).forEach(function(item) {
item.parentNode.style.overflow = 'hidden';
});
}
animeOpts.targets = effectSettings.sortTargetsFn && typeof effectSettings.sortTargetsFn === 'function' ? [].slice.call(this.items).sort(effectSettings.sortTargetsFn) : this.items;
anime.remove(animeOpts.targets);
anime(animeOpts);
};
GridLoaderFx.prototype._resetStyles = function() {
this.el.style.WebkitPerspective = this.el.style.perspective = 'none';
[].slice.call(this.items).forEach(function(item) {
var gItem = item.parentNode;
item.style.opacity = 0;
item.style.WebkitTransformOrigin = item.style.transformOrigin = '50% 50%';
item.style.transform = 'none';
var svg = item.parentNode.querySelector('svg.grid__deco');
if (svg) {
gItem.removeChild(svg);
}
var revealer = item.parentNode.querySelector('.grid__reveal');
if (revealer) {
gItem.removeChild(revealer);
}
gItem.style.overflow = '';
});
};
window.GridLoaderFx = GridLoaderFx;
var body = document.body,
grids = [].slice.call(document.querySelectorAll('.grid')),
masonry = [],
currentGrid = 0,
// Switch grid radio buttons.
switchGridCtrls = [].slice.call(document.querySelectorAll('.control__radio')),
// Choose effect buttons.
fxCtrls = [].slice.call(document.querySelectorAll('.control--effects > .control__btn')),
// The GridLoaderFx instances.
loaders = [],
loadingTimeout;
function init() {
// Preload images
imagesLoaded(body, function() {
// Initialize Masonry on each grid.
grids.forEach(function(grid) {
var m = new Masonry(grid, {
itemSelector: '.grid__item',
columnWidth: '.grid__sizer',
percentPosition: true,
transitionDuration: 0
});
masonry.push(m);
// Hide the grid.
grid.classList.add('grid--hidden');
// Init GridLoaderFx.
loaders.push(new GridLoaderFx(grid));
});
// Show current grid.
grids[currentGrid].classList.remove('grid--hidden');
// Init/Bind events.
initEvents();
// Remove loading class from body
body.classList.remove('loading');
loaders[currentGrid]._render('Shu');
});
}
function initEvents() {
// Switching grids radio buttons.
switchGridCtrls.forEach(function(ctrl) {
ctrl.addEventListener('click', switchGrid);
});
// Effect selection.
fxCtrls.forEach(function(ctrl) {
ctrl.addEventListener('click', applyFx);
});
}
function applyFx(ev) {
// Simulate loading grid to show the effect.
clearTimeout(loadingTimeout);
grids[currentGrid].classList.add('grid--loading');
loadingTimeout = setTimeout(function() {
grids[currentGrid].classList.remove('grid--loading');
// Apply effect.
loaders[currentGrid]._render(ev.target.getAttribute('data-fx'));
}, 500);
}
init();
})(window);
.js .loading::before,
.js .loading::after {
content: '';
position: fixed;
z-index: 1000;
}
.loading::before {
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #2c2d31;
}
.loading::after {
top: 50%;
left: 50%;
width: 40px;
height: 40px;
margin: -20px 0 0 -20px;
border: 8px solid #383a41;
border-bottom-color: #565963;
border-radius: 50%;
animation: animLoader 0.8s linear infinite forwards;
}
@keyframes animLoader {
to {
transform: rotate(360deg);
}
}
a {
text-decoration: none;
color: #f2f2f2;
outline: none;
}
.hidden {
position: absolute;
overflow: hidden;
width: 0;
height: 0;
pointer-events: none;
}
/* Icons */
.content--side {
position: relative;
z-index: 100;
width: 15vw;
min-width: 130px;
max-height: 100vh;
padding: 0 1em;
order: 2;
}
.content--center {
flex: 1;
max-width: 100vw;
}
.content--related {
display: flex;
flex-wrap: wrap;
justify-content: center;
width: 100%;
padding: 8em 1em 3em;
text-align: center;
order: 5;
}
.media-related {
width: 100%;
}
.media-item {
padding: 1em;
}
.media-item__img {
max-width: 100%;
/*opacity: 0.7;*/
/*transition: opacity 0.3s;*/
}
.media-item:hover .media-item__img,
.media-item:focus .media-item__img {
opacity: 1;
}
.media-item__title {
font-size: 1em;
max-width: 220px;
padding: 0.5em;
margin: 0 auto;
}
@keyframes octocat-wave {
0%,
100% {
transform: rotate(0);
}
20%,
60% {
transform: rotate(-25deg);
}
40%,
80% {
transform: rotate(10deg);
}
}
/* Grid */
.grid {
position: relative;
z-index: 1;
display: block;
margin: 2% 5%;
}
.grid--hidden {
position: fixed !important;
z-index: 1;
top: 0;
left: 0;
width: 100%;
pointer-events: none;
opacity: 0;
}
.js .grid--loading::before,
.js .grid--loading::after {
content: '';
z-index: 1000;
}
.js .grid--loading::before {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: #2c2d31;
}
.js .grid--loading::after {
position: absolute;
top: calc(25vh - 20px);
left: 50%;
width: 40px;
height: 40px;
margin: 0 0 0 -20px;
border: 8px solid #383a41;
border-bottom-color: #565963;
border-radius: 50%;
animation: animLoader 0.8s linear forwards infinite;
}
.grid__sizer {
margin-bottom: 0 !important;
}
.grid__link,
.grid__img {
display: block;
}
.grid__img {
width: 100%;
}
.grid__deco {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
.grid__deco path {
fill: none;
stroke: #fff;
stroke-width: 2px;
}
.grid__reveal {
position: absolute;
z-index: 50;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
opacity: 0;
background-color: #2c2d31;
}
.grid__item {}
.grid__item:hover>.cm-pic-author {
opacity: 1;
}
.grid__item:hover>.cm-pic-social {
opacity: 1;
}
.cm-pic-social {
transition: opacity 0.6s ease-in-out;
position: absolute;
right: 10px;
top: 10px;
opacity: 0;
}
.cm-pic-social a {
color: #ffffff;
font-family: 'Roboto', sans-serif;
text-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
font-size: .9em;
text-decoration: none;
}
.cm-pic-social a:not(:last-child) {
margin-right: 1em;
}
.cm-pic-author {
transition: opacity 0.6s ease-in-out;
position: absolute;
left: 10px;
bottom: 10px;
opacity: 0;
}
.cm-pic-author a {
font-family: 'Roboto', sans-serif;
font-size: .9em;
text-decoration: none;
color: #ffffff;
text-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
}
.cm-pic-author a img {
width: 35px;
height: 35px;
object-position: center;
object-fit: cover;
border: 1px solid #ffffff;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
border-radius: 50%;
margin-right: 10px;
}
.grid .grid__item,
.grid .grid__sizer {
width: calc(100% - 20px);
margin: 0 10px 20px;
}
@media only screen and (min-width: 576px) {
.grid .grid__item,
.grid .grid__sizer {
width: calc((100% / 2) - 20px);
margin: 0 10px 20px;
}
}
/* min-width 1200px, large screens */
@media only screen and (min-width: 1200px) {
.grid .grid__item,
.grid .grid__sizer {
width: calc((100% / 3) - 20px);
margin: 0 10px 20px;
}
}
/* min-width 1500px, xlarge screens */
@media only screen and (min-width: 1500px) {
/* Grid types */
.grid-masonry .grid__item,
.grid-masonry .grid__sizer {
width: calc(25% - 20px);
margin: 0 10px 20px;
}
}
/* min-width 1800px, xlarge screens */
@media only screen and (min-width: 1800px) {
/* Grid types */
.grid-masonry .grid__item,
.grid-masonry .grid__sizer {
width: calc(20% - 20px);
margin: 0 10px 20px;
}
}
/*!* min-width 2400px, xlarge screens 5k*!*/
/*@media only screen and (min-width: 2400px){*/
/*!* Grid types *!*/
/*.grid-masonry .grid__item,*/
/*.grid-masonry .grid__sizer {*/
/*width: calc(16.666666% - 20px);*/
/*margin: 0 10px 20px;*/
/*}*/
/*}*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/masonry/4.2.2/masonry.pkgd.min.js"></script>
<script src="https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.min.js"></script>
<div class="content content--center">
<div class="grid grid-masonry">
<div class="grid__sizer"></div>
<div class="grid__item">
<a class="grid__link" href="image-details.html">
<img class="grid__img" src="https://i.imgur.com/dCFlYyG.jpg" alt="Some image" />
</a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href="personal-profile-follow.html"><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/Zneml4H.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/H4bbqpA.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/9Q9pgmR.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="https://i.imgur.com/9Q9pgmR.jpg" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://picsum.photos/600/800" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="image-details.html">
<img class="grid__img" src="https://i.imgur.com/dCFlYyG.jpg" alt="Some image" />
</a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href="personal-profile-follow.html"><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/Zneml4H.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/H4bbqpA.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/9Q9pgmR.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="https://i.imgur.com/9Q9pgmR.jpg" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://picsum.photos/600/800" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
</div>
</div>
现在我正在尝试将它实现为一个 vue 组件,以便我可以在任何视图页面上呈现。
谢谢
可以通过npm安装
npm install masonry-layout --save
然后将其导入到您的组件(如果您愿意,也可以导入到全局)
组件
import Masonry from "masonry-layout";
export default {
mounted: function () {
// initialization of masonry
var grid = document.querySelector('.masonry-grid');
var msnry = new Masonry( grid, {
// options...
columnWidth: '.masonry-grid-sizer',
itemSelector: '.masonry-grid-item',
percentPosition: true
});
}
}
模板
<template>
<div>
<!-- Blog Masonry Blocks -->
<div class="container ">
<div class="masonry-grid row ">
<div class="masonry-grid-sizer col-sm-1"></div>
<div class="masonry-grid-item col-lg-3">
...
</div>
<div class="masonry-grid-item col-lg-3">
...
</div>
<div class="masonry-grid-item col-lg-3">
...
</div>
</div>
</div>
</div>
</template>
尝试安装 npm install vue-masonry-css --save-dev 很容易实现。 https://github.com/paulcollett/vue-masonry-css
<masonry
:cols="3"
:gutter="30"
>
<div v-for="(item, index) in items" :key="index">Item: {{index + 1}}</div>
</masonry>
目前,我正在处理 VueJS 项目及其 vue cli 3。我正在尝试在我的 Vue 项目中实施 MasonryJS,但我被卡住了。我不明白如何为我的 vue 项目实现这种砌体布局。
;
(function(window) {
/**
* GridLoaderFx obj.
*/
function GridLoaderFx(el, options) {
this.el = el;
this.items = this.el.querySelectorAll('.grid__item > .grid__link');
}
/**
* Effects.
*/
GridLoaderFx.prototype.effects = {
'Shu': {
lineDrawing: true,
animeLineDrawingOpts: {
duration: 800,
delay: function(t, i) {
return i * 150;
},
easing: 'easeInOutSine',
strokeDashoffset: [anime.setDashoffset, 0],
opacity: [{
value: [0, 1]
},
{
value: [1, 0],
duration: 200,
easing: 'linear',
delay: 500
}
]
},
animeOpts: {
duration: 800,
easing: [0.2, 1, 0.3, 1],
delay: function(t, i) {
return i * 150 + 800;
},
opacity: {
value: [0, 1],
easing: 'linear'
},
scale: [0.5, 1]
}
}
};
GridLoaderFx.prototype._render = function(effect) {
// Reset styles.
this._resetStyles();
var self = this,
effectSettings = this.effects[effect],
animeOpts = effectSettings.animeOpts
if (effectSettings.perspective != undefined) {
[].slice.call(this.items).forEach(function(item) {
item.parentNode.style.WebkitPerspective = item.parentNode.style.perspective = effectSettings.perspective + 'px';
});
}
if (effectSettings.origin != undefined) {
[].slice.call(this.items).forEach(function(item) {
item.style.WebkitTransformOrigin = item.style.transformOrigin = effectSettings.origin;
});
}
if (effectSettings.lineDrawing != undefined) {
[].slice.call(this.items).forEach(function(item) {
// Create SVG.
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
path = document.createElementNS('http://www.w3.org/2000/svg', 'path'),
itemW = item.offsetWidth,
itemH = item.offsetHeight;
svg.setAttribute('width', itemW + 'px');
svg.setAttribute('height', itemH + 'px');
svg.setAttribute('viewBox', '0 0 ' + itemW + ' ' + itemH);
svg.setAttribute('class', 'grid__deco');
path.setAttribute('d', 'M0,0 l' + itemW + ',0 0,' + itemH + ' -' + itemW + ',0 0,-' + itemH);
path.setAttribute('stroke-dashoffset', anime.setDashoffset(path));
svg.appendChild(path);
item.parentNode.appendChild(svg);
});
var animeLineDrawingOpts = effectSettings.animeLineDrawingOpts;
animeLineDrawingOpts.targets = this.el.querySelectorAll('.grid__deco > path');
anime.remove(animeLineDrawingOpts.targets);
anime(animeLineDrawingOpts);
}
if (effectSettings.revealer != undefined) {
[].slice.call(this.items).forEach(function(item) {
var revealer = document.createElement('div');
revealer.className = 'grid__reveal';
if (effectSettings.revealerOrigin != undefined) {
revealer.style.transformOrigin = effectSettings.revealerOrigin;
}
if (effectSettings.revealerColor != undefined) {
revealer.style.backgroundColor = effectSettings.revealerColor;
}
item.parentNode.appendChild(revealer);
});
var animeRevealerOpts = effectSettings.animeRevealerOpts;
animeRevealerOpts.targets = this.el.querySelectorAll('.grid__reveal');
animeRevealerOpts.begin = function(obj) {
for (var i = 0, len = obj.animatables.length; i < len; ++i) {
obj.animatables[i].target.style.opacity = 1;
}
};
anime.remove(animeRevealerOpts.targets);
anime(animeRevealerOpts);
}
if (effectSettings.itemOverflowHidden) {
[].slice.call(this.items).forEach(function(item) {
item.parentNode.style.overflow = 'hidden';
});
}
animeOpts.targets = effectSettings.sortTargetsFn && typeof effectSettings.sortTargetsFn === 'function' ? [].slice.call(this.items).sort(effectSettings.sortTargetsFn) : this.items;
anime.remove(animeOpts.targets);
anime(animeOpts);
};
GridLoaderFx.prototype._resetStyles = function() {
this.el.style.WebkitPerspective = this.el.style.perspective = 'none';
[].slice.call(this.items).forEach(function(item) {
var gItem = item.parentNode;
item.style.opacity = 0;
item.style.WebkitTransformOrigin = item.style.transformOrigin = '50% 50%';
item.style.transform = 'none';
var svg = item.parentNode.querySelector('svg.grid__deco');
if (svg) {
gItem.removeChild(svg);
}
var revealer = item.parentNode.querySelector('.grid__reveal');
if (revealer) {
gItem.removeChild(revealer);
}
gItem.style.overflow = '';
});
};
window.GridLoaderFx = GridLoaderFx;
var body = document.body,
grids = [].slice.call(document.querySelectorAll('.grid')),
masonry = [],
currentGrid = 0,
// Switch grid radio buttons.
switchGridCtrls = [].slice.call(document.querySelectorAll('.control__radio')),
// Choose effect buttons.
fxCtrls = [].slice.call(document.querySelectorAll('.control--effects > .control__btn')),
// The GridLoaderFx instances.
loaders = [],
loadingTimeout;
function init() {
// Preload images
imagesLoaded(body, function() {
// Initialize Masonry on each grid.
grids.forEach(function(grid) {
var m = new Masonry(grid, {
itemSelector: '.grid__item',
columnWidth: '.grid__sizer',
percentPosition: true,
transitionDuration: 0
});
masonry.push(m);
// Hide the grid.
grid.classList.add('grid--hidden');
// Init GridLoaderFx.
loaders.push(new GridLoaderFx(grid));
});
// Show current grid.
grids[currentGrid].classList.remove('grid--hidden');
// Init/Bind events.
initEvents();
// Remove loading class from body
body.classList.remove('loading');
loaders[currentGrid]._render('Shu');
});
}
function initEvents() {
// Switching grids radio buttons.
switchGridCtrls.forEach(function(ctrl) {
ctrl.addEventListener('click', switchGrid);
});
// Effect selection.
fxCtrls.forEach(function(ctrl) {
ctrl.addEventListener('click', applyFx);
});
}
function applyFx(ev) {
// Simulate loading grid to show the effect.
clearTimeout(loadingTimeout);
grids[currentGrid].classList.add('grid--loading');
loadingTimeout = setTimeout(function() {
grids[currentGrid].classList.remove('grid--loading');
// Apply effect.
loaders[currentGrid]._render(ev.target.getAttribute('data-fx'));
}, 500);
}
init();
})(window);
.js .loading::before,
.js .loading::after {
content: '';
position: fixed;
z-index: 1000;
}
.loading::before {
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #2c2d31;
}
.loading::after {
top: 50%;
left: 50%;
width: 40px;
height: 40px;
margin: -20px 0 0 -20px;
border: 8px solid #383a41;
border-bottom-color: #565963;
border-radius: 50%;
animation: animLoader 0.8s linear infinite forwards;
}
@keyframes animLoader {
to {
transform: rotate(360deg);
}
}
a {
text-decoration: none;
color: #f2f2f2;
outline: none;
}
.hidden {
position: absolute;
overflow: hidden;
width: 0;
height: 0;
pointer-events: none;
}
/* Icons */
.content--side {
position: relative;
z-index: 100;
width: 15vw;
min-width: 130px;
max-height: 100vh;
padding: 0 1em;
order: 2;
}
.content--center {
flex: 1;
max-width: 100vw;
}
.content--related {
display: flex;
flex-wrap: wrap;
justify-content: center;
width: 100%;
padding: 8em 1em 3em;
text-align: center;
order: 5;
}
.media-related {
width: 100%;
}
.media-item {
padding: 1em;
}
.media-item__img {
max-width: 100%;
/*opacity: 0.7;*/
/*transition: opacity 0.3s;*/
}
.media-item:hover .media-item__img,
.media-item:focus .media-item__img {
opacity: 1;
}
.media-item__title {
font-size: 1em;
max-width: 220px;
padding: 0.5em;
margin: 0 auto;
}
@keyframes octocat-wave {
0%,
100% {
transform: rotate(0);
}
20%,
60% {
transform: rotate(-25deg);
}
40%,
80% {
transform: rotate(10deg);
}
}
/* Grid */
.grid {
position: relative;
z-index: 1;
display: block;
margin: 2% 5%;
}
.grid--hidden {
position: fixed !important;
z-index: 1;
top: 0;
left: 0;
width: 100%;
pointer-events: none;
opacity: 0;
}
.js .grid--loading::before,
.js .grid--loading::after {
content: '';
z-index: 1000;
}
.js .grid--loading::before {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: #2c2d31;
}
.js .grid--loading::after {
position: absolute;
top: calc(25vh - 20px);
left: 50%;
width: 40px;
height: 40px;
margin: 0 0 0 -20px;
border: 8px solid #383a41;
border-bottom-color: #565963;
border-radius: 50%;
animation: animLoader 0.8s linear forwards infinite;
}
.grid__sizer {
margin-bottom: 0 !important;
}
.grid__link,
.grid__img {
display: block;
}
.grid__img {
width: 100%;
}
.grid__deco {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
.grid__deco path {
fill: none;
stroke: #fff;
stroke-width: 2px;
}
.grid__reveal {
position: absolute;
z-index: 50;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
opacity: 0;
background-color: #2c2d31;
}
.grid__item {}
.grid__item:hover>.cm-pic-author {
opacity: 1;
}
.grid__item:hover>.cm-pic-social {
opacity: 1;
}
.cm-pic-social {
transition: opacity 0.6s ease-in-out;
position: absolute;
right: 10px;
top: 10px;
opacity: 0;
}
.cm-pic-social a {
color: #ffffff;
font-family: 'Roboto', sans-serif;
text-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
font-size: .9em;
text-decoration: none;
}
.cm-pic-social a:not(:last-child) {
margin-right: 1em;
}
.cm-pic-author {
transition: opacity 0.6s ease-in-out;
position: absolute;
left: 10px;
bottom: 10px;
opacity: 0;
}
.cm-pic-author a {
font-family: 'Roboto', sans-serif;
font-size: .9em;
text-decoration: none;
color: #ffffff;
text-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
}
.cm-pic-author a img {
width: 35px;
height: 35px;
object-position: center;
object-fit: cover;
border: 1px solid #ffffff;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
border-radius: 50%;
margin-right: 10px;
}
.grid .grid__item,
.grid .grid__sizer {
width: calc(100% - 20px);
margin: 0 10px 20px;
}
@media only screen and (min-width: 576px) {
.grid .grid__item,
.grid .grid__sizer {
width: calc((100% / 2) - 20px);
margin: 0 10px 20px;
}
}
/* min-width 1200px, large screens */
@media only screen and (min-width: 1200px) {
.grid .grid__item,
.grid .grid__sizer {
width: calc((100% / 3) - 20px);
margin: 0 10px 20px;
}
}
/* min-width 1500px, xlarge screens */
@media only screen and (min-width: 1500px) {
/* Grid types */
.grid-masonry .grid__item,
.grid-masonry .grid__sizer {
width: calc(25% - 20px);
margin: 0 10px 20px;
}
}
/* min-width 1800px, xlarge screens */
@media only screen and (min-width: 1800px) {
/* Grid types */
.grid-masonry .grid__item,
.grid-masonry .grid__sizer {
width: calc(20% - 20px);
margin: 0 10px 20px;
}
}
/*!* min-width 2400px, xlarge screens 5k*!*/
/*@media only screen and (min-width: 2400px){*/
/*!* Grid types *!*/
/*.grid-masonry .grid__item,*/
/*.grid-masonry .grid__sizer {*/
/*width: calc(16.666666% - 20px);*/
/*margin: 0 10px 20px;*/
/*}*/
/*}*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/masonry/4.2.2/masonry.pkgd.min.js"></script>
<script src="https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.min.js"></script>
<div class="content content--center">
<div class="grid grid-masonry">
<div class="grid__sizer"></div>
<div class="grid__item">
<a class="grid__link" href="image-details.html">
<img class="grid__img" src="https://i.imgur.com/dCFlYyG.jpg" alt="Some image" />
</a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href="personal-profile-follow.html"><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/Zneml4H.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/H4bbqpA.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/9Q9pgmR.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="https://i.imgur.com/9Q9pgmR.jpg" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://picsum.photos/600/800" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="image-details.html">
<img class="grid__img" src="https://i.imgur.com/dCFlYyG.jpg" alt="Some image" />
</a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href="personal-profile-follow.html"><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/Zneml4H.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/H4bbqpA.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://i.imgur.com/9Q9pgmR.jpg" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="https://i.imgur.com/9Q9pgmR.jpg" alt="">J. Alexa</a>
</div>
</div>
<div class="grid__item">
<a class="grid__link" href="#"><img class="grid__img" src="https://picsum.photos/600/800" alt="Some image" /></a>
<div class="cm-pic-social d-flex">
<a href=""><span><img width="16px" src="images/add.svg" alt=""></span> Collection</a>
<a href=""><span><img width="16px" src="images/love.svg" alt=""></span> 50</a>
</div>
<div class="cm-pic-author d-flex">
<a href=""><img src="images/author@2x.png" alt="">J. Alexa</a>
</div>
</div>
</div>
</div>
现在我正在尝试将它实现为一个 vue 组件,以便我可以在任何视图页面上呈现。
谢谢
可以通过npm安装
npm install masonry-layout --save
然后将其导入到您的组件(如果您愿意,也可以导入到全局)
组件
import Masonry from "masonry-layout";
export default {
mounted: function () {
// initialization of masonry
var grid = document.querySelector('.masonry-grid');
var msnry = new Masonry( grid, {
// options...
columnWidth: '.masonry-grid-sizer',
itemSelector: '.masonry-grid-item',
percentPosition: true
});
}
}
模板
<template>
<div>
<!-- Blog Masonry Blocks -->
<div class="container ">
<div class="masonry-grid row ">
<div class="masonry-grid-sizer col-sm-1"></div>
<div class="masonry-grid-item col-lg-3">
...
</div>
<div class="masonry-grid-item col-lg-3">
...
</div>
<div class="masonry-grid-item col-lg-3">
...
</div>
</div>
</div>
</div>
</template>
尝试安装 npm install vue-masonry-css --save-dev 很容易实现。 https://github.com/paulcollett/vue-masonry-css
<masonry
:cols="3"
:gutter="30"
>
<div v-for="(item, index) in items" :key="index">Item: {{index + 1}}</div>
</masonry>