Browse Source

feat(imagepreview): 新增函数式调用、视频 (#858)

* fix: 样式冲突问题修复

* fix: 文档修改ImagePreview

* fix: 文档修复ImagePreview,体现taro

* upd: imagepreview组件优化

* feat: searchbar 组件启动开发

* feat: searchbar 开发初步完成;迁移至taro

* feat: searchbar 适配 taro

* upd: imageprevie import 优化

* upd: searchbar 外套form,对外暴露 input-type

* fix: imagepreview 引入 swiper 报错问题修复

* fix: 修复 searchbar 的一些问题;扩充文档内容,使描述更详细

* fix: searchbar 样式微调

* upd: imagepreview 点击轮播区域会关闭弹层

* upd: searchbar 1.props暴露背景样式2.slot使用优化3.sass变量命名优化

* docs: 背景样式增加默认值

* upd: imagepreview 引入video展示功能开发

* upd: 图片预览完善

* docs: imapgepreview 文档修改

* docs: imagepreview taro 文档完成

* docs: event close 调整

Co-authored-by: richard1015 <51844712@qq.com>
JackieScorpio 4 years ago
parent
commit
02454e8842

+ 3 - 2
src/config.json

@@ -243,12 +243,13 @@
         {
           "version": "3.0.0",
           "name": "ImagePreview",
-          "type": "component",
+          "type": "methods",
           "cName": "图片预览",
           "desc": "图片预览",
           "sort": 4,
           "show": true,
-          "taro": true,
+          "taro": false,
+          "tarodoc": true,
           "author": "zongyue3"
         }
       ]

+ 72 - 17
src/packages/__VUE/imagepreview/demo.vue

@@ -1,8 +1,29 @@
 <template>
   <div class="demo">
     <h2>基础用法</h2>
-    <nut-imagepreview :show="showPreview" :images="dataImgItem" @close="hideFn" />
-    <nut-cell isLink title="展示图片预览" :showIcon="true" @click="showFn"></nut-cell>
+    <nut-imagepreview :show="showPreview1" :images="imgData" @close="hideFn(1)" />
+    <nut-cell isLink title="展示图片预览" :showIcon="true" @click="showFn(1)"></nut-cell>
+
+    <h2>设置初始页码</h2>
+    <nut-imagepreview :show="showPreview2" :images="imgData" :content-close="true" :init-no="3" @close="hideFn(2)" />
+    <nut-cell isLink title="设置初始页码的图片预览" :showIcon="true" @click="showFn(2)"></nut-cell>
+
+    <h2>设置轮播指示器及颜色</h2>
+    <nut-imagepreview
+      :show="showPreview3"
+      :images="imgData"
+      :pagination-visible="true"
+      pagination-color="red"
+      @close="hideFn(3)"
+    />
+    <nut-cell isLink title="设置轮播指示器及颜色的图片预览" :showIcon="true" @click="showFn(3)"></nut-cell>
+
+    <h2>视频、图片预览</h2>
+    <nut-imagepreview :show="showPreview4" :videos="videoData" :images="imgData" @close="hideFn(4)" />
+    <nut-cell isLink title="视频、图片预览" :showIcon="true" @click="showFn(4)"></nut-cell>
+
+    <h2>函数式调用</h2>
+    <nut-cell isLink title="函数式调用的图片预览" :showIcon="true" @click="fnShow"></nut-cell>
   </div>
 </template>
 
@@ -10,43 +31,77 @@
 import { reactive, toRefs } from 'vue';
 import { createComponent } from '../../utils/create';
 const { createDemo } = createComponent('imagepreview');
