Slickが非推奨になって久しいですが、まだjQuery + Slickで動いているスライダーが残っていたので、jQuery脱却のタイミングでSwiperへ移行しました。今更すぎる内容ではありますが、オプションやエフェクト周りを毎回調べ直すのも手間なので、自分用のメモとしてまとめておきます。

CDNで導入する

npmでインストールする方法もありますが、WordPress案件ではCDNで読み込むのが手軽です。バージョンを固定しておくのがポイントです。

<!-- Swiper CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.css">

<!-- Swiper JS -->
<script src="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.js"></script>

swiper-bundleを使えば全モジュール入りで読み込めます。個別モジュールだけ使いたい場合はnpm経由でtree-shakingするのが正攻法ですが、CDN運用ならbundle一択で問題ありません。

基本のHTML構造

Slickとの最大の違いはHTML構造です。Slickは.slider > .slideの2階層でしたが、Swiperは.swiper > .swiper-wrapper > .swiper-slideの3階層構造になります。ナビゲーションやページネーションの要素も.swiperの中に含めます。

CodePen ソースコードサンプル

<!-- Swiperの基本構造 -->
<div class="swiper">
  <div class="swiper-wrapper">
    <div class="swiper-slide"><img src="slide1.jpg" alt=""></div>
    <div class="swiper-slide"><img src="slide2.jpg" alt=""></div>
    <div class="swiper-slide"><img src="slide3.jpg" alt=""></div>
  </div>

  <!-- ナビゲーション(前へ / 次へ) -->
  <div class="swiper-button-prev"></div>
  <div class="swiper-button-next"></div>

  <!-- ページネーション(ドット) -->
  <div class="swiper-pagination"></div>

  <!-- スクロールバー(任意) -->
  <div class="swiper-scrollbar"></div>
</div>

基本の初期化

jQueryは不要です。new Swiper()でインスタンスを生成するだけで動きます。

const swiper = new Swiper('.swiper', {
  loop: true,
  speed: 300,

  autoplay: {
    delay: 3000,
    disableOnInteraction: false,
  },

  navigation: {
    nextEl: '.swiper-button-next',
    prevEl: '.swiper-button-prev',
  },

  pagination: {
    el: '.swiper-pagination',
    clickable: true,
  },
});

Slick → Swiper オプション対応表

移行時に毎回迷うところなので、主要なオプションの対応をまとめました。

// ===== Slick → Swiper 対応表 =====
// Slick: autoplay: true, autoplaySpeed: 3000
autoplay: { delay: 3000 },
// Slick: infinite: true
loop: true,
// Slick: speed: 300
speed: 300,
// Slick: slidesToShow: 3
slidesPerView: 3,
// Slick: slidesToScroll: 1
slidesPerGroup: 1,
// Slick: dots: true
pagination: { el: '.swiper-pagination', clickable: true },
// Slick: arrows: true
navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev' },
// Slick: fade: true
effect: 'fade', fadeEffect: { crossFade: true },
// Slick: centerMode: true, centerPadding: '60px'
centeredSlides: true,
// Slick: variableWidth: true
slidesPerView: 'auto',
// Slick: adaptiveHeight: true
autoHeight: true,
// Slick: draggable: false
allowTouchMove: false,
// Slick: vertical: true
direction: 'vertical',
// Slick: rtl: true
// HTML側に dir="rtl" を追加するだけでOK

全オプション一覧

実務でよく使うものを中心に、カテゴリ別に整理しました。

基本オプション

const swiper = new Swiper('.swiper', {
  // スライドの方向('horizontal' | 'vertical')
  direction: 'horizontal',
  // アニメーション速度(ms)
  speed: 300,
  // 初期表示のスライド番号(0始まり)
  initialSlide: 0,
  // スライドの高さを自動調整
  autoHeight: false,
  // CSSモード(CSS Scroll Snapを使用、軽量だが一部制限あり)
  cssMode: false,
  // 掴むカーソルを表示
  grabCursor: true,
  // ラッパー要素のタグ名を変更
  wrapperClass: 'swiper-wrapper',
  slideClass: 'swiper-slide',
  slideActiveClass: 'swiper-slide-active',
});

スライド表示・レイアウト

