Browse Source

feat: 新增ImagePreview 组件

wangchunyu11 5 years ago
parent
commit
c964e1e855

+ 20 - 0
src/config.json

@@ -368,6 +368,26 @@
       "sort": "0",
       "showDemo": true,
       "author": "ivanwancy"
+    },
+    {
+      "version": "1.0.0",
+      "name": "Swiper",
+      "chnName": "滑动切换",
+      "desc": "Swiper 滑动切换",
+      "type": "component",
+      "sort": "0",
+      "showDemo": true,
+      "author": "ivanwancy"
+    },
+    {
+      "version": "1.0.0",
+      "name": "ImagePreview",
+      "chnName": "图片预览",
+      "desc": "ImagePreview 图片预览",
+      "type": "component",
+      "sort": "0",
+      "showDemo": true,
+      "author": "ivanwancy"
     }
   ]
 }

+ 7 - 1
src/nutui.js

@@ -76,6 +76,10 @@ import Address from './packages/address/index.js';
 import './packages/address/address.scss';
 import Tag from './packages/tag/index.js';
 import './packages/tag/tag.scss';
+import Swiper from './packages/swiper/index.js';
+import './packages/swiper/swiper.scss';
+import ImagePreview from './packages/imagepreview/index.js';
+import './packages/imagepreview/imagepreview.scss';
 
 const packages = {
   Cell,
@@ -116,7 +120,9 @@ const packages = {
   SubSideNavBar: SubSideNavBar,
   SideNavBarItem: SideNavBarItem,
   Address: Address,
-  Tag: Tag
+  Tag,
+  Swiper,
+  ImagePreview
 };
 
 const components = {};

+ 33 - 0
src/packages/imagepreview/demo.vue

@@ -0,0 +1,33 @@
+<template>
+  <div id="imagepreview">
+    <nut-cell isLink title="展示图片预览" :showIcon="true" @click.native="showPreview = true"></nut-cell>
+    <nut-imagepreview v-model="showPreview" :images="dataImgItem" @close="showPreview = false"/>
+  </div>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      dataImgItem: [],
+      showPreview: false
+    };
+  },
+  mounted() {
+    this.dataImgItem = [
+      {
+        imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg'
+      },
+      {
+        imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/26597/30/4870/174583/5c35c5d2Ed55eedc6/50e27870c25e7a82.png'
+      },
+      {
+        imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/9542/17/12873/201687/5c3c4362Ea9eb757d/60026b40a9d60d85.jpg'
+      },
+      {
+        imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/30042/36/427/82951/5c3bfdabE3faf2f66/9adca782661c988c.jpg'
+      }
+    ];
+  }
+};
+</script>
+<style lang="scss"></style>

+ 48 - 0
src/packages/imagepreview/doc.md

@@ -0,0 +1,48 @@
+# ImagePreview 图片预览
+
+展示一组图片全屏预览效果。
+
+## 基本用法
+
+
+```html
+<nut-cell isLink title="展示图片预览" :showIcon="true" @click.native="showPreview = true"></nut-cell>
+<nut-imagepreview v-model="showPreview" :images="dataImgItem" @close="showPreview = false"/>
+```
+
+JS 代码
+
+```js
+  data() {
+    return {
+      dataImgItem: [
+      {
+        imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg'
+      },
+      {
+        imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/26597/30/4870/174583/5c35c5d2Ed55eedc6/50e27870c25e7a82.png'
+      },
+      {
+        imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/9542/17/12873/201687/5c3c4362Ea9eb757d/60026b40a9d60d85.jpg'
+      },
+      {
+        imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/30042/36/427/82951/5c3bfdabE3faf2f66/9adca782661c988c.jpg'
+      }
+    ];,
+      showPreview: true
+    };
+  },
+```
+
+## Prop
+
+| 字段 | 说明 | 类型 | 默认值
+|----- | ----- | ----- | ----- 
+| value | 左侧主标题 | Boolean | false
+| images | 左侧副标题 | Array`<String>` | []
+
+## Event
+
+|字段|说明|回调参数|
+|--|--|--|
+|close|点击返回 icon 触发事件回调函数|无|

+ 30 - 0
src/packages/imagepreview/imagepreview.scss

