Skip to main content
Version: v6

ion-slides

コンテンツ

note

This component has been deprecated in favor of using Swiper.js directly. Please see the migration guide below.

Slidesコンポーネントは複数セクションのコンテナです。 各セクション間をスワイプまたはドラッグできます。これには任意の数のSlideコンポーネントが含まれます。

このガイドでは、廃止予定の ion-slides コンポーネントから、Swiper.jsが提供するフレームワーク固有のソリューションへの移行、および、まだそのコンポーネントを使用している開発者向けの既存の ion-slides API について説明します。

Swiper.jsを採用しています: ハードウェアアクセラレートされたトランジションを備えた最新のモバイルタッチスライダとフレームワークです。

http://www.idangero.us/swiper/

Copyright 2016, Vladimir Kharlampidi The iDangero.us http://www.idangero.us/

Licensed under MIT

移行

Ionic Framework v6のリリースに伴い、Ionicチームは ion-slidesion-slide コンポーネントを非推奨とし、Swiperが提供する公式フレームワーク統合を使用することを決定しました。心配はご無用です。Ionicチームは ion-slidesion-slide コンポーネントを廃止しましたが、Swiperを使用しているため、slidesコンポーネントの機能は全く変わりません。

Swiper.jsとは?

Swiper.jsは ion-slides を駆動するカルーセル/スライダーライブラリです。このライブラリは、Ionic Frameworkのすべてのバージョンに自動的にバンドルされています。Ionic Framework v4.がリリースされた当初、Swiperにはフレームワーク固有のライブラリ統合機能がなかったため、SwiperのコアライブラリとAngular、React、Vueなどのフレームワークのギャップを埋める手段として ion-slides が作成されました。

それ以来、Swiperチームは、Angular、React、Vueなどのフレームワークに特化したSwiper.jsの統合をリリースしています。

この変更の利点は何ですか?

Ionic Frameworkコミュニティのメンバーにとって、いくつかの利点があります。公式のSwiper.jsフレームワーク統合を使用することで、。

  • 開発者は、使用したいSwiper.jsのバージョンを正確にコントロールできるようになりました。これまで開発者は、Ionicチームが内部でバージョンを更新し、Ionic Frameworkの新バージョンをリリースすることに依存する必要がありました。
  • Ionicチームは、スライド以外の問題のトリアージと修正により多くの時間を費やし、開発プロセスをスピードアップして、コミュニティのためにフレームワークをより良く機能させることができます。
  • 開発者はより少ないバグを経験することができます。
  • アプリケーションのバンドルサイズを縮小できる場合があります。Swiper.jsをサードパーティの依存関係としてアプリケーションにインストールすることで、WebpackやRollupなどのバンドルは、コードをよりよくトレースすることができるようになるはずです。
  • 開発者は、ion-slidesを使用する場合、以前はなかった新しい機能にアクセスすることができます。

いつまでに移行しなければならないのですか?

Ionic Framework v7 で ion-slidesion-slide を削除する予定です。 ion-slidesion-slide は Ionic Framework v6 のライフサイクルを通して引き続き使用できますが、重要なバグ修正のみが行われます。

移行方法は?

スライドを動かす基本的な技術は同じなので、移行は簡単です。以下のガイドに従ってください。

Migration for Ionic Angular users

Migration for Ionic React users

Migration for Ionic Vue users


以上のドキュメントは ion-slides コンポーネントに適用されます。

カスタムアニメーション

デフォルトでは、Ionicのスライドはビルトインの slide アニメーションエフェクトを使用します。カスタムのアニメーションは options プロパティで指定できます。その他のアニメーションの例は以下をご参照ください。

Coverflow

