Blazor bootstrap masonry example

May 18, 2023 | 0 comments

개요

위 이미지의 좌/우를 비교해 보면
좌측은 일반적인 Grid 형태의 Layout 이며, 우측은 Masonry Layout 이라고 하며 한글로 번역하면 벽돌? 콘크리트? 라고 번역이 되네요…
일반적인 표 형태의 배치이다 보니 비어있는 공간이 많은 좌측 보다는 우측처럼 표시하는 경우가 많습니다.(디자인 영역이니 더 이상은 생략하겠습니다.)

Visual studio 2023 현재(2023-05-18) 기준으로 보면 blazor 프로젝트를 생성하면 Bootstrap 을 기본 참조해서 구성이 됩니다.
Bootstrap 의 Masonry 예제 페이지를 보면 Bootstrap 자체적으로 Masonry 라이브러리를 포함하고 있지 않기 때문에 추가적으로 참조할 라이브러리 정보를 알려줍니다.

Bootstrap 의 Masonry 예제 페이지를 참조해서 Blazor 프로젝트에 적용하기에는 설명이 조금 부실합니다.
Blazor 프로젝트에서 Bootstrap + Masonry 를 적용하는 예제를 작성해 보겠습니다.

프로젝트 생성

visual studio 에서 blazor webassembly 프로젝트를 생성합니다.

Client 프로젝트 수정

Masonry Initialize javascript

script 폴더를 생성해서 masonry.js 파일을 추가하고 다음과 같이 작성합니다.
Masonry 객체를 초기화 하는 함수입니다.

window.initMasonry = (parentSelector, itemSelector, percentPosition, transitionDuration) => {
    var masonry = new Masonry(parentSelector, {
        itemSelector: itemSelector,
        percentPosition: percentPosition,
        transitionDuration: transitionDuration
    });
};

javascript 라이브러리 참조 추가

index.html 파일에서 아래 코드를 추가합니다.
이전에 작성한 script/masonry.js 파일을 참조합니다.
bootstrap.bundle.min.js 과 masonry.pkgd.min.js 파일을 참조합니다.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>BlazorBootstrapMasonry</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link rel="icon" type="image/png" href="favicon.png" />
    <link href="BlazorBootstrapMasonry.Client.styles.css" rel="stylesheet" />
    <script src="script/masonry.js"></script>
</head>

<body>
    <div id="app">
        <svg class="loading-progress">
            <circle r="40%" cx="50%" cy="50%" />
            <circle r="40%" cx="50%" cy="50%" />
        </svg>
        <div class="loading-progress-text"></div>
    </div>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>

</body>

</html>

Masonry Service 생성

services 폴더를 생성해서 MasonryService.cs 파일을 추가하고 다음과 같이 작성합니다.
Masonry 초기화 함수를 호출하는 서비스 입니다.

using Microsoft.JSInterop;

namespace BlazorBootstrapMasonry.Client;

public interface IMasonryService
{
    Task Init(string parentSelector, string itemSelector, bool percentPosition = true, float transitionDurationSecs = .2F);
}

public class MasonryService : IMasonryService
{
    private readonly IJSRuntime _jsRuntime;

    public MasonryService(IJSRuntime jSRuntime)
    {
        _jsRuntime = jSRuntime;
    }

    /// <summary>
    /// options ref : https://masonry.desandro.com/options.html
    /// </summary>
    /// <param name="parentSelector"></param>
    /// <param name="itemSelector"></param>
    /// <param name="percentPosition"></param>
    /// <param name="transitionDurationSecs"></param>
    /// <returns></returns>
    public async Task Init(string parentSelector, string itemSelector, bool percentPosition = true, float transitionDurationSecs = 0.2f)
    {
        var transitionDurationStr = $"{transitionDurationSecs}s";

        await _jsRuntime.InvokeVoidAsync("initMasonry", parentSelector, itemSelector, percentPosition, transitionDurationStr);
    }
}

Masonry Service 등록

Program.cs 파일에서 다음 코드를 추가합니다.

using BlazorBootstrapMasonry.Client;

using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped<IMasonryService, MasonryService>();

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

await builder.Build().RunAsync();

홈페이지 수정

index.razor 파일을 다음과 같이 수정합니다.