@@ -0,0 +1,30 @@
+.nut-imagepreview {
+  &-swiper {
+    height: 100%;
+    width: 100vw;
+    background-color: transparent;
+  }
+  &-img {
+    width:100%;
+    height:100%;
+    object-fit: contain;
+  }
+
+  &-index {
+    position: fixed;
+    top: 50px;
+    text-align: center;
+    left: 0;
+    right: 0;
+    background: transparent;
+    color: #fff;
+
+    .arrow {
+      position: absolute;
+      left: 15px;
+      transform: rotateZ(180deg);
+    }
+  }
+}
+
+

+ 55 - 0
src/packages/imagepreview/imagepreview.vue

@@ -0,0 +1,55 @@
+<template>
+  <div>
+    <nut-popup v-model="value">
+      <nut-swiper
+        class="nut-imagepreview-swiper"
+        :paginationVisibile="true"
+        loop
+        direction="horizontal"
+        :swiperData="images"
+        @slideChangeEnd="slideChangeEnd"
+      >
+        <div v-for="(item, index) in images" :key="index" class="nut-swiper-slide">
+          <img :src="item.imgSrc" class="nut-imagepreview-img" />
+        </div>
+      </nut-swiper>
+
+      <div class="nut-imagepreview-index">
+        <nut-icon type="right" color="#fff" class="arrow" @click.native="$emit('close')" />
+        {{this.active}} / {{this.images.length}}
+      </div>
+    </nut-popup>
+  </div>
+</template>
+<script>
+export default {
+  name: 'nut-imagepreview',
+  props: {
+    value: {
+      type: Boolean,
+      default: true
+    },
+    images: {
+      type: Array,
+      default: () => []
+    }
+  },
+  data() {
+    return {
+      active: 1,
+    };
+  },
+  methods: {
+    slideChangeEnd(page) {
+      this.active = page;
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.popup-box {
+  height: 100%;
+  overflow: visible;
+  background-color: transparent;
+}
+</style>

+ 8 - 0
src/packages/imagepreview/index.js

@@ -0,0 +1,8 @@
+import ImagePreview from './imagepreview.vue';
+import './imagepreview.scss';
+
+ImagePreview.install = function(Vue) {
+  Vue.component(ImagePreview.name, ImagePreview);
+};
+
+export default ImagePreview;

+ 126 - 0
src/packages/swiper/demo.vue

@@ -0,0 +1,126 @@
+<template>
+  <div id="vueSwiper">
+    <h4>横向无缝切换</h4>
+    <nut-swiper :paginationVisibile="true" direction="horizontal" :swiperData="dataImgItem">
+      <div v-for="(item, index) in dataImgItem" :key="index" class="nut-swiper-slide ">
+        <img :src="item.imgSrc" style="max-width:100%;" />
+      </div>
+    </nut-swiper>
+
+    <h4>横向切换</h4>
+    <nut-swiper :paginationVisibile="true" direction="horizontal" :swiperData="dataImgItem" :canDragging="false" :paginationVisible="true">
+      <div v-for="(item, index) in dataImgItem" :key="index" class="nut-swiper-slide ">
+        <img :src="item.imgSrc" style="max-width:100%;" />
+      </div>
+    </nut-swiper>
+
+    <h4>横向循环切换</h4>
+    <nut-swiper
+      :paginationVisibile="true"
+      direction="horizontal"
+      :swiperData="dataImgItem"
+      :loop="true"
+      :canDragging="false"
+      :paginationVisible="true"
+    >
+      <div v-for="(item, index) in dataImgItem" :key="index" class="nut-swiper-slide ">
+        <img :src="item.imgSrc" style="max-width:100%;" />
+      </div>
+    </nut-swiper>
+
+    <h4>纵向自动播放</h4>
+    <nut-swiper direction="vertical" :autoPlay="3000" :swiperData="dataImgItem">
+      <div v-for="(item, index) in dataImgItem" :key="index" class="nut-swiper-slide ">
+        <img :src="item.imgSrc" style="max-width:100%;" />
+      </div>
+    </nut-swiper>
+
+    <h4>滑动懒加载图片</h4>
+    <nut-swiper
+      direction="horizontal"
+      :paginationClickable="true"
+      :swiperData="dataImgItem"
+      :lazyLoad="true"
+      :paginationVisible="true"
+      @slideChangeEnd="slideChangeEnd"
+      @slideMove="slideMove"
+      @slideChangeStart="slideChangeStart"
+    >
+      <div v-for="(item, index) in dataImgItem" :key="index" class="nut-swiper-slide ">
+        <img :data-src="item.imgSrc" style="max-width:100%;" class="nut-img-lazyload" />
+      </div>
+    </nut-swiper>
+  </div>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      dataItem: [],
+      dataImgItem: []
+    };
+  },
+  mounted() {
+    setTimeout(() => {
+      this.dataItem = [
+        {
+          name: 1
+        },
+        {
+          name: 2
+        },
+        {
+          name: 3
+        },
+        {
+          name: 4
+        }
+      ];
+
+      this.dataImgItem = [
+        {
+          imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg'
+        },
+        {
+          imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/26597/30/4870/174583/5c35c5d2Ed55eedc6/50e27870c25e7a82.png'
+        },
+        {
+          imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/9542/17/12873/201687/5c3c4362Ea9eb757d/60026b40a9d60d85.jpg'
+        },
+        {
+          imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/30042/36/427/82951/5c3bfdabE3faf2f66/9adca782661c988c.jpg'
+        }
+      ];
+    }, 300);
+  },
+  methods: {
+    slideChangeEnd(page) {
+      console.log(page);
+    },
+    slideMove(page) {
+      console.log(page);
+    },
+    slideChangeStart(page) {
+      console.log(page);
+    }
+  }
+};
+</script>
+<style lang="scss">
+#vueSwiper {
+  .nut-swiper-slide {
+    font-size: 24px;
+    justify-content: center;
+    align-items: center;
+    display: flex;
+  }
+  // .nut-swiper-slide:nth-child(1), .nut-swiper-slide:nth-child(3){
+  //     color:#fff;
+  //     background:#848689;
+  // }
+  // .nut-swiper-slide:nth-child(2), .nut-swiper-slide:nth-child(4){
+  //     color:#333;
+  //     background:#ccc;
+  // }
+}
+</style>