const slideOpts = {
slidesPerView: 3,
coverflowEffect: {
rotate: 50,
stretch: 0,
depth: 100,
modifier: 1,
slideShadows: true,
},
on: {
beforeInit() {
const swiper = this;

swiper.classNames.push(`${swiper.params.containerModifierClass}coverflow`);
swiper.classNames.push(`${swiper.params.containerModifierClass}3d`);

swiper.params.watchSlidesProgress = true;
swiper.originalParams.watchSlidesProgress = true;
},
setTranslate() {
const swiper = this;
const { width: swiperWidth, height: swiperHeight, slides, $wrapperEl, slidesSizesGrid, $ } = swiper;
const params = swiper.params.coverflowEffect;
const isHorizontal = swiper.isHorizontal();
const transform$$1 = swiper.translate;
const center = isHorizontal ? -transform$$1 + swiperWidth / 2 : -transform$$1 + swiperHeight / 2;
const rotate = isHorizontal ? params.rotate : -params.rotate;
const translate = params.depth;
// Each slide offset from center
for (let i = 0, length = slides.length; i < length; i += 1) {
const $slideEl = slides.eq(i);
const slideSize = slidesSizesGrid[i];
const slideOffset = $slideEl[0].swiperSlideOffset;
const offsetMultiplier = ((center - slideOffset - slideSize / 2) / slideSize) * params.modifier;

let rotateY = isHorizontal ? rotate * offsetMultiplier : 0;
let rotateX = isHorizontal ? 0 : rotate * offsetMultiplier;
// var rotateZ = 0
let translateZ = -translate * Math.abs(offsetMultiplier);

let translateY = isHorizontal ? 0 : params.stretch * offsetMultiplier;
let translateX = isHorizontal ? params.stretch * offsetMultiplier : 0;

// Fix for ultra small values
if (Math.abs(translateX) < 0.001) translateX = 0;
if (Math.abs(translateY) < 0.001) translateY = 0;
if (Math.abs(translateZ) < 0.001) translateZ = 0;
if (Math.abs(rotateY) < 0.001) rotateY = 0;
if (Math.abs(rotateX) < 0.001) rotateX = 0;

const slideTransform = `translate3d(${translateX}px,${translateY}px,${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;

$slideEl.transform(slideTransform);
$slideEl[0].style.zIndex = -Math.abs(Math.round(offsetMultiplier)) + 1;
if (params.slideShadows) {
// Set shadows
let $shadowBeforeEl = isHorizontal
? $slideEl.find('.swiper-slide-shadow-left')
: $slideEl.find('.swiper-slide-shadow-top');
let $shadowAfterEl = isHorizontal
? $slideEl.find('.swiper-slide-shadow-right')
: $slideEl.find('.swiper-slide-shadow-bottom');
if ($shadowBeforeEl.length === 0) {
$shadowBeforeEl = swiper.$(`<div class="swiper-slide-shadow-${isHorizontal ? 'left' : 'top'}"></div>`);
$slideEl.append($shadowBeforeEl);
}
if ($shadowAfterEl.length === 0) {
$shadowAfterEl = swiper.$(`<div class="swiper-slide-shadow-${isHorizontal ? 'right' : 'bottom'}"></div>`);
$slideEl.append($shadowAfterEl);
}
if ($shadowBeforeEl.length) $shadowBeforeEl[0].style.opacity = offsetMultiplier > 0 ? offsetMultiplier : 0;
if ($shadowAfterEl.length) $shadowAfterEl[0].style.opacity = -offsetMultiplier > 0 ? -offsetMultiplier : 0;
}
}

// Set correct perspective for IE10
if (swiper.support.pointerEvents || swiper.support.prefixedPointerEvents) {
const ws = $wrapperEl[0].style;
ws.perspectiveOrigin = `${center}px 50%`;
}
},
setTransition(duration) {
const swiper = this;
swiper.slides
.transition(duration)
.find(
'.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left'
)
.transition(duration);
},
},
};

Cube

const slideOpts = {
grabCursor: true,
cubeEffect: {
shadow: true,
slideShadows: true,
shadowOffset: 20,
shadowScale: 0.94,
},
on: {
beforeInit: function () {
const swiper = this;
swiper.classNames.push(`${swiper.params.containerModifierClass}cube`);
swiper.classNames.push(`${swiper.params.containerModifierClass}3d`);

const overwriteParams = {
slidesPerView: 1,
slidesPerColumn: 1,
slidesPerGroup: 1,
watchSlidesProgress: true,
resistanceRatio: 0,
spaceBetween: 0,
centeredSlides: false,
virtualTranslate: true,
};

this.params = Object.assign(this.params, overwriteParams);
this.originalParams = Object.assign(this.originalParams, overwriteParams);
},
setTranslate: function () {
const swiper = this;
const {
$el,
$wrapperEl,
slides,
width: swiperWidth,
height: swiperHeight,
rtlTranslate: rtl,
size: swiperSize,
} = swiper;
const params = swiper.params.cubeEffect;
const isHorizontal = swiper.isHorizontal();
const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
let wrapperRotate = 0;
let $cubeShadowEl;
if (params.shadow) {
if (isHorizontal) {
$cubeShadowEl = $wrapperEl.find('.swiper-cube-shadow');
if ($cubeShadowEl.length === 0) {
$cubeShadowEl = swiper.$('<div class="swiper-cube-shadow"></div>');
$wrapperEl.append($cubeShadowEl);
}
$cubeShadowEl.css({ height: `${swiperWidth}px` });
} else {
$cubeShadowEl = $el.find('.swiper-cube-shadow');
if ($cubeShadowEl.length === 0) {
$cubeShadowEl = swiper.$('<div class="swiper-cube-shadow"></div>');
$el.append($cubeShadowEl);
}
}
}

for (let i = 0; i < slides.length; i += 1) {
const $slideEl = slides.eq(i);
let slideIndex = i;
if (isVirtual) {
slideIndex = parseInt($slideEl.attr('data-swiper-slide-index'), 10);
}
let slideAngle = slideIndex * 90;
let round = Math.floor(slideAngle / 360);
if (rtl) {
slideAngle = -slideAngle;
round = Math.floor(-slideAngle / 360);
}
const progress = Math.max(Math.min($slideEl[0].progress, 1), -1);
let tx = 0;
let ty = 0;
let tz = 0;
if (slideIndex % 4 === 0) {
tx = -round * 4 * swiperSize;
tz = 0;
} else if ((slideIndex - 1) % 4 === 0) {
tx = 0;
tz = -round * 4 * swiperSize;
} else if ((slideIndex - 2) % 4 === 0) {
tx = swiperSize + round * 4 * swiperSize;
tz = swiperSize;
} else if ((slideIndex - 3) % 4 === 0) {
tx = -swiperSize;
tz = 3 * swiperSize + swiperSize * 4 * round;
}
if (rtl) {
tx = -tx;
}

if (!isHorizontal) {
ty = tx;
tx = 0;
}

const transform$$1 = `rotateX(${isHorizontal ? 0 : -slideAngle}deg) rotateY(${
isHorizontal ? slideAngle : 0
}deg) translate3d(${tx}px, ${ty}px, ${tz}px)`;
if (progress <= 1 && progress > -1) {
wrapperRotate = slideIndex * 90 + progress * 90;
if (rtl) wrapperRotate = -slideIndex * 90 - progress * 90;
}
$slideEl.transform(transform$$1);
if (params.slideShadows) {
// Set shadows
let shadowBefore = isHorizontal
? $slideEl.find('.swiper-slide-shadow-left')
: $slideEl.find('.swiper-slide-shadow-top');
let shadowAfter = isHorizontal
? $slideEl.find('.swiper-slide-shadow-right')
: $slideEl.find('.swiper-slide-shadow-bottom');
if (shadowBefore.length === 0) {
shadowBefore = swiper.$(`<div class="swiper-slide-shadow-${isHorizontal ? 'left' : 'top'}"></div>`);
$slideEl.append(shadowBefore);
}
if (shadowAfter.length === 0) {
shadowAfter = swiper.$(`<div class="swiper-slide-shadow-${isHorizontal ? 'right' : 'bottom'}"></div>`);
$slideEl.append(shadowAfter);
}
if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0);
if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0);
}
}
$wrapperEl.css({
'-webkit-transform-origin': `50% 50% -${swiperSize / 2}px`,
'-moz-transform-origin': `50% 50% -${swiperSize / 2}px`,
'-ms-transform-origin': `50% 50% -${swiperSize / 2}px`,
'transform-origin': `50% 50% -${swiperSize / 2}px`,
});

if (params.shadow) {
if (isHorizontal) {
$cubeShadowEl.transform(
`translate3d(0px, ${swiperWidth / 2 + params.shadowOffset}px, ${
-swiperWidth / 2
}px) rotateX(90deg) rotateZ(0deg) scale(${params.shadowScale})`
);
} else {
const shadowAngle = Math.abs(wrapperRotate) - Math.floor(Math.abs(wrapperRotate) / 90) * 90;
const multiplier =
1.5 - (Math.sin((shadowAngle * 2 * Math.PI) / 360) / 2 + Math.cos((shadowAngle * 2 * Math.PI) / 360) / 2);
const scale1 = params.shadowScale;
const scale2 = params.shadowScale / multiplier;
const offset$$1 = params.shadowOffset;
$cubeShadowEl.transform(
`scale3d(${scale1}, 1, ${scale2}) translate3d(0px, ${swiperHeight / 2 + offset$$1}px, ${
-swiperHeight / 2 / scale2
}px) rotateX(-90deg)`
);
}
}

const zFactor = swiper.browser.isSafari || swiper.browser.isUiWebView ? -swiperSize / 2 : 0;
$wrapperEl.transform(
`translate3d(0px,0,${zFactor}px) rotateX(${swiper.isHorizontal() ? 0 : wrapperRotate}deg) rotateY(${
swiper.isHorizontal() ? -wrapperRotate : 0
}deg)`
);
},
setTransition: function (duration) {
const swiper = this;
const { $el, slides } = swiper;
slides
.transition(duration)
.find(
'.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left'
)
.transition(duration);
if (swiper.params.cubeEffect.shadow && !swiper.isHorizontal()) {
$el.find('.swiper-cube-shadow').transition(duration);
}
},
},
};

Fade

const slideOpts = {
on: {
beforeInit() {
const swiper = this;
swiper.classNames.push(`${swiper.params.containerModifierClass}fade`);
const overwriteParams = {
slidesPerView: 1,
slidesPerColumn: 1,
slidesPerGroup: 1,
watchSlidesProgress: true,
spaceBetween: 0,
virtualTranslate: true,
};
swiper.params = Object.assign(swiper.params, overwriteParams);
swiper.params = Object.assign(swiper.originalParams, overwriteParams);
},
setTranslate() {
const swiper = this;
const { slides } = swiper;
for (let i = 0; i < slides.length; i += 1) {
const $slideEl = swiper.slides.eq(i);
const offset$$1 = $slideEl[0].swiperSlideOffset;
let tx = -offset$$1;
if (!swiper.params.virtualTranslate) tx -= swiper.translate;
let ty = 0;
if (!swiper.isHorizontal()) {
ty = tx;
tx = 0;
}
const slideOpacity = swiper.params.fadeEffect.crossFade
? Math.max(1 - Math.abs($slideEl[0].progress), 0)
: 1 + Math.min(Math.max($slideEl[0].progress, -1), 0);
$slideEl
.css({
opacity: slideOpacity,
})
.transform(`translate3d(${tx}px, ${ty}px, 0px)`);
}
},
setTransition(duration) {
const swiper = this;
const { slides, $wrapperEl } = swiper;
slides.transition(duration);
if (swiper.params.virtualTranslate && duration !== 0) {
let eventTriggered = false;
slides.transitionEnd(() => {
if (eventTriggered) return;
if (!swiper || swiper.destroyed) return;
eventTriggered = true;
swiper.animating = false;
const triggerEvents = ['webkitTransitionEnd', 'transitionend'];
for (let i = 0; i < triggerEvents.length; i += 1) {
$wrapperEl.trigger(triggerEvents[i]);
}
});
}
},
},
};

Flip

const slideOpts = {
on: {
beforeInit() {
const swiper = this;
swiper.classNames.push(`${swiper.params.containerModifierClass}flip`);
swiper.classNames.push(`${swiper.params.containerModifierClass}3d`);
const overwriteParams = {
slidesPerView: 1,
slidesPerColumn: 1,
slidesPerGroup: 1,
watchSlidesProgress: true,
spaceBetween: 0,
virtualTranslate: true,
};
swiper.params = Object.assign(swiper.params, overwriteParams);
swiper.originalParams = Object.assign(swiper.originalParams, overwriteParams);
},
setTranslate() {
const swiper = this;
const { $, slides, rtlTranslate: rtl } = swiper;
for (let i = 0; i < slides.length; i += 1) {
const $slideEl = slides.eq(i);
let progress = $slideEl[0].progress;
if (swiper.params.flipEffect.limitRotation) {
progress = Math.max(Math.min($slideEl[0].progress, 1), -1);
}
const offset$$1 = $slideEl[0].swiperSlideOffset;
const rotate = -180 * progress;
let rotateY = rotate;
let rotateX = 0;
let tx = -offset$$1;
let ty = 0;
if (!swiper.isHorizontal()) {
ty = tx;
tx = 0;
rotateX = -rotateY;
rotateY = 0;
} else if (rtl) {
rotateY = -rotateY;
}

$slideEl[0].style.zIndex = -Math.abs(Math.round(progress)) + slides.length;

if (swiper.params.flipEffect.slideShadows) {
// Set shadows
let shadowBefore = swiper.isHorizontal()
? $slideEl.find('.swiper-slide-shadow-left')
: $slideEl.find('.swiper-slide-shadow-top');
let shadowAfter = swiper.isHorizontal()
? $slideEl.find('.swiper-slide-shadow-right')
: $slideEl.find('.swiper-slide-shadow-bottom');
if (shadowBefore.length === 0) {
shadowBefore = swiper.$(
`<div class="swiper-slide-shadow-${swiper.isHorizontal() ? 'left' : 'top'}"></div>`
);
$slideEl.append(shadowBefore);
}
if (shadowAfter.length === 0) {
shadowAfter = swiper.$(
`<div class="swiper-slide-shadow-${swiper.isHorizontal() ? 'right' : 'bottom'}"></div>`
);
$slideEl.append(shadowAfter);
}
if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0);
if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0);
}
$slideEl.transform(`translate3d(${tx}px, ${ty}px, 0px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`);
}
},
setTransition(duration) {
const swiper = this;
const { slides, activeIndex, $wrapperEl } = swiper;
slides
.transition(duration)
.find(
'.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left'
)
.transition(duration);
if (swiper.params.virtualTranslate && duration !== 0) {
let eventTriggered = false;
// eslint-disable-next-line
slides.eq(activeIndex).transitionEnd(function onTransitionEnd() {
if (eventTriggered) return;
if (!swiper || swiper.destroyed) return;

eventTriggered = true;
swiper.animating = false;
const triggerEvents = ['webkitTransitionEnd', 'transitionend'];
for (let i = 0; i < triggerEvents.length; i += 1) {
$wrapperEl.trigger(triggerEvents[i]);
}
});
}
},
},
};

使い方

import { Component } from '@angular/core';

@Component({
selector: 'slides-example',
template: `
<ion-content>
<ion-slides pager="true" [options]="slideOpts">
<ion-slide>
<h1>Slide 1</h1>
</ion-slide>
<ion-slide>
<h1>Slide 2</h1>
</ion-slide>
<ion-slide>
<h1>Slide 3</h1>
</ion-slide>
</ion-slides>
</ion-content>
`,
})
export class SlideExample {
// Optional parameters to pass to the swiper instance.
// See https://swiperjs.com/swiper-api for valid options.
slideOpts = {
initialSlide: 1,
speed: 400,
};
constructor() {}
}
/* Without setting height the slides will take up the height of the slide's content */
ion-slides {
height: 100%;
}

プロパティ

mode

DescriptionThe mode determines which platform styles to use.
Attributemode
Type"ios" | "md"
Defaultundefined

options

DescriptionOptions to pass to the swiper instance. See https://swiperjs.com/swiper-api for valid options
Attributeoptions
Typeany
Default{}

pager

DescriptionIf true, show the pagination.
Attributepager
Typeboolean
Defaultfalse

scrollbar

DescriptionIf true, show the scrollbar.
Attributescrollbar
Typeboolean
Defaultfalse

イベント

NameDescription
ionSlideDidChangeEmitted after the active slide has changed.
ionSlideDoubleTapEmitted when the user double taps on the slide's container.
ionSlideDragEmitted when the slider is actively being moved.
ionSlideNextEndEmitted when the next slide has ended.
ionSlideNextStartEmitted when the next slide has started.
ionSlidePrevEndEmitted when the previous slide has ended.
ionSlidePrevStartEmitted when the previous slide has started.
ionSlideReachEndEmitted when the slider is at the last slide.
ionSlideReachStartEmitted when the slider is at its initial position.
ionSlidesDidLoadEmitted after Swiper initialization
ionSlideTapEmitted when the user taps/clicks on the slide's container.
ionSlideTouchEndEmitted when the user releases the touch.
ionSlideTouchStartEmitted when the user first touches the slider.
ionSlideTransitionEndEmitted when the slide transition has ended.
ionSlideTransitionStartEmitted when the slide transition has started.
ionSlideWillChangeEmitted before the active slide has changed.

メソッド

getActiveIndex

DescriptionGet the index of the active slide.
SignaturegetActiveIndex() => Promise<number>

getPreviousIndex

DescriptionGet the index of the previous slide.
SignaturegetPreviousIndex() => Promise<number>

getSwiper

DescriptionGet the Swiper instance. Use this to access the full Swiper API. See https://swiperjs.com/swiper-api for all API options.
SignaturegetSwiper() => Promise<any>

isBeginning

DescriptionGet whether or not the current slide is the first slide.
SignatureisBeginning() => Promise<boolean>

isEnd

DescriptionGet whether or not the current slide is the last slide.
SignatureisEnd() => Promise<boolean>

length

DescriptionGet the total number of slides.
Signaturelength() => Promise<number>

lockSwipeToNext

DescriptionLock or unlock the ability to slide to the next slide.
SignaturelockSwipeToNext(lock: boolean) => Promise<void>

lockSwipeToPrev

DescriptionLock or unlock the ability to slide to the previous slide.
SignaturelockSwipeToPrev(lock: boolean) => Promise<void>

lockSwipes

DescriptionLock or unlock the ability to slide to the next or previous slide.
SignaturelockSwipes(lock: boolean) => Promise<void>

slideNext

DescriptionTransition to the next slide.
SignatureslideNext(speed?: number, runCallbacks?: boolean) => Promise<void>

slidePrev

DescriptionTransition to the previous slide.
SignatureslidePrev(speed?: number, runCallbacks?: boolean) => Promise<void>

slideTo

DescriptionTransition to the specified slide.
SignatureslideTo(index: number, speed?: number, runCallbacks?: boolean) => Promise<void>

startAutoplay

DescriptionStart auto play.
SignaturestartAutoplay() => Promise<void>

stopAutoplay

DescriptionStop auto play.
SignaturestopAutoplay() => Promise<void>

update

DescriptionUpdate the underlying slider implementation. Call this if you've added or removed child slides.
Signatureupdate() => Promise<void>

updateAutoHeight

DescriptionForce swiper to update its height (when autoHeight is enabled) for the duration equal to 'speed' parameter.
SignatureupdateAutoHeight(speed?: number) => Promise<void>

CSS Shadow Parts

No CSS shadow parts available for this component.

CSSカスタムプロパティ

NameDescription
--bullet-backgroundBackground of the pagination bullets
--bullet-background-activeBackground of the active pagination bullet
--progress-bar-backgroundBackground of the pagination progress-bar
--progress-bar-background-activeBackground of the active pagination progress-bar
--scroll-bar-backgroundBackground of the pagination scroll-bar
--scroll-bar-background-activeBackground of the active pagination scroll-bar

Slots

No slots available for this component.

View Source