修复Masonry响应式布局的问题

master
落雨楓 2 months ago
parent 40276ca7c8
commit aca1cb98bd

@ -230,7 +230,7 @@
"masonry/ext.isekai.masonry.base.js"
],
"styles": [
"masonry/ext.isekai.masonry.less"
"masonry/ext.isekai.masonry.css"
],
"targets": [
"desktop",

@ -26,7 +26,7 @@ class MasonryItemWidget {
if (isset($params['col'])) {
$value = $params['col'];
$col = $value === 'full' ? $maxCol : min($maxCol, intval($value));
$col = $value === 'full' ? $maxCol : min(12, intval($value));
$className[] = 'col-' . $col;
} else {
$className[] = 'col-1';
@ -34,31 +34,31 @@ class MasonryItemWidget {
if (isset($params['xs-col'])) {
$value = $params['xs-col'];
$col = $value === 'full' ? $maxCol : min($maxCol, intval($value));
$col = $value === 'full' ? $maxCol : min(12, intval($value));
$className[] = 'col-xs-' . $col;
}
if (isset($params['sm-col'])) {
$value = $params['sm-col'];
$col = $value === 'full' ? $maxCol : min($maxCol, intval($value));
$col = $value === 'full' ? $maxCol : min(12, intval($value));
$className[] = 'col-sm-' . $col;
}
if (isset($params['md-col'])) {
$value = $params['md-col'];
$col = $value === 'full' ? $maxCol : min($maxCol, intval($value));
$col = $value === 'full' ? $maxCol : min(12, intval($value));
$className[] = 'col-md-' . $col;
}
if (isset($params['lg-col'])) {
$value = $params['lg-col'];
$col = $value === 'full' ? $maxCol : min($maxCol, intval($value));
$col = $value === 'full' ? $maxCol : min(12, intval($value));
$className[] = 'col-lg-' . $col;
}
if (isset($params['xl-col'])) {
$value = $params['xl-col'];
$col = $value === 'full' ? $maxCol : min($maxCol, intval($value));
$col = $value === 'full' ? $maxCol : min(12, intval($value));
$className[] = 'col-xl-' . $col;
}

@ -4,6 +4,13 @@ namespace Isekai\Widgets;
use Html;
class MasonryWidget {
public static $breakpoints = [
'xs' => 576,
'sm' => 768,
'md' => 992,
'lg' => 1200,
'xl' => 1400,
];
public static $paramsStack = [];
/**
@ -21,30 +28,25 @@ class MasonryWidget {
$gutter = max(0, $params['gutter']);
$maxCol = max(1, $params['cols']);
$colWidth = round(100 / $maxCol, 6);
$css = <<<CSS
.isekai-masonry.max-col-{$maxCol} { --masonry-col-width: {$colWidth}%; --masonry-gutter: {$gutter}px; }
CSS;
$breakpoints = [
'xs' => 576,
'sm' => 768,
'md' => 992,
'lg' => 1200,
'xl' => 1400,
];
$css = ".isekai-masonry.max-col-{$maxCol} { --masonry-col-width: {$colWidth}%; --masonry-gutter: {$gutter}px; }";
if (isset($params['xs-cols'])) {
$maxCol = max(1, $params['xs-cols']);
$colWidth = round(100 / $maxCol, 6);
$css = ".isekai-masonry.max-col-xs-{$maxCol} { --masonry-col-width: {$colWidth}%; --masonry-gutter: {$gutter}px; }";
}
foreach ($breakpoints as $breakpoint => $width) {
foreach (self::$breakpoints as $breakpoint => $width) {
$paramKey = "{$breakpoint}-cols";
if (!isset($params[$paramKey])) {
continue;
}
$maxCol = max(1, $params[$paramKey]);
$value = intval($params[$paramKey]);
$maxCol = max(1, $value);
$colWidth = round(100 / $maxCol, 6);
$css .= <<<CSS
@media (max-width: {$width}px) { .isekai-masonry.max-col-{$breakpoint}-${maxCol} { --masonry-col-width: {$colWidth}%; } }
CSS;
$css .= "@media (min-width: {$width}px) { .isekai-masonry.max-col-{$breakpoint}-${maxCol} { --masonry-col-width: {$colWidth}%; } }";
}
return Html::rawElement('style', [], $css);
@ -61,23 +63,20 @@ CSS;
$parser->getOutput()->addModules(['ext.isekai.masonry']);
$params['cols'] = intval($params['cols'] ?? 2);
$params['xs-cols'] = intval($params['xs-cols'] ?? 1);
$params['sm-cols'] = intval($params['sm-cols'] ?? 1);
$params['md-cols'] = intval($params['md-cols'] ?? 2);
$params['lg-cols'] = intval($params['lg-cols'] ?? 2);
$params['xl-cols'] = intval($params['xl-cols'] ?? 3);
$params['gutter'] = intval($params['gutter'] ?? 10);
$className = [
'isekai-masonry',
"max-col-{$params['cols']}",
"max-col-xs-{$params['xs-cols']}",
"max-col-sm-{$params['sm-cols']}",
"max-col-md-{$params['md-cols']}",
"max-col-lg-{$params['lg-cols']}",
"max-col-xl-{$params['xl-cols']}",
];
foreach (self::$breakpoints as $breakpoint => $_) {
$paramKey = "{$breakpoint}-cols";
if (isset($params[$paramKey])) {
$className[] = "max-col-{$breakpoint}-{$params[$paramKey]}";
}
}
self::$paramsStack[] = $params;
$content = $parser->recursiveTagParseFully($text, $frame);
array_pop(self::$paramsStack);

@ -18,14 +18,8 @@ function debounce(func, wait, immediate) {
};
}
$(function () {
let masonry = new isekai.lib.Masonry('.isekai-masonry', {
itemSelector: '.isekai-masonry-item',
columnWidth: '.isekai-masonry-sizer',
gutter: '.isekai-masonry-gutter-sizer',
percentPosition: true
});
function observeResize(masonry) {
console.log('ResizeObserver supported');
let resizeObserver = new ResizeObserver(debounce(function () {
console.log('masonry resize');
masonry.layout();
@ -35,4 +29,43 @@ $(function () {
items.forEach(function (item) {
resizeObserver.observe(item);
});
}
function observeResizeFallback(masonry) {
console.log('ResizeObserver not supported, using fallback');
let itemHeights = [];
let items = document.querySelectorAll('.isekai-masonry-item');
items.forEach(function (item) {
itemHeights.push(item.clientHeight);
});
setInterval(function () {
let isResized = false;
items.forEach(function (item, index) {
if (item.clientHeight !== itemHeights[index]) {
isResized = true;
itemHeights[index] = item.clientHeight;
}
});
if (isResized) {
console.log('masonry resize');
masonry.layout();
}
}, 1000);
}
$(function () {
let masonry = new isekai.lib.Masonry('.isekai-masonry', {
itemSelector: '.isekai-masonry-item',
columnWidth: '.isekai-masonry-sizer',
gutter: '.isekai-masonry-gutter-sizer',
percentPosition: true
});
if (typeof ResizeObserver !== 'undefined') {
observeResize(masonry);
} else {
observeResizeFallback(masonry);
}
});

@ -0,0 +1,315 @@
.isekai-masonry {
display: block;
width: 100%;
--masonry-col-width: 50%;
}
.isekai-masonry .isekai-masonry-gutter-sizer {
width: 0;
width: var(--masonry-gutter);
}
.isekai-masonry .isekai-masonry-sizer {
width: 100%;
width: calc(var(--masonry-col-width) - var(--masonry-gutter) - 1px);
}
.isekai-masonry .isekai-masonry-item {
margin-bottom: var(--masonry-gutter);
}
.isekai-masonry .col-1 {
width: 100%;
width: calc(var(--masonry-col-width) - var(--masonry-gutter) - 1px);
}
.isekai-masonry .col-2 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 2 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-3 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 3 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-4 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 4 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-5 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 5 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-6 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 6 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-7 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 7 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-8 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 8 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-9 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 9 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-10 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 10 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-11 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 11 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-12 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 12 - var(--masonry-gutter) - 1px));
}
@media (min-width: 576px) {
.isekai-masonry .col-xs-1 {
width: 100%;
width: calc(var(--masonry-col-width) - var(--masonry-gutter) - 1px);
}
.isekai-masonry .col-xs-2 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 2 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xs-3 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 3 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xs-4 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 4 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xs-5 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 5 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xs-6 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 6 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xs-7 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 7 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xs-8 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 8 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xs-9 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 9 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xs-10 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 10 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xs-11 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 11 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xs-12 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 12 - var(--masonry-gutter) - 1px));
}
}
@media (min-width: 768px) {
.isekai-masonry .col-sm-1 {
width: 100%;
width: calc(var(--masonry-col-width) - var(--masonry-gutter) - 1px);
}
.isekai-masonry .col-sm-2 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 2 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-sm-3 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 3 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-sm-4 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 4 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-sm-5 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 5 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-sm-6 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 6 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-sm-7 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 7 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-sm-8 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 8 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-sm-9 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 9 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-sm-10 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 10 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-sm-11 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 11 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-sm-12 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 12 - var(--masonry-gutter) - 1px));
}
}
@media (min-width: 992px) {
.isekai-masonry .col-md-1 {
width: 100%;
width: calc(var(--masonry-col-width) - var(--masonry-gutter) - 1px);
}
.isekai-masonry .col-md-2 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 2 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-md-3 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 3 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-md-4 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 4 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-md-5 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 5 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-md-6 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 6 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-md-7 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 7 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-md-8 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 8 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-md-9 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 9 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-md-10 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 10 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-md-11 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 11 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-md-12 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 12 - var(--masonry-gutter) - 1px));
}
}
@media (min-width: 1200px) {
.isekai-masonry .col-lg-1 {
width: 100%;
width: calc(var(--masonry-col-width) - var(--masonry-gutter) - 1px);
}
.isekai-masonry .col-lg-2 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 2 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-lg-3 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 3 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-lg-4 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 4 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-lg-5 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 5 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-lg-6 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 6 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-lg-7 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 7 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-lg-8 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 8 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-lg-9 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 9 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-lg-10 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 10 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-lg-11 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 11 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-lg-12 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 12 - var(--masonry-gutter) - 1px));
}
}
@media (min-width: 1400px) {
.isekai-masonry .col-xl-1 {
width: 100%;
width: calc(var(--masonry-col-width) - var(--masonry-gutter) - 1px);
}
.isekai-masonry .col-xl-2 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 2 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xl-3 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 3 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xl-4 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 4 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xl-5 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 5 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xl-6 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 6 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xl-7 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 7 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xl-8 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 8 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xl-9 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 9 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xl-10 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 10 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xl-11 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 11 - var(--masonry-gutter) - 1px));
}
.isekai-masonry .col-xl-12 {
width: 100%;
width: min(100%, calc(var(--masonry-col-width) * 12 - var(--masonry-gutter) - 1px));
}
}

@ -1,80 +0,0 @@
.isekai-masonry {
display: block;
width: 100%;
--masonry-col-width: 50%;
.isekai-masonry-gutter-sizer {
width: 0;
width: ~"var(--masonry-gutter)";
}
.isekai-masonry-sizer {
width: 100%;
width: ~"calc(var(--masonry-col-width) - var(--masonry-gutter) - 1px)";
}
.isekai-masonry-item {
margin-bottom: ~"var(--masonry-gutter)";
}
// Column width tools
.col-1 {
width: 100%; // Fallback
width: ~"calc(var(--masonry-col-width) - var(--masonry-gutter) - 1px)";
}
.col-2 {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * 2 - var(--masonry-gutter) - 1px))";
}
.col-3 {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * 3 - var(--masonry-gutter) - 1px))";
}
.col-4 {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * 4 - var(--masonry-gutter) - 1px))";
}
.col-5 {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * 5 - var(--masonry-gutter) - 1px))";
}
.col-6 {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * 6 - var(--masonry-gutter) - 1px))";
}
.col-7 {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * 7 - var(--masonry-gutter) - 1px))";
}
.col-8 {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * 8 - var(--masonry-gutter) - 1px))";
}
.col-9 {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * 9 - var(--masonry-gutter) - 1px))";
}
.col-10 {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * 10 - var(--masonry-gutter) - 1px))";
}
.col-11 {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * 11 - var(--masonry-gutter) - 1px))";
}
.col-12 {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * 12 - var(--masonry-gutter) - 1px))";
}
}

@ -1,3 +1,4 @@
import './ext.isekai.masonry.less';
import Masonry from "masonry-layout";
import { registerModule } from "../moduleRegister";

@ -0,0 +1,52 @@
@breakpoints: {
xs: 576px;
sm: 768px;
md: 992px;
lg: 1200px;
xl: 1400px;
};
.make-masonry-grids(@breakpoint: 0) {
@prefix: if(iskeyword(@breakpoint), ~"@{breakpoint}-", );
.col-@{prefix}1 {
width: 100%; // Fallback
width: ~"calc(var(--masonry-col-width) - var(--masonry-gutter) - 1px)";
}
each(range(2, 12, 1), {
.col-@{prefix}@{value} {
width: 100%;
width: ~"min(100%, calc(var(--masonry-col-width) * @{value} - var(--masonry-gutter) - 1px))";
}
});
}
.isekai-masonry {
display: block;
width: 100%;
--masonry-col-width: 50%;
.isekai-masonry-gutter-sizer {
width: 0;
width: ~"var(--masonry-gutter)";
}
.isekai-masonry-sizer {
width: 100%;
width: ~"calc(var(--masonry-col-width) - var(--masonry-gutter) - 1px)";
}
.isekai-masonry-item {
margin-bottom: ~"var(--masonry-gutter)";
}
// Column width tools
.make-masonry-grids();
each(@breakpoints, {
@media (min-width: @value) {
.make-masonry-grids(@key);
}
});
}
Loading…
Cancel
Save