+ 176 - 0
src/packages/swiper/doc.md

@@ -0,0 +1,176 @@
+# swiper 滑动切换
+
+常用于一组图片或卡片轮播,当内容空间不足时,可以用走马灯的形式进行收纳,进行轮播展现。
+
+## 基本用法
+
+横向无缝切换
+
+```html
+<nut-swiper
+    :paginationVisible="true"
+    direction="horizontal"
+    :swiperData="dataItem"
+    ref="demo1"
+>
+    <div  v-for="(item,index) in dataItem" :key="index"  class="nut-swiper-slide">
+        <span>page{{item.name} }</span>
+    </div>
+</nut-swiper>
+```
+
+横向切换
+
+```html
+<nut-swiper
+    direction="horizontal"
+    :swiperData="dataItem"
+    :canDragging="false"
+    :paginationVisible="true"
+    ref="demo2"
+>
+    <div  v-for="(item,index) in dataItem" :key="index"  class="nut-swiper-slide">
+        <span>page{{item.name} }</span>
+    </div>
+
+</nut-swiper>
+```
+
+横向循环切换
+
+```html
+<nut-swiper
+    direction="horizontal"
+    :loop="true"
+    :canDragging="false"
+    :paginationVisible="true"
+    ref="demo3"
+>
+    <div  class="nut-swiper-slide gray" >
+        <span>page 1</span>
+    </div>
+    <div  class="nut-swiper-slide gray_1" >
+        <span>page 2</span>
+    </div>
+    <div  class="nut-swiper-slide gray" >
+        <span>page 3</span>
+    </div>
+    <div  class="nut-swiper-slide gray_1" >
+        <span>page 4</span>
+    </div>
+</nut-swiper>
+```
+
+纵向自动播放
+
+```html
+ <nut-swiper
+    direction="vertical"
+    :autoPlay="3000"
+    ref="demo4"
+>
+    <div  class="nut-swiper-slide gray" >
+        <span>page 1</span>
+    </div>
+    <div  class="nut-swiper-slide gray_1" >
+        <span>page 2</span>
+    </div>
+    <div  class="nut-swiper-slide gray" >
+        <span>page 3</span>
+    </div>
+    <div  class="nut-swiper-slide gray_1" >
+        <span>page 4</span>
+    </div>
+</nut-swiper>
+```
+
+滑动懒加载图片
+
+```html
+<nut-swiper
+    direction="horizontal"
+    :swiperData="dataImgItem"
+    :lazyLoad="true"
+    :paginationVisible="true"
+    ref="demo5"
+>
+        <div  v-for="(item,index) in dataImgItem" :key="index"  class="nut-swiper-slide ">
+        <img :data-src="item.imgSrc"   style="max-width:100%; max-height:100%" class="nut-img-lazyload"/> 
+    </div>
+
+</nut-swiper>
+```
+
+```javascript
+    export default{
+        data(){
+            return{
+                dataItem:[],
+                dataImgItem:[],
+            }
+        },
+        mounted(){
+            setTimeout(()=>{
+                this.dataItem = [{
+                    name:1
+                },{
+                    name:2
+                },{
+                    name:3
+                },{
+                    name:4
+                }]
+
+                this.dataImgItem = [
+                    {
+                        imgSrc:'//m.360buyimg.com/mobilecms/s843x843_jfs/t19441/80/1577112624/568821/1ee9b683/5ad064f1Nf41a94b4.jpg'
+                    },
+                    {
+                        imgSrc:'//m.360buyimg.com/mobilecms/s843x843_jfs/t16798/338/1617130854/542623/4c197f4d/5ad064f1Nce5f69e2.jpg'
+                    },
+                    {
+                        imgSrc:'//m.360buyimg.com/mobilecms/s843x843_jfs/t22123/348/720079801/233727/23c4c0a4/5b162d64Nc5883413.jpg'
+                    },
+                    {
+                        imgSrc:'//m.360buyimg.com/mobilecms/s843x843_jfs/t1/27233/9/354/82863/5c090a0eEe2a350d8/aaa6686ce133e364.jpg'
+                    }
+                ];
+            },300)
+        }
+    }
+
+```
+
+## Prop
+
+| 字段 | 说明 | 类型 | 默认值
+|----- | ----- | ----- | ----- 
+| direction | 滑动方向 | String | vertical
+| paginationVisible | 是否分页显示 | Boolean | false
+| paginationClickable | 分页是否可以点击 | Boolean | false
+| loop | 是否循环 | Boolean | false
+| speed | 过度动画执行时间 | Number | 500
+| canDragging | 是否无缝切换 | Boolean | true
+| autoPlay | 自动轮播,轮播默认是循环模式,直接写轮播间隔时间 | Number | 0
+| initPage | 设置初始时候显示的页 | Number | 1
+| lazyLoad | 是否懒加载图片 | Boolean | false
+| lazyLoadUrl | 懒加载的默认展示图片 | String | -
+| swiperData | 异步数据渲染slide时,必须绑定对应数组(v2.1.7以上支持) | Array | -
+
+## Methods
+
+| 字段 | 说明 | 参数 
+|----- | ----- | ----- 
+| next | 去下一页 | -
+| prev | 去上一页 | -
+| setPage |  设置当前显示第几页 | number
+
+## Events
+| 字段 | 说明 | 回调参数 
+|----- | ----- | ----- 
+| slideChangeStart | 页面开始切换时候 | pageSize,el
+| slideChangeEnd | 页面结束切换时候 | pageSize,el
+| slideRevertStart | 拖动页面没改变回到原先位置开始时候 | pageSize,el
+| slideRevertEnd | 拖动页面没有改变回到原先位置结束时候 | pageSize,el
+| slideMove | 拖动过程中 | offset,el
+