+import { ImagePreview } from '@/packages/nutui.vue';
 export default createDemo({
   props: {},
   setup() {
     const resData = reactive({
-      showPreview: false,
-      dataImgItem: [
+      showPreview1: false,
+      showPreview2: false,
+      showPreview3: false,
+      showPreview4: false,
+      imgData: [
         {
-          imgSrc:
-            '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg'
+          src: '//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'
+          src: '//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'
+          src: '//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'
+          src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/30042/36/427/82951/5c3bfdabE3faf2f66/9adca782661c988c.jpg'
+        }
+      ],
+      videoData: [
+        {
+          source: {
+            src: 'https://storage.jd.com/about/big-final.mp4?Expires=3730193075&AccessKey=3LoYX1dQWa6ZXzQl&Signature=ViMFjz%2BOkBxS%2FY1rjtUVqbopbJI%3D',
+            type: 'video/mp4'
+          },
+          options: {
+            muted: true,
+            controls: true
+          }
+        },
+        {
+          source: {
+            src: 'https://storage.jd.com/about/big-final.mp4?Expires=3730193075&AccessKey=3LoYX1dQWa6ZXzQl&Signature=ViMFjz%2BOkBxS%2FY1rjtUVqbopbJI%3D',
+            type: 'video/mp4'
+          },
+          options: {
+            muted: true,
+            controls: true
+          }
         }
       ]
     });
+    const onClose = () => {
+      console.log('imagepreview closed');
+    };
+
+    const showFn = (i: number) => {
+      (resData as any)['showPreview' + i] = true;
+    };
 
-    const showFn = () => {
-      resData.showPreview = true;
+    const fnShow = () => {
+      ImagePreview({
+        show: true,
+        images: resData.imgData,
+        onClose
+      });
     };
 
-    const hideFn = () => {
-      resData.showPreview = false;
+    const hideFn = (i: number) => {
+      (resData as any)['showPreview' + i] = false;
     };
 
     return {
       ...toRefs(resData),
       showFn,
-      hideFn
+      hideFn,
+      fnShow
     };
   }
 });

+ 236 - 13
src/packages/__VUE/imagepreview/doc.md

@@ -1,18 +1,15 @@
-# Imagepreview 组件
+# Imagepreview 图片预览
 
 ### 介绍
     
-图片预览
+支持全屏预览视频和图片,可函数式调用
 
 ### 安装
 
 ```javascript
 import { createApp, reactive, toRefs } from 'vue';
 
-// vue
-import { ImagePreview, Swiper, SwiperItem } from '@nutui/nutui';
-// taro
-import { ImagePreview } from '@nutui/nutui-taro';
+import { ImagePreview } from '@nutui/nutui';
 
 
 const app = createApp();
@@ -22,26 +19,30 @@ app.use(ImagePreview);
 ### 基础用法
 
 ```html
-<nut-imagepreview :show="showPreview" :images="dataImgItem" @close="hideFn" />
-<nut-cell title="展示图片预览" :showIcon="true" @click="showFn"></nut-cell>
+<nut-imagepreview
+    :show="showPreview"
+    :images="imgData"
+    @close="hideFn"
+/>
+<nut-cell isLink title="展示图片预览" :showIcon="true" @click="showFn"></nut-cell>
 ```
 
 ```javascript
 setup() {
     const resData = reactive({
         showPreview: false,
-        dataImgItem: [
+        imgData: [
             {
-            imgSrc: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg',
+                src: '//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',
+                src: '//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',
+                src: '//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',
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/30042/36/427/82951/5c3bfdabE3faf2f66/9adca782661c988c.jpg',
             },
         ]
     });
@@ -61,13 +62,235 @@ setup() {
     };
 },
 ```
+
+### 设置初始页码
+
+```html
+<nut-imagepreview
+    :show="showPreview"
+    :images="imgData"
+    :content-close="true"
+    :init-no="3"
+    @close="hideFn"
+/>
+<nut-cell isLink title="设置初始页码的图片预览" :showIcon="true" @click="showFn"></nut-cell>
+```
+
+```javascript
+setup() {
+    const resData = reactive({
+        showPreview: false,
+        imgData: [
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg',
+            },
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/26597/30/4870/174583/5c35c5d2Ed55eedc6/50e27870c25e7a82.png',
+            },
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/9542/17/12873/201687/5c3c4362Ea9eb757d/60026b40a9d60d85.jpg',
+            },
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/30042/36/427/82951/5c3bfdabE3faf2f66/9adca782661c988c.jpg',
+            },
+        ]
+    });
+
+    const showFn = () => {
+        resData.showPreview = true;
+    }
+
+    const hideFn = () => {
+        resData.showPreview = false;
+    }
+    
+    return {
+        ...toRefs(resData),
+        showFn,
+        hideFn
+    };
+},
+```
+
+### 设置轮播指示器及颜色
+
+```html
+<nut-imagepreview
+    :show="showPreview"
+    :images="imgData"
+    :pagination-visible="true"
+    pagination-color="red"
+    @close="hideFn"
+/>
+<nut-cell isLink title="设置轮播指示器及颜色" :showIcon="true" @click="showFn"></nut-cell>
+```
+
+```javascript
+setup() {
+    const resData = reactive({
+        showPreview: false,
+        imgData: [
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg',
+            },
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/26597/30/4870/174583/5c35c5d2Ed55eedc6/50e27870c25e7a82.png',
+            },
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/9542/17/12873/201687/5c3c4362Ea9eb757d/60026b40a9d60d85.jpg',
+            },
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/30042/36/427/82951/5c3bfdabE3faf2f66/9adca782661c988c.jpg',
+            },
+        ]
+    });
+
+    const showFn = () => {
+        resData.showPreview = true;
+    }
+
+    const hideFn = () => {
+        resData.showPreview = false;
+    }
+    
+    return {
+        ...toRefs(resData),
+        showFn,
+        hideFn
+    };
+},
+```
+
+### 视频、图片预览
+
+```html
+<nut-imagepreview
+    :show="showPreview"
+    :images="imgData"
+    :videos="videoData"      
+    @close="hideFn"
+/>
+<nut-cell isLink title="视频、图片预览" :showIcon="true" @click="showFn"></nut-cell>
+```
+
+```javascript
+setup() {
+    const resData = reactive({
+        showPreview: false,
+        imgData: [
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg',
+            },
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/26597/30/4870/174583/5c35c5d2Ed55eedc6/50e27870c25e7a82.png',
+            },
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/9542/17/12873/201687/5c3c4362Ea9eb757d/60026b40a9d60d85.jpg',
+            },
+            {
+                src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/30042/36/427/82951/5c3bfdabE3faf2f66/9adca782661c988c.jpg',
+            },
+        ],
+        videoData: [
+            {
+                source: {
+                    src: 'https://storage.jd.com/about/big-final.mp4?Expires=3730193075&AccessKey=3LoYX1dQWa6ZXzQl&Signature=ViMFjz%2BOkBxS%2FY1rjtUVqbopbJI%3D',
+                    type: 'video/mp4'
+                },
+                options: {
+                    muted: true,
+                    controls: true
+                }
+            },
+            {
+                source: {
+                    src: 'https://storage.jd.com/about/big-final.mp4?Expires=3730193075&AccessKey=3LoYX1dQWa6ZXzQl&Signature=ViMFjz%2BOkBxS%2FY1rjtUVqbopbJI%3D',
+                    type: 'video/mp4'
+                },
+                options: {
+                    muted: true,
+                    controls: true
+                }
+            }
+        ],
+    });
+
+    const showFn = () => {
+        resData.showPreview = true;
+    }
+
+    const hideFn = () => {
+        resData.showPreview = false;
+    }
+    
+    return {
+        ...toRefs(resData),
+        showFn,
+        hideFn
+    };
+},
+```
+                
+### 函数式调用
+
+```html
+<nut-cell isLink title="函数式调用的图片预览" :showIcon="true" @click="fnShow"></nut-cell>
+```
+
+```javascript
+import { ImagePreview } from '@nutui/nutui';
+
+export default {
+    setup() {
+        const resData = reactive({
+            imgData: [
+                {
+                    src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg',
+                },
+                {
+                    src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/26597/30/4870/174583/5c35c5d2Ed55eedc6/50e27870c25e7a82.png',
+                },
+                {
+                    src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/9542/17/12873/201687/5c3c4362Ea9eb757d/60026b40a9d60d85.jpg',
+                },
+                {
+                    src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/30042/36/427/82951/5c3bfdabE3faf2f66/9adca782661c988c.jpg',
+                },
+            ]
+        });
+
+        const onClose = () => {
+        console.log('imagepreview closed');
+        };
+
+        const fnShow = () => {
+        ImagePreview({
+            show: true,
+            images: resData.imgData,
+            onClose
+        })
+        };
+        
+        return {
+            ...toRefs(resData),
+            fnShow
+        };
+    },
+}
+```
     
 ### Props
 
 | 字段 | 说明 | 类型 | 默认值
 |----- | ----- | ----- | ----- 
 | show | 是否展示预览图片 | Boolean | false
+| videos | 预览的视频数组(视频自动放到图片之前) | Array<`Object`> | []
 | images | 预览图片数组 | Array<`String`> | []
+| init-no | 初始页码 | Number | 1
+| pagination-visible | 分页指示器是否展示    | Boolean | false |
+| pagination-color   | 分页指示器选中的颜色    | String  | '#fff'  |
+| content-close   | 点击图片可以退出预览    | Boolean  | false  |
+
     
 ### Events
 

+ 4 - 0
src/packages/__VUE/imagepreview/doc.taro.md

@@ -0,0 +1,4 @@
+# ImagePreview 图片预览
+
+
+#### 直接使用 Taro 现有 previewImage 组件开发 [参考文档](https://docs.taro.zone/docs/apis/media/image/previewImage)

+ 56 - 0
src/packages/__VUE/imagepreview/index.ts

@@ -0,0 +1,56 @@
+import ImagePreview from './index.vue';
+import { render, createVNode, h } from 'vue';
+export class ImagePreviewOptions {
+  show?: Boolean = false;
+  images?: Array<string> = [];
+  initNo?: Number = 1;
+  paginationVisible?: Boolean = false;
+  paginationColor?: string = '';
+  teleport?: String | HTMLElement = 'body';
+
+  // function
+  onClose?: Function = () => {};
+}
+
+class ImagePreviewFunction {
+  options: ImagePreviewOptions = new ImagePreviewOptions();
+
+  constructor(_options: ImagePreviewOptions) {
+    let options = Object.assign(this.options, _options);
+    let elWarp: HTMLElement = document.body;
+    let teleport = options.teleport as string;
+    if (teleport != 'body') {
+      if (typeof teleport == 'string') {
+        elWarp = document.querySelector(teleport) as HTMLElement;
+      } else {
+        elWarp = options.teleport as HTMLElement;
+      }
+    }
+    const root = document.createElement('view');
+    root.id = 'imagepreview-' + new Date().getTime();
+    const Wrapper = {
+      setup() {
+        // options.onClose = () => {
+        //     elWarp.removeChild(root);
+        // };
+        options.teleport = `#${root.id}`;
+        return () => {
+          return h(ImagePreview, options);
+        };
+      }
+    };
+    const instance: any = createVNode(Wrapper);
+    elWarp.appendChild(root);
+    render(instance, root);
+  }
+}
+
+const _ImagePreview = function (options: ImagePreviewOptions) {
+  return new ImagePreviewFunction(options);
+};
+_ImagePreview.install = (app: any) => {
+  app.use(ImagePreview);
+  app.config.globalProperties.$imagepreview = _ImagePreview;
+};
+export { ImagePreview };
+export default _ImagePreview;

