[フレーム]
Skip to main content
This is documentation for Ionic Documentation v6, which is no longer actively maintained.
For up-to-date documentation, see the latest version (v7).
Version: v6

ion-slides

Contents

note

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

The Slides component is a multi-section container. Each section can be swiped or dragged between. It contains any number of Slide components.

This guide will cover migration from the deprecated ion-slides component to the framework-specific solutions that Swiper.js provides as well as the existing ion-slides API for developers who are still using that component.

Adopted from Swiper.js: The most modern mobile touch slider and framework with hardware accelerated transitions.

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

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

Licensed under MIT

Migration

With the release of Ionic Framework v6, the Ionic Team has deprecated the ion-slides and ion-slide components in favor of using the official framework integrations provided by Swiper. Fear not! You will still be able to use slides components in your application. Additionally, because you are still using Swiper, the functionality of your slides component should remain exactly the same.

What is Swiper.js?

Swiper.js is the carousel/slider library that powers ion-slides. The library is bundled automatically with all versions of Ionic Framework. When Ionic Framework v4. was first released, Swiper did not have framework specific integrations of its library, so ion-slides was created as a way of bridging the gap between the core Swiper library and frameworks such as Angular, React, and Vue.

Since then, the Swiper team has released framework specific integrations of Swiper.js for Angular, React, Vue, and more!

What are the benefits of this change?

There are several benefits for members of the Ionic Framework community. By using the official Swiper.js framework integrations:

  • Developers can now be in control of the exact version of Swiper.js they want to use. Previously, developers would need to rely on the Ionic Team to update the version internally and release a new version of Ionic Framework.
  • The Ionic Team can spend more time triaging and fixing other non-slides issues, speeding up our development process so we can make the framework work better for our community.
  • Developers should experience fewer bugs.
  • Application bundle sizes can shrink in some cases. By installing Swiper.js as a 3rd party dependency in your application, bundlers such as Webpack or Rollup should be able to treeshake your code better.
  • Developers have access to new features that they previously did not have when using ion-slides.

How long do I have to migrate?

We plan to remove ion-slides and ion-slide in Ionic Framework v7. ion-slides and ion-slide will continue to be available for the entire Ionic Framework v6 lifecycle but will only receive critical bug fixes.

How do I migrate?

Since the underlying technology that powers your slides is the same, the migration process is easy! Follow the guides below for your specific framework.

Migration for Ionic Angular users

Migration for Ionic React users

Migration for Ionic Vue users


The following documentation applies to the ion-slides component.

Custom Animations

By default, Ionic slides use the built-in slide animation effect. Custom animations can be provided via the options property. Examples of other animations can be found below.

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;
}elseif((slideIndex -1)%4===0){
tx =0;
tz =-round *4* swiperSize;
}elseif((slideIndex -2)%4===0){
tx = swiperSize + round *4* swiperSize;
tz = swiperSize;
}elseif((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;
}elseif(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(functiononTransitionEnd(){
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]);
}
});
}
},
},
};

Usage

  • Angular
  • Javascript
  • React
  • Stencil
  • Vue
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>
`,
})
exportclassSlideExample{
// 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%;
}

Properties

mode

Description The mode determines which platform styles to use.
Attribute mode
Type "ios" | "md"
Default undefined

options

Description Options to pass to the swiper instance. See https://swiperjs.com/swiper-api for valid options
Attribute options
Type any
Default {}

pager

Description If true, show the pagination.
Attribute pager
Type boolean
Default false

scrollbar

Description If true, show the scrollbar.
Attribute scrollbar
Type boolean
Default false

Events

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

Methods

getActiveIndex

Description Get the index of the active slide.
Signature getActiveIndex() => Promise<number>

getPreviousIndex

Description Get the index of the previous slide.
Signature getPreviousIndex() => Promise<number>

getSwiper

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

isBeginning

Description Get whether or not the current slide is the first slide.
Signature isBeginning() => Promise<boolean>

isEnd

Description Get whether or not the current slide is the last slide.
Signature isEnd() => Promise<boolean>

length

Description Get the total number of slides.
Signature length() => Promise<number>

lockSwipeToNext

Description Lock or unlock the ability to slide to the next slide.
Signature lockSwipeToNext(lock: boolean) => Promise<void>

lockSwipeToPrev

Description Lock or unlock the ability to slide to the previous slide.
Signature lockSwipeToPrev(lock: boolean) => Promise<void>

lockSwipes

Description Lock or unlock the ability to slide to the next or previous slide.
Signature lockSwipes(lock: boolean) => Promise<void>

slideNext

Description Transition to the next slide.
Signature slideNext(speed?: number, runCallbacks?: boolean) => Promise<void>

slidePrev

Description Transition to the previous slide.
Signature slidePrev(speed?: number, runCallbacks?: boolean) => Promise<void>

slideTo

Description Transition to the specified slide.
Signature slideTo(index: number, speed?: number, runCallbacks?: boolean) => Promise<void>

startAutoplay

Description Start auto play.
Signature startAutoplay() => Promise<void>

stopAutoplay

Description Stop auto play.
Signature stopAutoplay() => Promise<void>

update

Description Update the underlying slider implementation. Call this if you've added or removed child slides.
Signature update() => Promise<void>

updateAutoHeight

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

CSS Shadow Parts

No CSS shadow parts available for this component.

CSS Custom Properties

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.

AltStyle によって変換されたページ (->オリジナル) /