Browse Source

fix(swiper): support dynamic update imgs(#1115)

suzigang 3 years ago
parent
commit
95b5d11d6a

+ 17 - 0
src/packages/__VUE/swiper/demo.vue

@@ -16,6 +16,14 @@
         </nut-swiper-item>
       </nut-swiper>
     </view>
+    <h2>{{ translate('dynamicDel') }}</h2>
+    <view class="demo-box">
+      <nut-swiper :init-page="page" :pagination-visible="true" pagination-color="#426543" auto-play="2000">
+        <nut-swiper-item v-for="item in list2" :key="item">
+          <img :src="item" alt="" />
+        </nut-swiper-item>
+      </nut-swiper>
+    </view>
     <h2>{{ translate('size') }}</h2>
     <view class="demo-box">
       <nut-swiper :init-page="page2" :loop="false" width="300">
@@ -74,6 +82,7 @@ useTranslate({
   'zh-CN': {
     basic: '基本用法',
     asyc: '异步加载(3s)',
+    dynamicDel: '动态删除',
     size: '自定义大小',
     indicator: '自定义指示器',
     indicator1: '自定义指示器(异步3s)',
@@ -82,6 +91,7 @@ useTranslate({
   'en-US': {
     basic: 'Basic Usage',
     asyc: 'Asynchronous loading(3s)',
+    dynamicDel: 'Dynamic deletion',
     size: 'Custom size',
     indicator: 'Custom indicator',
     indicator1: 'Custom indicator(Asynchronous loading(3s))',
@@ -104,6 +114,12 @@ export default createDemo({
         'https://storage.360buyimg.com/jdc-article/welcomenutui.jpg',
         'https://storage.360buyimg.com/jdc-article/fristfabu.jpg'
       ],
+      list2: [
+        'https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg',
+        'https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg',
+        'https://storage.360buyimg.com/jdc-article/welcomenutui.jpg',
+        'https://storage.360buyimg.com/jdc-article/fristfabu.jpg'
+      ],
       list1: [] as string[]
     });
     const change = (index: number) => {
@@ -115,6 +131,7 @@ export default createDemo({
     onMounted(() => {
       setTimeout(() => {
         state.list1 = state.list.slice();
+        state.list2.splice(1, 1);
       }, 3000);
     });
     return {

+ 49 - 0
src/packages/__VUE/swiper/doc.en-US.md

@@ -114,6 +114,55 @@ app.use(Swiper).use(SwiperItem);
 
 :::
 
+### Dynamic deletion
+
+Support dynamic addition / deletion of pictures
+
+:::demo
+
+```html
+<template>
+  <nut-swiper :init-page="page" :pagination-visible="true" pagination-color="#426543" auto-play="3000">
+     <nut-swiper-item v-for="item in list" :key="item">
+        <img :src="item" alt="" />
+      </nut-swiper-item>
+  </nut-swiper>
+</template>
+<script lang="ts">
+  import { reactive, toRefs, onMounted } from 'vue';
+  export default {
+    setup() {
+      const state = reactive({
+        page: 2,
+        list: [
+          'https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg',
+          'https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg',
+          'https://storage.360buyimg.com/jdc-article/welcomenutui.jpg',
+          'https://storage.360buyimg.com/jdc-article/fristfabu.jpg'
+        ]
+      });
+      onMounted(() => {
+        setTimeout(() => {
+          state.list.splice(1, 1);
+        }, 3000);
+      });
+      return { ...toRefs(state) };
+    }
+  };
+</script>
+<style lang="scss" scoped>
+  .nut-swiper-item {
+    line-height: 150px;
+    img {
+      width: 100%;
+      height: 100%;
+    }
+  }
+</style>
+```
+
+:::
+
 ### Custom size
 
 `width` Custom rotation size

+ 49 - 0
src/packages/__VUE/swiper/doc.md

@@ -114,6 +114,55 @@ app.use(Swiper).use(SwiperItem);
 
 :::
 
+### 动态加载
+
+支持动态增加/删除图片
+
+:::demo
+
+```html
+<template>
+  <nut-swiper :init-page="page" :pagination-visible="true" pagination-color="#426543" auto-play="3000">
+     <nut-swiper-item v-for="item in list" :key="item">
+        <img :src="item" alt="" />
+      </nut-swiper-item>
+  </nut-swiper>
+</template>
+<script lang="ts">
+  import { reactive, toRefs, onMounted } from 'vue';
+  export default {
+    setup() {
+      const state = reactive({
+        page: 2,
+        list: [
+          'https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg',
+          'https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg',
+          'https://storage.360buyimg.com/jdc-article/welcomenutui.jpg',
+          'https://storage.360buyimg.com/jdc-article/fristfabu.jpg'
+        ]
+      });
+      onMounted(() => {
+        setTimeout(() => {
+          state.list.splice(1, 1);
+        }, 3000);
+      });
+      return { ...toRefs(state) };
+    }
+  };
+</script>
+<style lang="scss" scoped>
+  .nut-swiper-item {
+    line-height: 150px;
+    img {
+      width: 100%;
+      height: 100%;
+    }
+  }
+</style>
+```
+
+:::
+
 ### 自定义大小
 
 `width` 自定义轮播大小

+ 31 - 3
src/packages/__VUE/swiper/index.taro.vue

@@ -46,7 +46,8 @@ import {
   reactive,
   computed,
   ref,
-  watch
+  watch,
+  VNode
 } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 import { useTouch } from './use-touch';
@@ -121,6 +122,7 @@ export default create({
       touchTime: 0,
       autoplayTimer: 0 as number | undefined,
       children: [] as ComponentPublicInstance[],
+      childrenVNode: [] as VNode[],
       style: {}
     });
 
@@ -169,8 +171,34 @@ export default create({
     };
 
     const relation = (child: ComponentInternalInstance) => {
-      if (child.proxy) {
-        state.children.push(child.proxy);
+      let children = [] as VNode[];
+      let slot = slots?.default?.() as VNode[];
+      slot = slot.filter((item: VNode) => item.children && Array.isArray(item.children));
+      slot.forEach((item: VNode) => {
+        children = children.concat(item.children as VNode[]);
+      });
+      if (!state.childrenVNode.length) {
+        state.childrenVNode = children.slice();
+        child.proxy && state.children.push(child.proxy);
+      } else {
+        if (state.childrenVNode.length > children.length) {
+          state.children = state.children.filter((item: ComponentPublicInstance) => child.proxy !== item);
+        } else if (state.childrenVNode.length < children.length) {
+          for (let i = 0; i < state.childrenVNode.length; i++) {
+            if ((children[i] as VNode).key !== (state.childrenVNode[i] as VNode).key) {
+              child.proxy && state.children.splice(i, 0, child.proxy);
+              child.vnode && state.childrenVNode.splice(i, 0, child.vnode);
+              break;
+            }
+          }
+          if (state.childrenVNode.length !== children.length) {
+            child.proxy && state.children.push(child.proxy);
+            child.vnode && state.childrenVNode.push(child.vnode);
+          }
+        } else {
+          state.childrenVNode = children.slice();
+          child.proxy && state.children.push(child.proxy);
+        }
       }
     };
 

+ 31 - 6
src/packages/__VUE/swiper/index.vue

@@ -37,8 +37,6 @@
 
 <script lang="ts">
 import {
-  onMounted,
-  onActivated,
   onDeactivated,
   onBeforeUnmount,
   provide,
@@ -48,7 +46,8 @@ import {
   computed,
   nextTick,
   ref,
-  watch
+  watch,
+  VNode
 } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 import { useTouch } from './use-touch';
@@ -120,6 +119,7 @@ export default create({
       touchTime: 0,
       autoplayTimer: 0 as number | undefined,
       children: [] as ComponentPublicInstance[],
+      childrenVNode: [] as VNode[],
       style: {}
     });
 
@@ -168,8 +168,34 @@ export default create({
     };
 
     const relation = (child: ComponentInternalInstance) => {
-      if (child.proxy) {
-        state.children.push(child.proxy);
+      let children = [] as VNode[];
+      let slot = slots?.default?.() as VNode[];
+      slot = slot.filter((item: VNode) => item.children && Array.isArray(item.children));
+      slot.forEach((item: VNode) => {
+        children = children.concat(item.children as VNode[]);
+      });
+      if (!state.childrenVNode.length) {
+        state.childrenVNode = children.slice();
+        child.proxy && state.children.push(child.proxy);
+      } else {
+        if (state.childrenVNode.length > children.length) {
+          state.children = state.children.filter((item: ComponentPublicInstance) => child.proxy !== item);
+        } else if (state.childrenVNode.length < children.length) {
+          for (let i = 0; i < state.childrenVNode.length; i++) {
+            if ((children[i] as VNode).key !== (state.childrenVNode[i] as VNode).key) {
+              child.proxy && state.children.splice(i, 0, child.proxy);
+              child.vnode && state.childrenVNode.splice(i, 0, child.vnode);
+              break;
+            }
+          }
+          if (state.childrenVNode.length !== children.length) {
+            child.proxy && state.children.push(child.proxy);
+            child.vnode && state.childrenVNode.push(child.vnode);
+          }
+        } else {
+          state.childrenVNode = children.slice();
+          child.proxy && state.children.push(child.proxy);
+        }
       }
     };
 
@@ -405,7 +431,6 @@ export default create({
       () => state.children.length,
       () => {
         nextTick(() => {
-          // console.log(state.active)
           init();
         });
       }

+ 5 - 1
src/packages/__VUE/swiperitem/index.taro.vue

@@ -5,7 +5,7 @@
 </template>
 
 <script lang="ts">
-import { computed, reactive, inject, getCurrentInstance, watch } from 'vue';
+import { computed, reactive, inject, getCurrentInstance, onUnmounted } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 import { useExpose } from '@/packages/utils/useExpose/index';
 const { create, componentName } = createComponent('swiper-item');
@@ -47,6 +47,10 @@ export default create({
       state.offset = offset;
     };
 
+    onUnmounted(() => {
+      parent['relation'](getCurrentInstance(), 'unmount');
+    });
+
     useExpose({ setOffset });
 
     return {

+ 5 - 1
src/packages/__VUE/swiperitem/index.vue

@@ -5,7 +5,7 @@
 </template>
 
 <script lang="ts">
-import { computed, reactive, inject, getCurrentInstance, watch } from 'vue';
+import { computed, reactive, inject, getCurrentInstance, onUnmounted } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 import { useExpose } from '@/packages/utils/useExpose/index';
 const { create, componentName } = createComponent('swiper-item');
@@ -47,6 +47,10 @@ export default create({
       state.offset = offset;
     };
 
+    onUnmounted(() => {
+      parent['relation'](getCurrentInstance(), 'unmount');
+    });
+
     useExpose({ setOffset });
 
     return {

+ 15 - 0
src/sites/mobile-taro/vue/src/exhibition/pages/swiper/index.vue

@@ -16,6 +16,14 @@
         </nut-swiper-item>
       </nut-swiper>
     </view>
+    <h2>动态加载</h2>
+    <view class="demo-box">
+      <nut-swiper :init-page="page" :pagination-visible="true" pagination-color="#426543" auto-play="2000">
+        <nut-swiper-item v-for="item in list2" :key="item">
+          <img :src="item" alt="" />
+        </nut-swiper-item>
+      </nut-swiper>
+    </view>
     <h2>自定义大小</h2>
     <view class="demo-box">
       <nut-swiper :init-page="page2" :loop="false" width="300">
@@ -84,6 +92,12 @@ export default {
         'https://storage.360buyimg.com/jdc-article/welcomenutui.jpg',
         'https://storage.360buyimg.com/jdc-article/fristfabu.jpg'
       ],
+      list2: [
+        'https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg',
+        'https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg',
+        'https://storage.360buyimg.com/jdc-article/welcomenutui.jpg',
+        'https://storage.360buyimg.com/jdc-article/fristfabu.jpg'
+      ],
       list1: [] as string[]
     });
     const change = (index: number) => {
@@ -95,6 +109,7 @@ export default {
     onMounted(() => {
       setTimeout(() => {
         state.list1 = state.list.slice();
+        state.list2.splice(1, 1);
       }, 3000);
     });
     return {