동일한 목록을 표시하는 Grid 를 좌/우로 배치하였습니다.
컨테이너가 Row 가 되고, Row 하위에 Column 단위로 구성이 됩니다.
우측 항목의 Row 에는 masonryRow CSS class 를 추가하였습니다.
OnAfterRenderAsync 메서드에서 Masonry 초기화 서비스를 호출합니다.
이때, Row 와 Column 의 CSS class 를 지정해서 초기화를 합니다.
masonryRow CSS class 는 Masonry Layout 을 적용할 Row 를 쉽게 찾기 위해서 추가되었습니다.

@page "/"
@using System.Drawing;

@inject IMasonryService Masonry

<PageTitle>Masonry test</PageTitle>

<div class="container-fluid mt-2 p-1">
    <button type="button" class="btn btn-secondary mb-1" @onclick="FetchDatas">
        Refresh
    </button>
    <div class="row">
        <div class="col">
            <div class="alert alert-info my-1" role="alert">
                Normal Grid Layout
            </div>
            <div class="row border mx-1">
                @foreach (var item in Items)
                {
                    <div class="col-sm-6 col-lg-4 col-xl-3 col-xxl-2 p-1" @key="item">
                        <div class="card" style="@($"background-color:{item.BackColor}")">
                            <span style="@($"font-size:{item.TextSize}em")">@item.Text</span>
                        </div>
                    </div>
                }
            </div>
        </div>
        <div class="col">
            <div class="alert alert-info my-1" role="alert">
                Masonry Layout
            </div>
            <div class="row border mx-1 masonryRow">
                @foreach (var item in Items)
                {
                    <div class="col-sm-6 col-lg-4 col-xl-3 col-xxl-2 p-1" @key="item">
                        <div class="card" style="@($"background-color:{item.BackColor}")">
                            <span style="@($"font-size:{item.TextSize}em")">@item.Text</span>
                        </div>
                    </div>
                }
            </div>
        </div>
    </div>
</div>



@code {
    class MasonryItem
    {
        public string Text { get; set; }
        public double TextSize { get; set; }
        public string BackColor { get; set; }
    }
    List<MasonryItem> Items = new();
    protected override async Task OnInitializedAsync()
    {
        await FetchDatas();
    }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await Masonry.Init(".masonryRow", ".col-sm-6");
    }

    async Task FetchDatas()
    {
        Items = await Task.FromResult(Enumerable.Range(1, 20).Select(idx => new MasonryItem()
            {
                Text = $"{idx}",
                TextSize = Random.Shared.Next(3, 7),
                BackColor = GetRandomColor()
            }).ToList());
    }
    static string GetRandomColor()
    {
        return ColorTranslator.ToHtml(Color.FromArgb(Random.Shared.Next(256), Random.Shared.Next(256), Random.Shared.Next(256)));
    }
}

index.razor.css 파일을 추가하고 다음과 같이 작성합니다.

.masonryRow {

}

span {
    text-align:center;
}

결과 확인

Server 프로젝트를 실행하면 홈페이지가 다음과 같이 표시됩니다.
상단 새로고침 버튼을 클릭하면 목록을 랜덤하게 갱신하는 기능을 합니다.
Masonry 적용 전과 후를 비교하기 위해 좌/우로 구분해서 동일한 항목으로 표시합니다.
브라우저 크기를 변경해보면 사이즈에 따라 실시간으로 재배치 되는 것을 확인하실 수 있습니다.

Youtube

영상으로도 확인하실 수 있습니다.

Github

해당 예제의 소스 코드는 다음 Github repository 를 참조하시면 됩니다.

https://github.com/kkomzi7179/BlazorBootstrapMasonry

Learn more on this topic

Related Blog Posts

Join in the conversation

Leave a Comment

0 Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

무료 온라인 전광판

전광판

텍스트를 입력하고 텍스트 효과 및 배경효과 를 변경해서 전체화면으로 표시할 수 있는 전광판 용도로 사용하실 수 있습니다. 각종 스포츠 및 공연 관람시 응원 용도로 사용이 가능합니다.

Carousel

여러개의 슬라이드를 추가하여 프레젠테이션 및 이미지 슬라이드 용도로 사용하실 수 있습니다. 브라우저가 포함된 IT 기기로 큰 모니터에 연결하여 매장 내 공지사항 및 메뉴소개를 이미지로 표시할 수 있습니다.

Pin It on Pinterest

Shares
Share This

Share This

Share this post with your friends!

Shares