+ 8 - 0
src/packages/swiper/index.js

@@ -0,0 +1,8 @@
+import Swiper from './swiper.vue';
+import './swiper.scss';
+
+Swiper.install = function(Vue) {
+  Vue.component(Swiper.name, Swiper);
+};
+
+export default Swiper;

+ 98 - 0
src/packages/swiper/swiper.scss

@@ -0,0 +1,98 @@
+.nut-swiper {
+  position: relative;
+  overflow: hidden;
+  height: 200px;
+  .nut-swiper-wrap {
+    display: flex;
+    display: -webkit-flex;
+    width: 100%;
+    height: 100%;
+    transition: all 0ms ease;
+    -webkit-transition: all 0ms ease;
+  }
+  .nut-swiper-slide {
+    overflow: hidden;
+    flex-shrink: 0;
+    -webkit-flex-shrink: 0;
+    width: 100%;
+    height: 100%;
+    cursor: default;
+    position: relative;
+    @keyframes nut-preloader-spin {
+      100% {
+        transform: rotate(360deg);
+      }
+    }
+    .nut-lazy {
+      &.img {
+        width: 100%;
+        height: 100%;
+        background-repeat: no-repeat;
+        background-size: 100% 100%;
+      }
+      &.preloader {
+        width: 42px;
+        height: 42px;
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        margin-left: -21px;
+        margin-top: -21px;
+        z-index: 10;
+        transform-origin: 50%;
+        animation: nut-preloader-spin 1s infinite linear;
+        box-sizing: border-box;
+        border: 4px solid #fff;
+        border-radius: 50%;
+        border-top-color: transparent;
+      }
+    }
+  }
+  &.horizontal .nut-swiper-wrap {
+    flex-direction: row;
+    -webkit-flex-direction: row;
+  }
+  &.vertical .nut-swiper-wrap {
+    flex-direction: column;
+    -webkit-flex-direction: column;
+  }
+  .nut-swiper-pagination {
+    position: absolute;
+    .swiper-pagination-bullet {
+      width: 8px;
+      height: 8px;
+      border-radius: 50%;
+      background-color: #000;
+      opacity: 0.2;
+      transition: all 0.5s ease;
+      -webkit-transition: all 0.5s ease;
+    }
+    .swiper-pagination-bullet.active {
+      background-color: #007aff;
+      opacity: 1;
+    }
+  }
+
+  &.vertical .nut-swiper-pagination {
+    right: 10px;
+    top: 50%;
+    transform: translate3d(0, -50%, 0);
+    -webkit-transform: translate3d(0, -50%, 0);
+    .swiper-pagination-bullet {
+      display: block;
+      margin: 6px 0;
+    }
+  }
+  &.horizontal .nut-swiper-pagination {
+    bottom: 10px;
+    width: 100%;
+    text-align: center;
+    .swiper-pagination-bullet {
+      display: inline-block;
+      margin: 0 3px;
+    }
+  }
+  img {
+    pointer-events: none;
+  }
+}

