/* eslint-disable react/prop-types */
/* eslint-disable react/no-multi-comp */
import 'weui';
import React from 'react';
import classNames from 'classnames';
import Swipers from 'swiper';
import 'swiper/dist/css/swiper.min.css';
import './style/swiper.css';
let INSTANCE_ID = 0;
class SwiperItem extends React.Component {
render() {
const { className, style, itemId, children, ...restProps } = this.props;
const cls = classNames('swiper-slide', className);
return (
{children}
);
}
}
const createEvent = (type) => {
let e;
try {
e = new TouchEvent(type);
} catch (err) {
e = document.createEvent('Event');
e.initEvent(type, true, true);
}
return e;
};
class Swiper extends React.Component {
constructor() {
super(...arguments);
this.$el = null;
this._id = INSTANCE_ID + 1;
INSTANCE_ID++;
this._$current = 0;
this._$width = 0;
this._$height = 0;
}
componentDidMount() {
const {
autoplay = false,
interval = 5000,
duration = 500,
current = 0,
displayMultipleItems = 1,
vertical,
spaceBetween,
} = this.props;
const that = this;
const opt = {
// 指示器
pagination: { el: `.taro-swiper-${this._id} > .swiper-container > .swiper-pagination` },
direction: vertical ? 'vertical' : 'horizontal',
loop: true,
slidesPerView: parseFloat(displayMultipleItems, 10),
initialSlide: parseInt(current, 10),
speed: parseInt(duration, 10),
observer: true,
observeParents: true,
on: {
slideChange() {
const e = createEvent('touchend');
try {
Object.defineProperty(e, 'detail', {
enumerable: true,
value: {
current: this.realIndex,
},
});
} catch (err) {}
that._$current = this.realIndex;
that.handleOnChange(e);
},
transitionEnd: () => {
const e = createEvent('touchend');
try {
Object.defineProperty(e, 'detail', {
enumerable: true,
value: {
current: this.mySwiper.realIndex,
},
});
if (this.mySwiper.isBeginning) {
this.mySwiper.slideToLoop(this.props.children.length - 1, 0);
} else if (this.mySwiper.isEnd) {
this.mySwiper.slideToLoop(0, 0);
}
} catch (err) {}
that.handleOnAnimationFinish(e);
},
observerUpdate: (e) => {
if (
e.target &&
e.target.className === 'taro_page' &&
e.target.style.display === 'block' &&
e.target.contains(this.$el)
) {
if (this.props.autoplay) {
setTimeout(() => {
this.mySwiper.slideTo(this._$current);
}, 1000);
}
}
},
},
};
// 自动播放
if (autoplay) {
opt.autoplay = {
delay: parseInt(interval, 10),
stopOnLastSlide: true,
disableOnInteraction: false,
};
}
// 两端距离
if (spaceBetween) {
opt.spaceBetween = spaceBetween;
}
this.mySwiper = new Swipers(this.$el, opt);
setTimeout(() => {
this.mySwiper.update();
}, 500);
}
componentWillReceiveProps(nextProps) {
if (this.mySwiper) {
const nextCurrent =
typeof nextProps.current === 'number' ? nextProps.current : this._$current || 0;
this.mySwiper.loopDestroy();
this.mySwiper.loopCreate();
// 是否衔接滚动模式
if (nextProps.circular) {
if (!this.mySwiper.isBeginning && !this.mySwiper.isEnd) {
this.mySwiper.slideToLoop(parseInt(nextCurrent, 10)); // 更新下标
}
} else {
this.mySwiper.slideTo(parseInt(nextCurrent, 10) + 1); // 更新下标
}
const {autoplay} = this.mySwiper;
// 判断是否需要停止或开始自动轮播
if (autoplay?.running !== nextProps.autoplay) {
if (nextProps.autoplay) {
autoplay.start();
} else {
autoplay.stop();
}
}
if (nextProps.autoplay && !autoplay.paused) {
autoplay.run();
autoplay.paused = false;
}
this.mySwiper.update(); // 更新子元素
}
}
componentDidUpdate(preProps) {
if (preProps.children.length === 0 && this.props.children.length > 0) {
this.mySwiper.loopDestroy();
this.mySwiper.loopCreate();
}
if (!this.mySwiper) return;
if (this.props.autoplay) {
if (this._$width !== this.mySwiper.width || this._$height !== this.mySwiper.height) {
this.mySwiper.autoplay.run();
}
}
this._$width = this.mySwiper.width;
this._$height = this.mySwiper.height;
}
componentWillUnmount() {
this.$el = null;
if (this.mySwiper) this.mySwiper.destroy();
}
handleOnChange(e) {
const func = this.props.onChange;
typeof func === 'function' && func(e);
}
handleOnAnimationFinish(e) {
const func = this.props.onAnimationFinish;
typeof func === 'function' && func(e);
}
parsePX(s = '0px') {
return parseFloat(s.replace(/r*px/i, ''), 10);
}
render() {
const {
className,
style,
vertical,
previousMargin,
nextMargin,
indicatorColor,
indicatorActiveColor,
} = this.props;
const defaultIndicatorColor = indicatorColor || 'rgba(0, 0, 0, .3)';
const defaultIndicatorActiveColor = indicatorActiveColor || '#000';
const cls = classNames(`taro-swiper-${this._id}`, className);
const sty = Object.assign(
{
paddingTop: vertical ? this.parsePX(previousMargin) : 0,
paddingRight: vertical ? 0 : this.parsePX(nextMargin),
paddingBottom: vertical ? this.parsePX(nextMargin) : 0,
paddingLeft: vertical ? 0 : this.parsePX(previousMargin),
overflow: 'hidden',
},
style,
);
const paginationCls = classNames('swiper-pagination', {
'swiper-pagination-hidden': !this.props.indicatorDots,
'swiper-pagination-bullets': this.props.indicatorDots,
});
return (
{
this.$el = el;
}}
>
.taro-swiper-${this._id} > .swiper-container > .swiper-pagination > .swiper-pagination-bullet { background: ${defaultIndicatorColor} }
.taro-swiper-${this._id} > .swiper-container > .swiper-pagination > .swiper-pagination-bullet-active { background: ${defaultIndicatorActiveColor} }
`,
}}
/>
{this.props.children}
);
}
}
export { Swiper, SwiperItem };