+ 70 - 13
src/packages/__VUE/imagepreview/index.vue

@@ -1,27 +1,36 @@
 <template>
-  <view class="nut-imagepreview">
-    <nut-popup pop-class="custom-pop" v-model:visible="showPop" @click="closePop">
+  <nut-popup pop-class="custom-pop" v-model:visible="showPop" @click="onClose">
+    <view class="nut-imagepreview" @click.stop="closeOnImg">
       <nut-swiper
         v-if="showPop"
         :auto-play="3000"
         class="nut-imagepreview-swiper"
         :loop="true"
+        :is-preventDefault="false"
         direction="horizontal"
         @change="slideChangeEnd"
-        :is-preventDefault="false"
+        :init-page="initNo > maxNo ? maxNo - 1 : initNo - 1"
+        :pagination-visible="paginationVisible"
+        :pagination-color="paginationColor"
       >
+        <nut-swiper-item v-for="(item, index) in videos" :key="index">
+          <nut-video :source="item.source" :options="item.options"></nut-video>
+        </nut-swiper-item>
         <nut-swiper-item v-for="(item, index) in images" :key="index">
-          <img :src="item.imgSrc" class="nut-imagepreview-img" />
+          <img :src="item.src" class="nut-imagepreview-img" />
         </nut-swiper-item>
       </nut-swiper>