const swiper = new Swiper('.swiper', {
  // 表示するスライド数(数値 or 'auto')
  slidesPerView: 1,
  // 一度にスクロールするスライド数
  slidesPerGroup: 1,
  // スライド間の余白(px)
  spaceBetween: 0,
  // アクティブスライドを中央に配置
  centeredSlides: false,
  // 中央配置時に端を埋める
  centeredSlidesBounds: false,
  // スライダー前後の余白(px)
  slidesOffsetBefore: 0,
  slidesOffsetAfter: 0,
  // グリッド表示(複数行)
  grid: {
    rows: 1,       // 行数
    fill: 'column', // 'column' | 'row'
  },
});

ループ・自動再生

const swiper = new Swiper('.swiper', {
  // 無限ループ
  loop: true,
  // ループ時にスライドを巻き戻す
  rewind: false, // loop: false の時に使う。最後→最初に戻る
  // 自動再生
  autoplay: {
    delay: 3000,                // スライド間隔(ms)
    disableOnInteraction: false, // 操作後も自動再生を継続
    pauseOnMouseEnter: true,     // ホバーで一時停止
    stopOnLastSlide: false,      // 最後のスライドで停止(loop: false時)
    reverseDirection: false,     // 逆方向に自動再生
    waitForTransition: true,     // トランジション完了を待つ
  },
});

タッチ・マウス操作

const swiper = new Swiper('.swiper', {
  // タッチ操作を許可
  allowTouchMove: true,
  // マウスドラッグを有効
  simulateTouch: true,
  // タッチの感度(デフォルト: 1)
  touchRatio: 1,
  // スワイプ認識の角度(度)
  touchAngle: 45,
  // ショートスワイプを有効
  shortSwipes: true,
  // ロングスワイプを有効
  longSwipes: true,
  // ロングスワイプのしきい値
  longSwipesRatio: 0.5,
  longSwipesMs: 300,
  // スワイプ認識の最小距離(px)
  threshold: 5,
  // 端での抵抗
  resistance: true,
  resistanceRatio: 0.85,
  // 特定要素でのスワイプを無効化
  noSwiping: true,
  noSwipingClass: 'swiper-no-swiping',
  noSwipingSelector: 'input, textarea',
  // タッチ開始時のイベント伝播
  touchStartPreventDefault: true,
  touchStartForcePreventDefault: false,
  touchMoveStopPropagation: false,
  // パッシブイベントリスナー
  passiveListeners: true,
});

フリーモード

const swiper = new Swiper('.swiper', {
  // フリーモード(スナップなしのスクロール)
  freeMode: {
    enabled: true,
    momentum: true,          // 慣性スクロール
    momentumRatio: 1,        // 慣性の強さ
    momentumBounce: true,    // 端でのバウンス
    momentumBounceRatio: 1,  // バウンスの強さ
    momentumVelocityRatio: 1, // 速度の比率
    sticky: false,           // true: 最寄りのスライドにスナップ
  },
});

ナビゲーション

const swiper = new Swiper('.swiper', {
  navigation: {
    nextEl: '.swiper-button-next',
    prevEl: '.swiper-button-prev',
    hideOnClick: false,
    disabledClass: 'swiper-button-disabled',
    hiddenClass: 'swiper-button-hidden',
    lockClass: 'swiper-button-lock',
  },
});

ページネーション

const swiper = new Swiper('.swiper', {
  pagination: {
    el: '.swiper-pagination',
    clickable: true,
    // タイプ: 'bullets' | 'fraction' | 'progressbar' | 'custom'
    type: 'bullets',
    // ダイナミックバレット(アクティブ付近のみ表示)
    dynamicBullets: false,
    dynamicMainBullets: 1,
    // フラクション表示のフォーマット
    formatFractionCurrent: (number) => String(number).padStart(2, '0'),
    formatFractionTotal: (number) => String(number).padStart(2, '0'),
    // カスタムバレットのレンダリング
    renderBullet: (index, className) => {
      return `<span class="${className}">${index + 1}</span>`;
    },
    // カスタムフラクションのレンダリング
    renderFraction: (currentClass, totalClass) => {
      return `<span class="${currentClass}"></span> / <span class="${totalClass}"></span>`;
    },
    // カスタムプログレスバーのレンダリング
    renderProgressbar: (progressbarFillClass) => {
      return `<span class="${progressbarFillClass}"></span>`;
    },
  },
});