+ 408 - 0
src/packages/swiper/swiper.vue

@@ -0,0 +1,408 @@
+<template>
+  <div class="nut-swiper" :class="[direction, { dragging: dragging }]" @touchstart="_onTouchStart($event)"
+    @mousedown="_onTouchStart($event)">
+    <div class="nut-swiper-wrap" :style="{
+        transform: 'translate3d(' + translateX + 'px,' + translateY + 'px,0)',
+        'transition-duration': transitionDuration + 'ms',
+        '-webkit-transform': 'translate3d(' + translateX + 'px,' + translateY + 'px,0)',
+        '-webkit-transition-duration': transitionDuration + 'ms',
+        'transition-timing-function': 'ease'
+      }" @transitionend="_onTransitionEnd">
+      <slot></slot>
+    </div>
+    <div class="nut-swiper-pagination" v-show="paginationVisible">
+      <span class="swiper-pagination-bullet" :class="{ active: index + 1 === currentPage }"
+        v-for="(slide, index) in slideEls" :key="index" @click="paginationClickable && setPage(index + 1, true)">
+      </span>
+    </div>
+  </div>
+</template>
+<script>
+const VERTICAL = 'vertical';
+const HORIZONTAL = 'horizontal';
+export default {
+  name: 'nut-swiper',
+  props: {
+    direction: {
+      type: String,
+      default: HORIZONTAL,
+      validator: value => [VERTICAL, HORIZONTAL].indexOf(value) > -1
+    },
+    paginationVisible: {
+      type: Boolean,
+      default: false
+    },
+    paginationClickable: {
+      type: Boolean,
+      default: false
+    },
+    loop: {
+      type: Boolean,
+      default: false
+    },
+    speed: {
+      type: Number,
+      default: 500
+    },
+    canDragging: {
+      type: Boolean,
+      default: true
+    },
+    autoPlay: {
+      type: Number,
+      default: 0
+    },
+    initPage: {
+      type: Number,
+      default: 1
+    },
+    lazyLoad: {
+      type: Boolean,
+      default: false
+    },
+    lazyLoadUrl: {
+      type: String,
+      default: ''
+    },
+    swiperData: {
+      type: [Array],
+      default: function() {
+        return [];
+      }
+    }
+  },
+  watch: {
+    swiperData(newValue, oldValue) {
+      this.updateEvent();
+    }
+  },
+  data() {
+    return {
+      dragging: false,
+      currentPage: this.initPage,
+      lastPage: 1,
+      translateX: 0,
+      translateY: 0,
+      startTranslate: 0,
+      slideEls: [],
+      translateOffset: 0, //当前偏移初始位置距离
+      transitionDuration: 0, //切换动画时间
+      startPos: null,
+      delta: 0, //拖动距离
+      startTime: null,
+      isLoop: this.loop,
+      timer: null, //自动播放定时器
+      domTimer: null, //渲染延迟查找
+      stopAutoPlay: false, //停止自动播放
+      swiperWrap: null,
+      oneSlideTranslate: 0 //一个slide的大小
+    };
+  },
+  methods: {
+    //下一张
+    next() {
+      let page = this.currentPage;
+      if (page < this.slideEls.length || this.isLoop) {
+        this.setPage(page + 1, true, 'NEXT');
+      } else {
+        this._revert();
+      }
+    },
+    //上一张
+    prev() {
+      let page = this.currentPage;
+      if (page > 1 || this.isLoop) {
+        this.setPage(page - 1, true, 'PREV');
+      } else {
+        this._revert();
+      }
+    },
+    setPage(page, isHasAnimation, type) {
+      if (page === 0) {
+        this.currentPage = this.slideEls.length;
+      } else if (page === this.slideEls.length + 1) {
+        this.currentPage = 1;
+      } else {
+        this.currentPage = page;
+      }
+      this._setTranslate(this._getTranslateOfPage(page));
+      if (!isHasAnimation) {
+        this._slideClassHandle();
+      } else {
+        this._onTransitionStart(type);
+      }
+    },
+    isHorizontal() {
+      return this.direction === HORIZONTAL;
+    },
+    isVertical() {
+      return this.direction === VERTICAL;
+    },
+    renderLazyDom(slideEls) {
+      slideEls.forEach((item, index) => {
+        let src = item.getAttribute('data-src');
+        if (item.className != 'nut-swiper-slide nut-swiper-slide-selected') {
+          var dom = document.createElement('div');
+          //jd 图片占位图)
+          if (this.lazyLoadUrl) {
+            dom.style.backgroundImage = `url('${this.lazyLoadUrl}')`;
+            dom.className = 'nut-lazy img';
+          } else {
+            dom.className = 'nut-lazy preloader';
+          }
+          item.appendChild(dom);
+        }
+      });
+      return true;
+    },
+    updateEvent(pageSize) {
+      this.$nextTick(() => {
+        this.domTimer = setTimeout(() => {
+          if (pageSize != undefined) this.currentPage = pageSize;
+          this.swiperWrap = this.$el.querySelector('.nut-swiper-wrap');
+          this.slideEls = [...this.swiperWrap.children];
+          if (this.slideEls.length === 0) return;
+          this._getSlideDistance(this.slideEls[0]);
+          if (this.autoPlay != 0) {
+            this.isLoop = true;
+            this._createAutoPlay();
+          }
+          this.isLoop && this._createLoop();
+          this.setPage(this.currentPage, false);
+          this.lazyLoad && this.renderLazyDom(this.slideEls) && this._imgLazyLoad();
+        }, 0);
+      });
+    },
+    _slideClassHandle() {
+      let selectedSlide = this.$el.querySelector('.nut-swiper-slide-selected');
+      selectedSlide && selectedSlide.classList.remove('nut-swiper-slide-selected');
+      this.slideEls[this.currentPage - 1].classList.add('nut-swiper-slide-selected');
+      this.lastPage = this.currentPage;
+    },
+    _getSlideDistance(el) {
+      let styleArr = getComputedStyle(el);
+      let marginTop = styleArr['marginTop'].replace('px', '') - 0;
+      let marginBottom = styleArr['marginBottom'].replace('px', '') - 0;
+      let marginRight = styleArr['marginRight'].replace('px', '') - 0;
+      let marginLeft = styleArr['marginLeft'].replace('px', '') - 0;
+      if (this.isHorizontal()) {
+        this.oneSlideTranslate = marginRight + marginLeft + el['offsetWidth'];
+      } else {
+        this.oneSlideTranslate = marginTop + marginBottom + el['offsetHeight'];
+      }
+    },
+    _onTouchStart(e) {
+      this.swiperWrap.addEventListener('touchmove', this._onTouchMove, false);
+      this.swiperWrap.addEventListener('touchend', this._onTouchEnd, false);
+      this.swiperWrap.addEventListener('mousemove', this._onTouchMove, false);
+      this.swiperWrap.addEventListener('mouseup', this._onTouchEnd, false);
+      this.startPos = this._getTouchPos(e);
+      this.delta = 0;
+      this.startTranslate = this._getTranslateOfPage(this.currentPage);
+      if (this.isLoop) {
+        this._setTranslate(this.startTranslate);
+      }
+      this.startTime = new Date().getTime();
+      this.dragging = true;
+      this.transitionDuration = 0;
+      this.stopAutoPlay = true;
+    },
+    _onTouchMove(e) {
+      if (!this.dragging) return;
+      if (this.isHorizontal()) {
+        this.delta = this._getTouchPos(e).x - this.startPos.x;
+      } else {
+        this.delta = this._getTouchPos(e).y - this.startPos.y;
+      }
+      //let  isQuickAction = (new Date().getTime() - this.startTime) < 200;
+      if (this.canDragging && this._computePreventDefault(e)) {
+        e.preventDefault();
+        this._setTranslate(this.startTranslate + this.delta);
+        this.$emit('slideMove', this._getTranslate(), this.$el);
+        this.$emit('slide-move', this._getTranslate(), this.$el);
+      }
+    },
+    _onTouchEnd(e) {
+      if (!this.dragging) return;
+      this.dragging = false;
+      this.transitionDuration = this.speed;
+      let isQuickAction = new Date().getTime() - this.startTime < 1000;
+      if (this.delta < -this.oneSlideTranslate / 2 || (isQuickAction && this.delta < -15)) {
+        this.next();
+      } else if (this.delta > this.oneSlideTranslate / 2 || (isQuickAction && this.delta > 15)) {
+        this.prev();
+      } else {
+        this._revert();
+      }
+      this.swiperWrap.removeEventListener('touchmove', this._onTouchMove, false);
+      this.swiperWrap.removeEventListener('touchend', this._onTouchEnd, false);
+      this.swiperWrap.removeEventListener('mousemove', this._onTouchMove, false);
+      this.swiperWrap.removeEventListener('mouseup', this._onTouchEnd, false);
+    },
+    _revert() {
+      this.setPage(this.currentPage, true);
+    },
+    _computePreventDefault(e) {
+      let pos = this._getTouchPos(e);
+      let xDis = Math.abs(this.startPos.x - pos.x);
+      let yDis = Math.abs(this.startPos.y - pos.y);
+      if (xDis <= 5 && xDis >= 0) {
+        return false;
+      } else if (yDis > 5 && yDis / xDis > 0.5) {
+        return false;
+      } else {
+        return true;
+      }
+    },
+    _getTouchPos(e) {
+      let x = e.changedTouches ? e.changedTouches[0]['pageX'] : e['pageX'];
+      let y = e.changedTouches ? e.changedTouches[0]['pageY'] : e['pageY'];
+      return { x, y };
+    },
+    _onTransitionStart(type) {
+      this.transitionDuration = this.speed;
+      this.lazyLoad && this._imgLazyLoad(1);
+      if (this._isPageChanged()) {
+        this.$emit('slideChangeStart', this.currentPage, this.$el, type);
+        this.$emit('slide-change-start', this.currentPage, this.$el, type);
+      } else {
+        this.$emit('slideRevertStart', this.currentPage, this.$el, type);
+        this.$emit('slide-revert-start', this.currentPage, this.$el, type);
+      }
+    },
+    _onTransitionEnd() {
+      if (this._isPageChanged()) {
+        this.$emit('slideChangeEnd', this.currentPage, this.$el);
+        this.$emit('slide-change-end', this.currentPage, this.$el);
+      } else {
+        this.$emit('slideRevertEnd', this.currentPage, this.$el);
+        this.$emit('slide-revert-end', this.currentPage, this.$el);
+      }
+      this.transitionDuration = 0;
+      this.delta = 0;
+      this.lastPage = this.currentPage;
+
+      this._slideClassHandle();
+      if (this.isLoop) {
+        this._setTranslate(this._getTranslateOfPage(this.currentPage));
+      }
+      this.stopAutoPlay = false;
+    },
+    _isPageChanged() {
+      return this.lastPage !== this.currentPage;
+    },
+    _setTranslate(value) {
+      let translateName = this.isHorizontal() ? 'translateX' : 'translateY';
+      this[translateName] = value;
+    },
+    _getTranslate() {
+      let translateName = this.isHorizontal() ? 'translateX' : 'translateY';
+      return this[translateName];
+    },
+    _getTranslateOfPage(page) {
+      if (page === 0) return 0;
+      let propName = this.isHorizontal() ? 'offsetWidth' : 'offsetHeight';
+      let _this = this;
+      return (
+        -[].reduce.call(
+          this.slideEls,
+          function(total, el, i) {
+            return i > page - 2 ? total : total + _this.oneSlideTranslate;
+          },
+          0
+        ) + this.translateOffset
+      );
+    },
+    _createLoop() {
+      let propName = this.isHorizontal() ? 'offsetWidth' : 'offsetHeight';
+      let swiperWrapEl = this.$el.querySelector('.nut-swiper-wrap');
+      let duplicateFirstChild = swiperWrapEl.firstElementChild.cloneNode(true);
+      let duplicateLastChild = swiperWrapEl.lastElementChild.cloneNode(true);
+      swiperWrapEl.insertBefore(duplicateLastChild, swiperWrapEl.firstElementChild);
+      swiperWrapEl.appendChild(duplicateFirstChild);
+      this.translateOffset = -this.oneSlideTranslate;
+    },
+    _createAutoPlay() {
+      clearInterval(this.timer);
+      this.timer = setInterval(() => {
+        if (!this.stopAutoPlay) {
+          this.next();
+        }
+      }, this.autoPlay);
+    },
+    _requestAniFrame() {
+      return (
+        window.requestAnimationFrame ||
+        window.webkitRequestAnimationFrame ||
+        function(callback) {
+          window.setTimeout(callback, 1000 / 60);
+        }
+      );
+    },
+    _imgLazyLoad(type) {
+      let requestAniFrame = this._requestAniFrame();
+      let imgLazyLoadEl;
+      requestAniFrame(() => {
+        imgLazyLoadEl = this.swiperWrap.querySelectorAll('.nut-img-lazyload');
+        if (type == 1) {
+          imgLazyLoadEl = this.slideEls[this.currentPage - 1].querySelectorAll('.nut-img-lazyload');
+        }
+        imgLazyLoadEl.forEach((item, index) => {
+          if (!this._checkInView(item) && type != 1) return;
+          let src = item.getAttribute('data-src');
+          let img = new Image();
+          img.src = src;
+          img.onload = () => {
+            let lazyLoadingEle = item.parentElement.querySelector('.nut-lazy');
+            if (lazyLoadingEle) {
+              item.parentElement.removeChild(lazyLoadingEle);
+            }
+            item.src = src;
+            item.classList.remove('nut-img-lazyload');
+          };
+          img.onerror = () => {
+            item.src = this.lazyLoadUrl;
+            item.classList.remove('nut-img-lazyload');
+          };
+        });
+      });
+    },
+    _checkInView(imgItem) {
+      let imgRect = imgItem.getBoundingClientRect();
+      let swiperRect = this.$el.getBoundingClientRect();
+      let imgTop = imgRect.top;
+      let imgLeft = imgRect.left;
+      let swiperWidth = this.$el.clientWidth;
+      let swiperHeight = this.$el.clientHeight;
+      let swiperTop = swiperRect.top;
+      let swiperLeft = swiperRect.left;
+      let isInView = true;
+      if (imgTop > swiperTop + swiperHeight || imgLeft > swiperLeft + swiperWidth) {
+        isInView = false;
+      }
+      return isInView;
+    }
+  },
+  created() {},
+  mounted() {
+    this._onTouchMove = this._onTouchMove.bind(this);
+    this._onTouchEnd = this._onTouchEnd.bind(this);
+    this.updateEvent();
+  },
+  destroyed() {
+    this.timer = null;
+    this.domTimer = null;
+  },
+  activated() {
+    if (this.keepAlive) {
+      this.keepAlive = false;
+      this.updateEvent();
+    }
+  },
+  deactivated() {
+    this.keepAlive = true;
+    this.timer = null;
+    this.domTimer = null;
+  }
+};
+</script>