「LWRサイト × Agentforce」 で作る不動産ポータル開発連載、第2回です。 前回(Vol.1)は、グリッドシステムを使った検索一覧画面を構築しました。
今回は、ユーザーが物件をクリックした後に遷移する 「物件詳細画面」 の実装です。
不動産サイトにおいて、詳細画面の主役は間違いなく 「物件写真」 です。 しかし、LWR (Build Your Own) 環境では、Aura時代のようなリッチな標準コンポーネント(カルーセル等)が不足しているか、デザインの自由度が低いという課題があります。
そこで今回は、「完全自作の画像スライダー (listingPhotoSlider)」 を実装しました。 ライブラリに頼らず、軽量なLWCだけで スマホのタッチスワイプ にまで対応させた実装の裏側を解説します。
今回の記事で作成したコンポーネントの全ソースコードをGitHubで公開しています。 ぜひ Clone して、あなたの組織で動かしてみてください。
実装するスライダーの要件
目指すのは以下のような本格的なビューワーです。
- メイン画像: 大きく表示し、左右の矢印で切り替え可能。
- スマホ対応: 指でスワイプして画像をめくれること。(PCでもドラッグしてめくれる)
- サムネイル: 下部に一覧を表示し、クリックでその画像にジャンプできること。
- 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による複雑なデータ処理に挑みます。





読者の声