スクロールバー

const swiper = new Swiper('.swiper', {
  scrollbar: {
    el: '.swiper-scrollbar',
    draggable: true,     // ドラッグ可能
    hide: false,         // 操作後に自動で隠す
    snapOnRelease: true, // リリース時にスナップ
  },
});

キーボード・マウスホイール

const swiper = new Swiper('.swiper', {
  // キーボード操作
  keyboard: {
    enabled: true,
    onlyInViewport: true,  // ビューポート内でのみ有効
    pageUpDown: true,       // PageUp/PageDownキーも使用
  },
  // マウスホイール
  mousewheel: {
    enabled: true,
    forceToAxis: true,       // 軸方向のみに制限
    sensitivity: 1,          // 感度
    releaseOnEdges: false,   // 端でページスクロールを許可
    invert: false,           // スクロール方向を反転
    eventsTarget: 'wrapper', // イベント対象の要素
    thresholdDelta: null,    // 最小デルタ値
    thresholdTime: null,     // 最小時間間隔
  },
});

その他のオプション

const swiper = new Swiper('.swiper', {
  // パララックス効果
  parallax: true,
  // ズーム
  zoom: {
    maxRatio: 3,
    minRatio: 1,
    toggle: true, // ダブルタップでズーム切替
  },
  // サムネイル連携
  thumbs: {
    swiper: thumbSwiper, // サムネイル用Swiperインスタンス
    autoScrollOffset: 1,
  },
  // コントローラー(複数Swiperの同期)
  controller: {
    control: anotherSwiper,
    by: 'slide', // 'slide' | 'container'
    inverse: false,
  },
  // ハッシュナビゲーション
  hashNavigation: {
    watchState: true,
    replaceState: false,
  },
  // History API
  history: {
    enabled: true,
    root: '/',
    replaceState: false,
    key: 'slide',
  },
  // アクセシビリティ
  a11y: {
    enabled: true,
    prevSlideMessage: '前のスライド',
    nextSlideMessage: '次のスライド',
    firstSlideMessage: '最初のスライドです',
    lastSlideMessage: '最後のスライドです',
    paginationBulletMessage: 'スライド {{index}} に移動',
  },
  // バーチャルスライド(大量スライド向け)
  virtual: {
    enabled: true,
    slides: ['Slide 1', 'Slide 2', 'Slide 3'],
    addSlidesAfter: 0,
    addSlidesBefore: 0,
    cache: true,
    renderSlide: (slide, index) => {
      return `<div class="swiper-slide">${slide}</div>`;
    },
  },
  // ウォッチ系
  watchSlidesProgress: false, // スライドの進行状況を監視
  watchOverflow: true,        // スライド数が少ない時にナビ非表示
  observer: false,            // DOM変更を監視して自動更新
  observeParents: false,      // 親要素のDOM変更も監視
  observeSlideChildren: false, // 子要素のDOM変更も監視
  // ユニークなナビゲーション要素(複数Swiper配置時)
  uniqueNavElements: true,
});

全エフェクト一覧

Swiperには6種類のエフェクトが用意されています。effectオプションで指定し、各エフェクト固有のオプションで微調整できます。

slide(デフォルト)

通常のスライドアニメーションです。特に指定しなければこれが適用されます。

const swiper = new Swiper('.swiper', {
  effect: 'slide', // デフォルトなので省略可
});

fade

フェードイン・フェードアウトで切り替わります。crossFade: trueにしないと前のスライドが透けて見えるので注意してください。

const swiper = new Swiper('.swiper', {
  effect: 'fade',
  fadeEffect: {
    crossFade: true, // これを入れないと重なって表示される
  },
});

cube

3Dキューブ回転です。見た目のインパクトはありますが、実務では使いどころを選びます。

const swiper = new Swiper('.swiper', {
  effect: 'cube',
  cubeEffect: {
    shadow: true,        // 影を表示
    slideShadows: true,  // スライドに影を表示
    shadowOffset: 20,    // 影のオフセット(px)
    shadowScale: 0.94,   // 影のスケール
  },
});

coverflow

