chore(slides): refactor

* chore(): refactor

* chore(): make slide options dynamic
This commit is contained in:
Mike Hartington
2018-01-05 09:09:20 -08:00
committed by GitHub
parent cc9df62b0b
commit c7f75ead92
8 changed files with 415 additions and 317 deletions

View File

@ -24,146 +24,36 @@ Licensed under MIT
## Properties
#### autoplay
number
#### control
#### options
any
#### direction
any
#### effect
string
#### initialSlide
number
#### keyboardControl
boolean
#### loop
boolean
Options to pass to the swiper instance.
See http://idangero.us/swiper/api/ for valid options
#### pager
boolean
#### paginationType
string
#### parallax
boolean
#### slidesPerView
any
#### spaceBetween
number
#### speed
number
#### zoom
boolean
Show or hide the pager
## Attributes
#### autoplay
number
#### control
#### options
any
#### direction
any
#### effect
string
#### initialSlide
number
#### keyboardControl
boolean
#### loop
boolean
Options to pass to the swiper instance.
See http://idangero.us/swiper/api/ for valid options
#### pager
boolean
#### paginationType
string
#### parallax
boolean
#### slidesPerView
any
#### spaceBetween
number
#### speed
number
#### zoom
boolean
Show or hide the pager
## Events
@ -207,6 +97,79 @@ boolean
#### ionSlideWillChange
## Methods
#### getActiveIndex()
Get the index of the active slide.
#### getPreviousIndex()
Get the index of the previous slide.
#### isBeginning()
Get whether or not the current slide is the first slide.
#### isEnd()
Get whether or not the current slide is the last slide.
#### length()
Get the total number of slides.
#### lockSwipeToNext()
Lock or unlock the ability to slide to the next slides.
#### lockSwipeToPrev()
Lock or unlock the ability to slide to the previous slides.
#### lockSwipes()
Lock or unlock the ability to slide to change slides.
#### slideNext()
Transition to the next slide.
#### slidePrev()
Transition to the previous slide.
#### slideTo()
Transition to the specified slide.
#### startAutoplay()
Start auto play.
#### stopAutoplay()
Stop auto play.
#### update()
Update the underlying slider implementation. Call this if you've added or removed
child slides.
----------------------------------------------

View File

