【必読】なぜ今、Aura ではなく LWR を選ぶべきなのか?

【B2B不動産ポータル 制作日誌 Vol.2】物件詳細と画像スライダーを自作する:標準コンポーネントの壁を越えるCSS/JS実装

「LWRサイト × Agentforce」 で作る不動産ポータル開発連載、第2回です。 前回(Vol.1)は、グリッドシステムを使った検索一覧画面を構築しました。

今回は、ユーザーが物件をクリックした後に遷移する 「物件詳細画面」 の実装です。
不動産サイトにおいて、詳細画面の主役は間違いなく 「物件写真」 です。 しかし、LWR (Build Your Own) 環境では、Aura時代のようなリッチな標準コンポーネント(カルーセル等)が不足しているか、デザインの自由度が低いという課題があります。

そこで今回は、「完全自作の画像スライダー (listingPhotoSlider)」 を実装しました。 ライブラリに頼らず、軽量なLWCだけで スマホのタッチスワイプ にまで対応させた実装の裏側を解説します。

DXforce Point for Developers

今回の記事で作成したコンポーネントの全ソースコードをGitHubで公開しています。 ぜひ Clone して、あなたの組織で動かしてみてください。

実装するスライダーの要件

目指すのは以下のような本格的なビューワーです。

  1. メイン画像: 大きく表示し、左右の矢印で切り替え可能。
  2. スマホ対応: 指でスワイプして画像をめくれること。(PCでもドラッグしてめくれる)
  3. サムネイル: 下部に一覧を表示し、クリックでその画像にジャンプできること。
  4. CMS連携: CMSで管理された画像を表示すること。

データ取得とCMS画像パスの生成

まずはJavaScript (listingPhotoSlider.js) のデータ取得部分です。 ここで重要なのが、Salesforce CMSの画像を表示するための URL生成ロジック です。

LWRサイトでCMSメディアを表示する場合、/sfsites/c/cms/delivery/media/{ContentKey} というパスを使用します。これを動的に組み立てる必要があります。

import { LightningElement, api, wire, track } from 'lwc';
import getListingImages from '@salesforce/apex/PropertySearchController.getListingImages';
import basePath from '@salesforce/community/basePath'; // サイトのベースパスを取得

export default class ListingPhotoSlider extends LightningElement {
    @api recordId;
    @track imageUrls = [];
    
    // CMS画像のベースURL定義
    cmsBaseUrl = basePath + '/sfsites/c/cms/delivery/media/';

    @wire(getListingImages, { listingId: '$recordId' })
    wiredImages({ error, data }) {
        if (data) {
            this.imageUrls = data.map((imgObj, index) => {
                return {
                    // ベースURL + コンテンツキー で画像パスを生成
                    url: this.cmsBaseUrl + imgObj.key,
                    caption: imgObj.comment,
                    index: index,
                    // アクティブ状態の管理用フラグ
                    active: index === 0,
                    dotClass: index === 0 ? 'dot active' : 'dot',
                    thumbClass: index === 0 ? 'thumbnail active' : 'thumbnail'
                };
            });
        }
    }
    // ...
}

スワイプ操作の実装 (PC/スマホ両対応)

「ライブラリなしでスワイプ実装」と聞くと難しそうですが、実はシンプルです。 「押し始めの位置 (startX)」「離した位置 (endX)」 の差分を計算するだけです。

今回は、マウス操作(PC)とタッチ操作(スマホ)の両方のイベントをハンドルしています。

HTML:

<div class="main-image-wrapper"
     ontouchstart={handleTouchStart}
     ontouchend={handleTouchEnd}
     onmousedown={handleMouseDown}
     onmouseup={handleMouseUp}
     onmouseleave={handleMouseLeave}>
</div>

JavaScript:

// 変数定義
    startX = 0;
    endX = 0;

    // タッチ開始 (スマホ)
    handleTouchStart(event) {
        this.startX = event.changedTouches[0].screenX;
    }

    // タッチ終了 (スマホ)
    handleTouchEnd(event) {
        this.endX = event.changedTouches[0].screenX;
        this.handleSwipe();
    }

    // ドラッグ判定ロジック
    handleSwipe() {
        const threshold = 50; // 50px以上動かしたらスワイプとみなす
        
        // 右にドラッグ (startX < endX) -> 前の画像へ
        // 左にドラッグ (startX > endX) -> 次の画像へ
        
        if (this.startX - this.endX > threshold) {
            this.handleNext(); // 次へ
        } else if (this.endX - this.startX > threshold) {
            this.handlePrev(); // 前へ
        }
        
        // 座標リセット
        this.startX = 0;
        this.endX = 0;
    }

この数十行のコードを入れるだけで、スマホでの操作性が劇的に向上します。LWRサイトはモバイルで閲覧されることが多いため、必須のテクニックです。

CSSによるデザイン制御

最後にスタイル (listingPhotoSlider.css) です。 画像の表示方法として、今回は以下の使い分けを行いました。

  • メイン画像: object-fit: contain
    • 理由: 不動産画像は全体が見えることが重要。トリミングされて部屋の広さが伝わらなくなるのを防ぐため、余白ができても全体を表示させます。
  • サムネイル: object-fit: cover
    • 理由: 小さな枠内で綺麗に並べるため、トリミングして埋めます。
.main-image-wrapper {
    position: relative;
    width: 100%;
    height: 400px;
    background-color: #f4f6f9;
    /* ドラッグ可能であることを示すカーソル */
    cursor: grab; 
    user-select: none; 
}

/* ドラッグ中のUX向上 */
.main-image-wrapper:active {
    cursor: grabbing;
}

.main-image {
    width: 100%;
    height: 100%;
    object-fit: contain; /* アスペクト比を維持して全体を表示 */
}

/* サムネイルのアクティブ表示 */
.thumbnail.active {
    opacity: 1;
    border-color: #0176d3; /* 選択中の画像を枠線で強調 */
}

まとめ

今回は、LWRサイト上で動作する 「カスタム画像スライダー」 を実装しました。

  • CMSパス生成: basePath を活用して正しいURLを生成する。
  • タッチイベント: touchstart / touchend で座標差分を取り、スワイプを検知する。
  • CSS: object-fit を使い分け、UXの高いビューワーを作る。

標準コンポーネントがないなら作ればいい。 LWCの基本機能だけで、ここまでリッチなUIが作れるのもLWR開発の醍醐味です。

次回 Vol.3 では、この詳細画面に 「リアルタイム空室カレンダー」 を埋め込みます。 単なる予約データ登録フォームではなく、「その場で予約が確定する」システムをどう構築するか? Apexによる複雑なデータ処理に挑みます。

DXforceの管理人

福島 瑛二

2013年にJavaエンジニアとしてのキャリアをスタート。2019年にSalesforceと出会い、Salesforceエンジニアの道へ。

デザインや UI/UX の観点からもシステムを捉え、ユーザーにとって心地よい体験を実装することにやりがいを感じています。

CRM(顧客データ)や Data Cloud と連携した高度なサイトを目に見える形で表現できる Experience Cloud に大きな可能性を見出しており、バックエンドのデータ構造とフロントエンドの表現力を極めることがこれからの Salesforce エンジニアに求められるスキルだと確信しています。

Trailblazer: efukushima

福島 瑛二をフォローする

読者の声

タイトルとURLをコピーしました