iTunesのカバーフロー風のエフェクトです。複数スライドを表示する場合によく使います。

const swiper = new Swiper('.swiper', {
  effect: 'coverflow',
  slidesPerView: 'auto',
  centeredSlides: true,
  coverflowEffect: {
    rotate: 50,         // Y軸の回転角度
    stretch: 0,         // スライド間の引き伸ばし
    depth: 100,         // 奥行きのオフセット(px)
    modifier: 1,        // エフェクトの倍率
    slideShadows: true, // スライドの影
    scale: 1,           // スライドのスケール
  },
});

flip

カードを裏返すようなフリップアニメーションです。

const swiper = new Swiper('.swiper', {
  effect: 'flip',
  flipEffect: {
    slideShadows: true,  // スライドの影
    limitRotation: true, // 回転角度を制限
  },
});

cards

カードが積み重なった状態から1枚ずつめくるエフェクトです。Tinder風のUIに近いイメージです。

const swiper = new Swiper('.swiper', {
  effect: 'cards',
  cardsEffect: {
    slideShadows: true,  // スライドの影
    perSlideOffset: 8,   // スライドごとのオフセット(px)
    perSlideRotate: 2,   // スライドごとの回転角度
    rotate: true,        // 回転を有効にする
  },
});

creative

完全にカスタムのアニメーションを作れるエフェクトです。前後のスライドの位置・回転・スケール・透明度を自由に指定できます。

const swiper = new Swiper('.swiper', {
  effect: 'creative',
  creativeEffect: {
    // 前のスライドの状態
    prev: {
      translate: [0, 0, -400],   // [x, y, z](px or '%')
      rotate: [0, 0, 0],         // [x, y, z](度)
      opacity: 0,                // 透明度
      scale: 1,                  // スケール
      shadow: true,              // 影
    },
    // 次のスライドの状態
    next: {
      translate: ['100%', 0, 0],
      rotate: [0, 0, 0],
      opacity: 1,
      scale: 1,
      shadow: true,
    },
    // オプション
    perspective: true,   // 3Dパースペクティブを有効
    limitProgress: 1,    // プログレスの最大値
    shadowPerProgress: false,
    progressMultiplier: 1,
  },
});
// ===== creativeEffect の実用例 =====
// 例1: 下からスライドイン
creativeEffect: {
  prev: { translate: [0, '-100%', 0] },
  next: { translate: [0, '100%', 0] },
},
// 例2: 回転しながら消える
creativeEffect: {
  prev: { translate: ['-120%', 0, -500], rotate: [0, 0, -15], opacity: 0 },
  next: { translate: ['120%', 0, -500], rotate: [0, 0, 15], opacity: 0 },
},
// 例3: スケールダウンしてフェードアウト
creativeEffect: {
  prev: { translate: ['-20%', 0, -200], scale: 0.8, opacity: 0 },
  next: { translate: ['100%', 0, 0] },
},

レスポンシブ設定(breakpoints)

Slickのresponsive配列(max-width基準・降順)とは異なり、Swiperのbreakpointsはmin-width基準・昇順で記述します。モバイルファーストの設計と相性が良いです。

const swiper = new Swiper('.swiper', {
  // デフォルト(モバイル)
  slidesPerView: 1,
  spaceBetween: 10,
  breakpoints: {
    // 768px以上
    768: {
      slidesPerView: 2,
      spaceBetween: 20,
    },
    // 1024px以上
    1024: {
      slidesPerView: 3,
      spaceBetween: 30,
    },
    // 1200px以上
    1200: {
      slidesPerView: 4,
      spaceBetween: 40,
    },
  },
});

PCのみ / SPのみでSwiperを適用する

案件でよくある「SPではスライダー、PCでは横並び」や「PCではスライダー、SPでは縦積み」のパターンです。matchMediaを使ってSwiperの初期化・破棄を制御します。

SPのみSwiper(768px未満で適用)