@ -1,6 +1,6 @@
import { Component, Element, Event, EventEmitter, Prop } from '@stencil/core';
import { Component, Element, Event, EventEmitter, Method, Prop, PropDidChange } from '@stencil/core';
import { Swiper } from './vendor/swiper.js';
import { SwiperOptions } from './vendor/swiper';
@Component({
tag: 'ion-slides',
@ -8,9 +8,16 @@ import { Swiper } from './vendor/swiper.js';
assetsDir: 'vendor'
})
export class Slides {
swiper: any;
@Element() private el: HTMLElement;
private container: HTMLElement;
private init: boolean;
private tmr: number;
private swiper: any;
private finalOptions: any;
private slidesId: number;
private slideId: string;
@Element() private el: HTMLElement;
/**
* @output {Event} Emitted before the active slide has changed.
@ -78,178 +85,78 @@ export class Slides {
@Event() ionSlideTouchEnd: EventEmitter;
/**
* @input {string} The animation effect of the slides.
* Possible values are: `slide`, `fade`, `cube`, `coverflow` or `flip`.
* Default: `slide`.
* Options to pass to the swiper instance.
* See http://idangero.us/swiper/api/ for valid options
*/
@Prop() effect: string = 'slide';
@Prop() options: SwiperOptions;
@PropDidChange('options')
updateSwiperOptions() {
let newOptions = this.normalizeOptions();
this.swiper.params = Object.assign({}, this.swiper.params, newOptions);
this.update();
}
/**
* @input {number} Delay between transitions (in milliseconds). If this
* parameter is not passed, autoplay is disabled. Default does
* not have a value and does not autoplay.
* Default: `null`.
* Show or hide the pager
*/
@Prop() autoplay: number;
/**
* @input {Slides} Pass another Slides instance or array of Slides instances
* that should be controlled by this Slides instance.
* Default: `null`.
*/
@Prop() control: any = null;
/**
* @input {string} Swipe direction: 'horizontal' or 'vertical'.
* Default: `horizontal`.
*/
@Prop() direction: 'horizontal' | 'vertical' = 'horizontal';
/**
* @input {number} Index number of initial slide. Default: `0`.
*/
@Prop() initialSlide: number = 0;
/**
* @input {boolean} If true, continuously loop from the last slide to the
* first slide.
*/
@Prop() loop: boolean = false;
/**
* @input {boolean} If true, show the pager.
*/
@Prop() pager: boolean;
/**
* @input {string} Type of pagination. Possible values are:
* `bullets`, `fraction`, `progress`. Default: `bullets`.
* (Note that the pager will not show unless `pager` input
* is set to true).
*/
@Prop() paginationType: string = 'bullets';
/**
* @input {boolean} If true, allows you to use "parallaxed" elements inside of
* slider.
*/
@Prop() parallax: boolean = false;
/**
* @input {number} Slides per view. Slides visible at the same time. Default: `1`.
*/
@Prop() slidesPerView: number | 'auto' = 1;
/**
* @input {number} Distance between slides in px. Default: `0`.
*/
@Prop() spaceBetween: number = 0;
/**
* @input {number} Duration of transition between slides
* (in milliseconds). Default: `300`.
*/
@Prop() speed: number = 300;
/**
* @input {boolean} If true, enables zooming functionality.
*/
@Prop() zoom: boolean;
/**
* @input {boolean} If true, enables keyboard control
*/
@Prop() keyboardControl: boolean;
@Prop() pager: boolean = true;
render() {
return (
<div class='swiper-container' data-dir='rtl'>
<div class='swiper-wrapper'>
<slot></slot>
<slot />
</div>
<div class={{
'swiper-pagination': true,
'hide': !this.pager
}}></div>
<div
class={{
'swiper-pagination': true,
hide: !this.pager
}}
/>
</div>
);
}
/**
* Height of container.
*/
private height: number;
/**
* Width of container.
*/
private width: number;
/**
* Enabled this option and swiper will be operated as usual except it will
* not move, real translate values on wrapper will not be set. Useful when
* you may need to create custom slide transition.
*/
private virtualTranslate = false;
/**
* Set to true to round values of slides width and height to prevent blurry
* texts on usual resolution screens (if you have such)
*/
private roundLengths = false;
// Slides grid
private originalEvent: any;
/**
* Private properties only useful to this class.
* ------------------------------------
*/
private _init: boolean;
private _tmr: number;
/**
* Properties that are exposed publicly but no docs.
* ------------------------------------
*/
private container: HTMLElement;
private slidesId: number;
private slideId: string;
constructor(
) {
constructor() {
this.slidesId = ++slidesId;
this.slideId = 'slides-' + this.slidesId;
}
private _initSlides() {
if (!this._init) {
private initSlides() {
if (!this.init) {
console.debug(`ion-slides, init`);
this.container = this.el.children[0] as HTMLElement;
// init swiper core
this.swiper = new Swiper(this.container, this.normalizeOptions());
if (this.options.keyboardControl) {
// init keyboard event listeners
this.enableKeyboardControl(true);
}
this.init = true;
}
}
normalizeOptions() {
// Base options, can be changed
var swiperOptions = {
height: this.height,
width: this.width,
virtualTranslate: this.virtualTranslate,
roundLengths: this.roundLengths,
originalEvent: this.originalEvent,
autoplay: this.autoplay,
direction: this.direction,
initialSlide: this.initialSlide,
loop: this.loop,
pager: this.pager,
paginationType: this.paginationType,
parallax: this.parallax,
slidesPerView: this.slidesPerView,
spaceBetween: this.spaceBetween,
speed: this.speed,
zoom: this.zoom,
effect: 'slide',
autoplay: 0,
direction: 'horizontal',
initialSlide: 0,
loop: false,
pager: false,
pagination: '.swiper-pagination',
paginationType: 'bullets',
parallax: false,
slidesPerView: 1,
spaceBetween: 0,
speed: 300,
zoom: false,
slidesPerColumn: 1,
slidesPerColumnFill: 'column',
slidesPerGroup: 1,
@ -324,7 +231,12 @@ export class Slides {
prevSlideMessage: 'Previous slide',
nextSlideMessage: 'Next slide',
firstSlideMessage: 'This is the first slide',
lastSlideMessage: 'This is the last slide',
lastSlideMessage: 'This is the last slide'
};
// Keep the event options separate, we dont want users
// overwriting these
var eventOptions = {
onSlideChangeStart: this.ionSlideWillChange.emit,
onSlideChangeEnd: this.ionSlideDidChange.emit,
onSlideNextStart: this.ionSlideNextStart.emit,
@ -337,19 +249,17 @@ export class Slides {
onReachBeginning: this.ionSlideReachStart.emit,
onReachEnd: this.ionSlideReachEnd.emit,
onTouchStart: this.ionSlideTouchStart.emit,
onTouchEnd: this.ionSlideTouchEnd.emit,
onTouchEnd: this.ionSlideTouchEnd.emit
};
// init swiper core
this.swiper = new Swiper(this.container, swiperOptions);
// Merge the base, user options, and events together then pas to swiper
return Object.assign(
{},
swiperOptions,
this.options,
eventOptions
);
if (this.keyboardControl) {
// init keyboard event listeners
this.enableKeyboardControl(true);
}
this._init = true;
}
}
componentDidLoad() {
@ -358,7 +268,7 @@ export class Slides {
* child components are ready.
*/
setTimeout(() => {
this._initSlides();
this.initSlides();
}, 10);
}
@ -366,18 +276,20 @@ export class Slides {
* Update the underlying slider implementation. Call this if you've added or removed
* child slides.
*/
@Method()
update(debounce = 300) {
if (this._init) {
window.clearTimeout(this._tmr);
this._tmr = window.setTimeout(() => {
this.swiper.update();
// Don't allow pager to show with > 10 slides
if (this.length() > 10) {
this.paginationType = undefined;
}
}, debounce);
}
this.swiper.update();
// if (this.init) {
// window.clearTimeout(this.tmr);
// this.tmr = window.setTimeout(() => {
// this.swiper.update();
//
// // Don't allow pager to show with > 10 slides
// if (this.length() > 10) {
// this.options.paginationType = undefined;
// }
// }, debounce);
// }
}
/**
@ -387,6 +299,7 @@ export class Slides {
* @param {number} [speed] Transition duration (in ms).
* @param {boolean} [runCallbacks] Whether or not to emit the `ionSlideWillChange`/`ionSlideDidChange` events. Default true.
*/
@Method()
slideTo(index: number, speed?: number, runCallbacks?: boolean) {
this.swiper.slideTo(index, speed, runCallbacks);
}
@ -397,6 +310,7 @@ export class Slides {
* @param {number} [speed] Transition duration (in ms).
* @param {boolean} [runCallbacks] Whether or not to emit the `ionSlideWillChange`/`ionSlideDidChange` events. Default true.
*/
@Method()
slideNext(speed?: number, runCallbacks?: boolean) {
this.swiper.slideNext(runCallbacks, speed);
}
@ -407,6 +321,7 @@ export class Slides {
* @param {number} [speed] Transition duration (in ms).
* @param {boolean} [runCallbacks] Whether or not to emit the `ionSlideWillChange`/`ionSlideDidChange` events. Default true.
*/
@Method()
slidePrev(speed?: number, runCallbacks?: boolean) {
this.swiper.slidePrev(runCallbacks, speed);
}
@ -416,6 +331,7 @@ export class Slides {
*
* @returns {number} The index number of the current slide.
*/
@Method()
getActiveIndex(): number {
return this.swiper.activeIndex;
}
@ -425,6 +341,7 @@ export class Slides {
*
* @returns {number} The index number of the previous slide.
*/
@Method()
getPreviousIndex(): number {
return this.swiper.previousIndex;
}
@ -434,6 +351,7 @@ export class Slides {
*
* @returns {number} The total number of slides.
*/
@Method()
length(): number {
return this.swiper.slides.length;
}
@ -443,8 +361,9 @@ export class Slides {
*
* @returns {boolean} If the slide is the last slide or not.
*/
@Method()
isEnd(): boolean {
return this.isEnd();
return this.swiper.isEnd;
}
/**
@ -452,27 +371,31 @@ export class Slides {
*
* @returns {boolean} If the slide is the first slide or not.
*/
@Method()
isBeginning(): boolean {
return this.isBeginning();
return this.swiper.isBeginning;
}
/**
* Start auto play.
*/
startAutoplay() {
@Method()
startAutoplay(speed?: number): void {
this.swiper.startAutoplay();
}
/**
* Stop auto play.
*/
stopAutoplay() {
@Method()
stopAutoplay(): void {
this.swiper.stopAutoplay();
}
/**
* Lock or unlock the ability to slide to the next slides.
*/
@Method()
lockSwipeToNext(shouldLockSwipeToNext: boolean) {
if (shouldLockSwipeToNext) {
return this.swiper.lockSwipeToNext();
@ -483,6 +406,7 @@ export class Slides {
/**
* Lock or unlock the ability to slide to the previous slides.
*/
@Method()
lockSwipeToPrev(shouldLockSwipeToPrev: boolean) {
if (shouldLockSwipeToPrev) {
return this.swiper.lockSwipeToPrev();
@ -493,6 +417,7 @@ export class Slides {
/**
* Lock or unlock the ability to slide to change slides.
*/
@Method()
lockSwipes(shouldLockSwipes: boolean) {
if (shouldLockSwipes) {
return this.swiper.lockSwipes();
@ -510,8 +435,11 @@ export class Slides {
this.swiper.disableKeyboardControl();
}
/**
* @hidden
*/
componentDidUnload() {
this._init = false;
this.init = false;
this.swiper.destroy(true, true);
this.enableKeyboardControl(false);

View File

@ -0,0 +1,102 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Slides - App Intro</title>
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="/dist/ionic.js"></script>
<style>
.scroll-inner,
.slides,
.swiper-container {
height: 100%;
}
.swiper-slide {
display: flex;
display: flex;
flex-direction: column;
}
.swiper-slide img {
max-width: 300px;
}
</style>
</head>
<body>
<ion-app>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-button onclick="slidePrev()">Prev</ion-button>
</ion-buttons>
<ion-buttons slot="end">
<ion-button onclick="slideNext()">Next</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-slides class="slides">
<ion-slide>
<img src="https://images.unsplash.com/photo-1490718687940-0ecadf414600?auto=format&fit=crop&w=1352&q=80&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" class="slide-image" />
<div padding>
<h2 class="slide-title">
Welcome to <b>ICA</b>
</h2>
<p>
The <b>ionic conference app</b> is a practical preview of the ionic framework in action, and a demonstration of proper code use.
</p>
</div>
</ion-slide>
<ion-slide>
<img src="https://images.unsplash.com/photo-1504703500545-4c4ee081b155?auto=format&fit=crop&w=1350&q=80&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" class="slide-image" />
<div padding>
<h2 class="slide-title">What is Ionic?</h2>
<p><b>Ionic Framework</b> is an open source SDK that enables developers to build high quality mobile apps with web technologies like HTML, CSS, and JavaScript.</p>
</div>
</ion-slide>
<ion-slide>
<img src="https://images.unsplash.com/photo-1501879779179-4576bae71d8d?auto=format&fit=crop&w=1350&q=80&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" class="slide-image" />
<div padding>
<h2 class="slide-title">What is Ionic Pro?</h2>
<p><b>Ionic Pro</b> is a powerful set of services and features built on top of Ionic Framework that brings a totally new level of app development agility to mobile dev teams.</p>
</div>
</ion-slide>
<ion-slide>
<img src="https://images.unsplash.com/photo-1485832329521-e944d75fa65e?auto=format&fit=crop&w=1350&q=80&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" class="slide-image" />
<ion-button onclick="toStart()">
Back to the start
</ion-button>
</ion-slide>
</ion-slides>
</ion-content>
</ion-page>
</ion-app>
<script>
const slides = document.querySelector('.slides')
slides.pager = true;
function slideNext() {
slides.slideNext()
};
function slidePrev() {
slides.slidePrev();
};
function toStart() {
slides.slideTo(0);
}
</script>
</body>
</html>

View File

@ -1,9 +1,11 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Slides - Basic</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="/dist/ionic.js"></script>
</head>
@ -11,7 +13,7 @@
<ion-app>
<ion-page>
<ion-content>
<ion-slides style="background: black" pager="true" effect="flip">
<ion-slides style="background: black" id="slides">
<ion-slide style="background: red; color: white;">
<h1>Slide 1</h1>
</ion-slide>
@ -22,8 +24,113 @@
<h1>Slide 3</h1>
</ion-slide>
</ion-slides>
<ion-button expand="block" onclick="slidePrev()">Slide Prev</ion-button>
<ion-button expand="block" onclick="slideNext()">Slide Next</ion-button>
<ion-button expand="block" onclick="getActiveIndex()">Get Active Index</ion-button>
<ion-button expand="block" onclick="getPreviousIndex()">Get Previous Index</ion-button>
<ion-button expand="block" onclick="isEnd()">Is the End?</ion-button>
<ion-button expand="block" onclick="isBeginning()">Is the beginning?</ion-button>
<ion-button expand="block" onclick="slideTo()">Slide to slide index 2</ion-button>
<ion-button expand="block" onclick="slideLength()">Get slide length</ion-button>
<ion-button expand="block" onclick="slideAutoPlay()">Start auto play</ion-button>
<ion-button expand="block" onclick="slideStopAutoPlay()">Stop auto play</ion-button>
<ion-button expand="block" onclick="setOptions()">Set options</ion-button>
</ion-content>
</ion-page>
</ion-app>
<script>
const slides = document.getElementById('slides')
slides.pager = false;
slides.options = {}
function slideNext() {
slides.slideNext(500)
};
function slidePrev() {
slides.slidePrev(500);
};
function slideTo() {
slides.slideTo(2);
}
function slideAutoPlay() {
slides.options = Object.assign({}, slides.options, {autoplay: 300});
slides.startAutoplay();
}
function slideStopAutoPlay() {
slides.stopAutoplay();
}
function setOptions() {
slides.options = Object.assign({}, slides.options, {
slidesPerView: 2,
});
}
function slideLength() {
console.log(slides.length());
}
function getActiveIndex() {
console.log(slides.getActiveIndex());
};
function getPreviousIndex() {
console.log(slides.getPreviousIndex());
};
function isEnd() {
console.log(slides.isEnd());
}
function isBeginning() {
console.log(slides.isBeginning());
}
slides.addEventListener('ionSlideDidChange', function(e) {
console.log('slide did change', e)
});
slides.addEventListener('ionSlideWillChange', function(e) {
console.log('slide will change', e)
});
slides.addEventListener('ionSlideNextStart', function(e) {
console.log('slide next start', e)
});
slides.addEventListener('ionSlidePrevStart', function(e) {
console.log('slide prev start', e)
});
slides.addEventListener('ionSlideNextEnd', function(e) {
console.log('slide next end', e)
});
slides.addEventListener('ionSlidePrevEnd', function(e) {
console.log('slide prev end', e)
});
slides.addEventListener('ionSlideTransitionStart', function(e) {
console.log('slide transition start', e)
});
slides.addEventListener('ionSlideTransitionEnd', function(e) {
console.log('slide transistion end', e)
});
slides.addEventListener('ionSlideDrag', function(e) {
console.log('slide drag', e)
});
slides.addEventListener('ionSlideReachStart', function(e) {
console.log('slide reach start', e)
});
slides.addEventListener('ionSlideReachEnd', function(e) {
console.log('slide reach end', e)
});
slides.addEventListener('ionSlideTouchStart', function(e) {
console.log('slide touch start', e)
});
slides.addEventListener('ionSlideTouchEnd', function(e) {
console.log('slide touch end', e)
});
</script>
</body>
</html>

View File

@ -9,7 +9,7 @@
</head>
<body>
<ion-slides style="background: black" pager="true" effect="flip">
<ion-slides style="background: black" pager="true">
<ion-slide style="background: red; color: white;">
<h1>Slide 1</h1>
@ -24,5 +24,12 @@
</ion-slide>
</ion-slides>
<script>
var slides = document.getElementsByTagName('ion-slides');
slides[0].options = {
effect: 'flip'
}
</script>
</body>
</html>

View File

@ -3,7 +3,7 @@
// Definitions by: Sebastián Galiano <https://github.com/sgaliano/>, Luca Trazzi <https://github.com/lucax88x/>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
interface SwiperOptions {
export interface SwiperOptions {
initialSlide?: number;
direction?: string;
speed?: number;