-      <view class="nut-imagepreview-index"> {{ active }} / {{ images.length }} </view>
-    </nut-popup>
-  </view>
+      <view class="nut-imagepreview-index"> {{ active }} / {{ images.length + videos.length }} </view>
+    </view>
+  </nut-popup>
 </template>
 <script lang="ts">
-import { toRefs, reactive, watch } from 'vue';
+import { toRefs, reactive, watch, onMounted, ref } from 'vue';
 import { createComponent } from '../../utils/create';
 import Popup from '../popup/index.vue';
+import Video from '../video/index.vue';
+import Swiper from '../swiper/index.vue';
+import SwiperItem from '../swiperitem/index.vue';
 const { componentName, create } = createComponent('imagepreview');
 
 export default create({
@@ -33,25 +42,65 @@ export default create({
     images: {
       type: Array,
       default: () => []
+    },
+    videos: {
+      type: Array,
+      default: () => []
+    },
+    contentClose: {
+      type: Boolean,
+      default: false
+    },
+    initNo: {
+      type: Number,
+      default: 1
+    },
+    paginationVisible: {
+      type: Boolean,
+      default: false
+    },
+    paginationColor: {
+      type: String,
+      default: '#fff'
     }
   },
+  emits: ['close'],
   components: {
-    [Popup.name]: Popup
+    [Popup.name]: Popup,
+    [Video.name]: Video,
+    [Swiper.name]: Swiper,
+    [SwiperItem.name]: SwiperItem
   },
 
   setup(props, { emit }) {
     const { show, images } = toRefs(props);
 
     const state = reactive({
-      showPop: show,
-      active: 1
+      showPop: false,
+      active: 1,
+      maxNo: 1,
+      source: {
+        src: 'https://storage.jd.com/about/big-final.mp4?Expires=3730193075&AccessKey=3LoYX1dQWa6ZXzQl&Signature=ViMFjz%2BOkBxS%2FY1rjtUVqbopbJI%3D',
+        type: 'video/mp4'
+      },
+      options: {
+        muted: true,
+        controls: true
+      }
     });
 
     const slideChangeEnd = function (page: number) {
       state.active = page + 1;
     };
 
-    const closePop = function () {
+    const closeOnImg = () => {
+      // 点击内容区域的图片是否可以关闭弹层(视频区域由于nut-video做了限制,无法关闭弹层)
+      if (props.contentClose) {
+        onClose();
+      }
+    };
+
+    const onClose = () => {
       state.showPop = false;
       state.active = 1;
       emit('close');
@@ -64,10 +113,18 @@ export default create({
       }
     );
 
+    onMounted(() => {
+      // 初始化页码
+      state.active = props.initNo;
+      state.showPop = props.show;
+      state.maxNo = props.images.length + props.videos.length;
+    });
+
     return {
       ...toRefs(state),
       slideChangeEnd,
-      closePop
+      onClose,
+      closeOnImg
     };
   }
 });

+ 7 - 11
src/packages/__VUE/signature/index.taro.vue

@@ -14,12 +14,8 @@
         @touchleave="leaveEventHandler"
       />
     </div>
-    <nut-button class="nut-signature-btn" type="default" @click="clear()"
-      >重签</nut-button
-    >
-    <nut-button class="nut-signature-btn" type="primary" @click="confirm()"
-      >确认</nut-button
-    >
+    <nut-button class="nut-signature-btn" type="default" @click="clear()">重签</nut-button>
+    <nut-button class="nut-signature-btn" type="primary" @click="confirm()">确认</nut-button>
   </div>
 </template>
 <script lang="ts">
@@ -108,21 +104,21 @@ export default create({
         return;
       }
       Taro.createSelectorQuery()
-        .select("#spcanvas")
+        .select('#spcanvas')
         .fields({
           node: true,
-          size: true,
+          size: true
         })
         .exec(async (res) => {
           Taro.canvasToTempFilePath({
             canvas: res[0].node,
-            fileType: props.type,
+            fileType: props.type
           })
             .then((res) => {
-              emit("confirm", res.tempFilePath);
+              emit('confirm', res.tempFilePath);
             })
             .catch((e) => {
-              emit("confirm", e);
+              emit('confirm', e);
             });
         });
     };