const breakpoint = 768;
let swiper = null;
const initSwiper = () => {
  if (window.innerWidth < breakpoint) {
    if (!swiper) {
      swiper = new Swiper('.swiper', {
        slidesPerView: 1.2,
        spaceBetween: 16,
        pagination: {
          el: '.swiper-pagination',
          clickable: true,
        },
      });
    }
  } else {
    // PC表示: Swiperを破棄
    if (swiper) {
      swiper.destroy(true, true);
      swiper = null;
    }
  }
};
// 初期化
initSwiper();
// リサイズ時に再判定(デバウンス推奨)
let resizeTimer;
window.addEventListener('resize', () => {
  clearTimeout(resizeTimer);
  resizeTimer = setTimeout(initSwiper, 250);
});

PCのみSwiper(768px以上で適用)

const breakpoint = 768;
let swiper = null;
const initSwiper = () => {
  if (window.innerWidth >= breakpoint) {
    if (!swiper) {
      swiper = new Swiper('.swiper', {
        slidesPerView: 3,
        spaceBetween: 24,
        navigation: {
          nextEl: '.swiper-button-next',
          prevEl: '.swiper-button-prev',
        },
      });
    }
  } else {
    if (swiper) {
      swiper.destroy(true, true);
      swiper = null;
    }
  }
};
initSwiper();
let resizeTimer;
window.addEventListener('resize', () => {
  clearTimeout(resizeTimer);
  resizeTimer = setTimeout(initSwiper, 250);
});

matchMediaを使ったよりスマートな方法

window.matchMediaを使うとリサイズイベントのデバウンス処理が不要になります。ブレークポイントを跨いだ時だけコールバックが発火するので効率的です。

// SPのみSwiperを適用(matchMedia版)
let swiper = null;
const mediaQuery = window.matchMedia('(max-width: 767px)');
const handleMediaChange = (e) => {
  if (e.matches) {
    // SP: Swiperを初期化
    swiper = new Swiper('.swiper', {
      slidesPerView: 1.2,
      spaceBetween: 16,
      pagination: {
        el: '.swiper-pagination',
        clickable: true,
      },
    });
  } else {
    // PC: Swiperを破棄
    if (swiper) {
      swiper.destroy(true, true);
      swiper = null;
    }
  }
};
// 初期判定 + リスナー登録
handleMediaChange(mediaQuery);
mediaQuery.addEventListener('change', handleMediaChange);

Swiper破棄時のCSS補足

destroy()するとSwiperのインラインスタイルが除去されますが、CSSでPC時のレイアウトを別途指定しておく必要があります。

/* SPではSwiperが適用されるのでスタイル不要 */
/* PCではSwiperが破棄されるので横並びに */
@media (min-width: 768px) {
  .swiper-wrapper {
    display: flex;
    gap: 24px;
  }
  .swiper-slide {
    flex: 1;
  }
  /* ナビゲーション・ページネーションを非表示 */
  .swiper-pagination,
  .swiper-button-prev,
  .swiper-button-next {
    display: none;
  }
}

イベントハンドラ

スライド切り替え時の処理や外部との連携で使うイベントをまとめます。

const swiper = new Swiper('.swiper', {
  on: {
    // 初期化完了
    init: function () {
      console.log('初期化完了:', this.activeIndex);
    },
    // スライド変更(アニメーション開始時)
    slideChange: function () {
      console.log('現在のスライド:', this.realIndex);
    },
    // トランジション開始
    slideChangeTransitionStart: function () {},
    // トランジション完了
    slideChangeTransitionEnd: function () {},
    // タッチ開始
    touchStart: function (swiper, event) {},
    // タッチ移動中
    touchMove: function (swiper, event) {},
    // タッチ終了
    touchEnd: function (swiper, event) {},
    // リサイズ
    resize: function () {},
    // 最初のスライドに到達
    reachBeginning: function () {},
    // 最後のスライドに到達
    reachEnd: function () {},
    // 進行状況の変更
    progress: function (swiper, progress) {},
    // Swiper破棄時
    destroy: function () {},
  },
});
// 初期化後にイベントを追加する場合
swiper.on('slideChange', function () {
  console.log('後から追加したイベント');
});
// イベントを1回だけ実行
swiper.once('slideChange', function () {
  console.log('1回だけ実行');
});

メソッド一覧

外部からSwiperを操作する際に使う主要メソッドです。

// 次のスライドへ
swiper.slideNext();
swiper.slideNext(300); // 速度指定
// 前のスライドへ
swiper.slidePrev();
// 指定スライドへ移動
swiper.slideTo(2);       // インデックス指定
swiper.slideTo(2, 300);  // 速度指定
// 自動再生の制御
swiper.autoplay.start();
swiper.autoplay.stop();
swiper.autoplay.pause();
// Swiperの更新(DOM変更後に実行)
swiper.update();
// Swiperの破棄
swiper.destroy(true, true);
// 第1引数: DOMをクリーンアップするか
// 第2引数: イベントリスナーを削除するか
// 現在の状態を取得
swiper.activeIndex;  // アクティブスライドのインデックス
swiper.realIndex;    // ループ時の実際のインデックス
swiper.previousIndex; // 前のスライドのインデックス
swiper.isBeginning;  // 最初のスライドかどうか
swiper.isEnd;        // 最後のスライドかどうか

サムネイル付きスライダーの実装

メインスライダーとサムネイルスライダーを連動させるパターンです。案件でもよく使います。

<!-- メインスライダー -->
<div class="swiper swiper-main">
  <div class="swiper-wrapper">
    <div class="swiper-slide"><img src="img1.jpg" alt=""></div>
    <div class="swiper-slide"><img src="img2.jpg" alt=""></div>
    <div class="swiper-slide"><img src="img3.jpg" alt=""></div>
    <div class="swiper-slide"><img src="img4.jpg" alt=""></div>
  </div>
</div>
<!-- サムネイルスライダー -->
<div class="swiper swiper-thumb">
  <div class="swiper-wrapper">
    <div class="swiper-slide"><img src="img1-thumb.jpg" alt=""></div>
    <div class="swiper-slide"><img src="img2-thumb.jpg" alt=""></div>
    <div class="swiper-slide"><img src="img3-thumb.jpg" alt=""></div>
    <div class="swiper-slide"><img src="img4-thumb.jpg" alt=""></div>
  </div>
</div>
// サムネイルスライダーを先に初期化
const thumbSwiper = new Swiper('.swiper-thumb', {
  slidesPerView: 4,
  spaceBetween: 10,
  watchSlidesProgress: true,
});
// メインスライダー
const mainSwiper = new Swiper('.swiper-main', {
  effect: 'fade',
  fadeEffect: { crossFade: true },
  thumbs: {
    swiper: thumbSwiper,
  },
});

ナビゲーションのCSSカスタマイズ

デフォルトの矢印やドットをカスタマイズする場合のCSSです。Swiperのデフォルトスタイルを上書きして使います。

/* ===== 矢印ボタンのカスタマイズ ===== */
.swiper-button-prev,
.swiper-button-next {
  /* デフォルトの色を変更 */
  --swiper-navigation-color: #333;
  --swiper-navigation-size: 24px;
  /* 背景付きの丸ボタンにする場合 */
  width: 48px;
  height: 48px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.swiper-button-prev::after,
.swiper-button-next::after {
  font-size: 16px;
  font-weight: bold;
}
/* ===== ページネーション(ドット)のカスタマイズ ===== */
.swiper-pagination-bullet {
  --swiper-pagination-color: #333;
  --swiper-pagination-bullet-inactive-color: #ccc;
  --swiper-pagination-bullet-inactive-opacity: 0.5;
  --swiper-pagination-bullet-size: 10px;
  --swiper-pagination-bullet-horizontal-gap: 6px;
}
/* アクティブなドットを横長にする */
.swiper-pagination-bullet-active {
  width: 24px;
  border-radius: 5px;
  transition: width 0.3s;
}
/* ===== プログレスバーのカスタマイズ ===== */
.swiper-pagination-progressbar {
  --swiper-pagination-progressbar-bg-color: rgba(0, 0, 0, 0.1);
}
.swiper-pagination-progressbar-fill {
  --swiper-pagination-color: #333;
}

まとめ

jQuery + Slickの組み合わせからSwiperに移行すると、jQueryへの依存がなくなるだけでなく、エフェクトやレスポンシブ設定の自由度が格段に上がります。個人的に移行時に引っかかりやすいポイントとしては、HTML構造が3階層になること、breakpointsがmin-width基準であること、fadeEffectcrossFade: trueを忘れること、の3つです。都度オプションを調べ直す手間を省くためにまとめた記事ですが、何かの参考になれば幸いです。