|
1 | | -import { SwiperProps } from '@tarojs/components' |
2 | | -import { |
3 | | - defineCustomElementTaroSwiperCore, |
4 | | - defineCustomElementTaroSwiperItemCore, |
5 | | -} from '@tarojs/components/dist/components' |
6 | | -import { eventCenter } from '@tarojs/runtime' |
7 | | -import { isFunction } from '@tarojs/shared' |
8 | 1 | import Taro from '@tarojs/taro' |
9 | | -import { showActionSheet, showToast } from '@tarojs/taro-h5' |
10 | 2 |
|
11 | | -import native from '../../NativeApi' |
12 | 3 | import { shouldBeObject } from '../../utils' |
13 | 4 | import { MethodHandler } from '../../utils/handler' |
14 | | -import { saveImageToPhotosAlbum } from './saveImageToPhotosAlbum' |
| 5 | +import nativeImage from './NativeImage' |
15 | 6 |
|
16 | 7 | /** |
17 | 8 | * 在新页面中全屏预览图片。预览的过程中用户可以进行保存图片、发送给朋友等操作。 |
18 | 9 | * |
19 | 10 | * @canUse previewImage |
20 | 11 | * @__object [urls, current, showmenu] |
21 | 12 | */ |
22 | | -export const previewImage: typeof Taro.previewImage = async (options) => { |
23 | | - // TODO 改为通过 window.__taroAppConfig 获取配置的 Swiper 插件创建节点 |
24 | | - defineCustomElementTaroSwiperCore() |
25 | | - defineCustomElementTaroSwiperItemCore() |
26 | | - const PRESS_TIME = 1000 |
27 | | - const SHOW_TIME = 2000 |
28 | | - const SAVE_IMAGE_BUTTON = 1 |
29 | | - |
| 13 | +export const previewImage: typeof Taro.previewImage = (options) => { |
30 | 14 | // options must be an Object |
31 | 15 | const isObject = shouldBeObject(options) |
32 | 16 | if (!isObject.flag) { |
33 | 17 | const res = { errMsg: `previewImage:fail ${isObject.msg}` } |
34 | 18 | console.error(res.errMsg) |
35 | 19 | return Promise.reject(res) |
36 | 20 | } |
37 | | - |
38 | | - const { urls = [], current, success, fail, complete, showmenu } = options |
| 21 | + const { urls = [], current, showmenu, success, fail, complete } = options |
39 | 22 | const handle = new MethodHandler({ name: 'previewImage', success, fail, complete }) |
40 | | - const container = document.createElement('div') |
41 | | - const removeHandler = () => { |
42 | | - eventCenter.off('__taroRouterChange', removeHandler) |
43 | | - container.remove() |
44 | | - eventCenter.trigger('__taroExitFullScreen', {}) |
45 | | - } |
46 | | - // 路由改变后应该关闭预览框 |
47 | | - eventCenter.on('__taroRouterChange', removeHandler) |
48 | | - |
49 | | - container.classList.add('preview-image') |
50 | | - container.style.cssText = |
51 | | - 'position:fixed;top:0;left:0;z-index:999;width:100%;height:100%;overflow:hidden;outline:0;background-color:#111;' |
52 | | - container.addEventListener('click', removeHandler) |
53 | | - |
54 | | - const swiper: HTMLElement & Omit<SwiperProps, 'style' | 'children'> = document.createElement('taro-swiper-core') |
55 | | - // @ts-ignore |
56 | | - swiper.full = true |
57 | | - // @ts-ignore |
58 | | - swiper.zoom = true |
59 | | - |
60 | | - let children: Node[] = [] |
61 | | - |
62 | | - function loadImage (url: string, loadFail: typeof fail): Promise<Node> { |
63 | | - return new Promise((resolve) => { |
64 | | - const item = document.createElement('taro-swiper-item-core') |
65 | | - item.style.cssText = 'display:flex;align-items:start;justify-content:center;overflow-y:scroll;' |
66 | | - const image = new Image() |
67 | 23 |
|
68 | | - image.style.maxWidth = '100%' |
69 | | - image.src = url |
70 | | - const div = document.createElement('div') |
71 | | - div.classList.add('swiper-zoom-container') |
72 | | - div.style.cssText = 'display:flex;align-items:center;justify-content:center;max-width:100%;min-height:100%;' |
73 | | - div.appendChild(image) |
74 | | - div.style.zIndex = '900' |
75 | | - |
76 | | - let pressTimer |
77 | | - function startPress () { |
78 | | - pressTimer = setTimeout(async function () { |
79 | | - if (!showmenu) { |
80 | | - return |
81 | | - } |
82 | | - try { |
83 | | - const { tapIndex } = await showActionSheet({ |
84 | | - itemList: ['转发给朋友', '保存图片', '收藏', '翻译图片中的文字', '提取文字'], |
85 | | - }) |
86 | | - if (tapIndex !== SAVE_IMAGE_BUTTON) { |
87 | | - return |
88 | | - } |
89 | | - native.downloadFile({ |
90 | | - url: url, // 仅为示例,并非真实的资源 |
91 | | - success: function (res: any) { |
92 | | - // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容 |
93 | | - saveImageToPhotosAlbum({ |
94 | | - filePath: res.tempFilePath, |
95 | | - success: function (res: any) { |
96 | | - showToast({ |
97 | | - title: '保存成功', |
98 | | - icon: 'success', |
99 | | - duration: SHOW_TIME, |
100 | | - }) |
101 | | - handle.success(res) |
102 | | - }, |
103 | | - fail: function (err: any) { |
104 | | - handle.fail(err) |
105 | | - }, |
106 | | - }) |
107 | | - }, |
108 | | - fail: function (err: any) { |
109 | | - handle.fail(err) |
110 | | - }, |
111 | | - }) |
112 | | - } catch (e) { |
113 | | - return handle.fail({ |
114 | | - errMsg: e.errMsg?.replace('^.*:fail ', ''), |
115 | | - }) |
116 | | - } |
117 | | - }, PRESS_TIME) // 这里的1000表示长按的时间,以毫秒为单位,您可以根据需要调整 |
118 | | - } |
119 | | - |
120 | | - function cancelPress () { |
121 | | - clearTimeout(pressTimer) |
122 | | - } |
123 | | - |
124 | | - // 添加触摸事件监听器 |
125 | | - div.addEventListener('touchstart', startPress) |
126 | | - div.addEventListener('touchend', cancelPress) |
127 | | - div.addEventListener('touchmove', cancelPress) |
128 | | - |
129 | | - item.appendChild(div) |
130 | | - // Note: 等待图片加载完后返回,会导致轮播被卡住 |
131 | | - resolve(item) |
132 | | - if (isFunction(loadFail)) { |
133 | | - image.addEventListener('error', (err) => { |
134 | | - loadFail({ errMsg: err.message }) |
135 | | - }) |
136 | | - } |
| 24 | + return new Promise<TaroGeneral.CallbackResult>((resolve, reject) => { |
| 25 | + nativeImage.previewImage({ |
| 26 | + urls, |
| 27 | + current, |
| 28 | + showmenu, |
| 29 | + success: (res) => { |
| 30 | + handle.success(res, { resolve, reject }) |
| 31 | + }, |
| 32 | + fail: (res) => { |
| 33 | + handle.fail(res, { resolve, reject }) |
| 34 | + }, |
137 | 35 | }) |
138 | | - } |
139 | | - |
140 | | - try { |
141 | | - children = await Promise.all(urls.map((e) => loadImage(e, fail))) |
142 | | - } catch (error) { |
143 | | - return handle.fail({ |
144 | | - errMsg: error, |
145 | | - }) |
146 | | - } |
147 | | - |
148 | | - for (let i = 0; i < children.length; i++) { |
149 | | - const child = children[i] |
150 | | - swiper.appendChild(child) |
151 | | - } |
152 | | - |
153 | | - // 根据微信小程序文档标准(https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.previewImage.html) |
154 | | - // current是一个字符串 |
155 | | - let currentIndex = 0 |
156 | | - if (current && typeof current === 'string') { |
157 | | - const index = urls.indexOf(current) |
158 | | - currentIndex = index > -1 ? index : 0 |
159 | | - } |
160 | | - |
161 | | - swiper.current = currentIndex |
162 | | - |
163 | | - // 创建一个固定定位的容器 |
164 | | - const indexContainer = document.createElement('div') |
165 | | - indexContainer.style.position = 'fixed' |
166 | | - indexContainer.style.top = '35px' |
167 | | - indexContainer.style.left = '50%' |
168 | | - indexContainer.style.transform = 'translateX(-50%)' |
169 | | - indexContainer.style.zIndex = '999' // 确保显示在最上层 |
170 | | - container.appendChild(indexContainer) |
171 | | - |
172 | | - // 创建一个div用来显示索引 |
173 | | - const indexDisplay = document.createElement('div') |
174 | | - indexContainer.style.position = 'fixed' |
175 | | - indexDisplay.id = 'index-display' |
176 | | - indexDisplay.style.backgroundColor = '#111' // 设置背景颜色为黑色 |
177 | | - indexDisplay.style.color = 'white' // 设置文字颜色为白色 |
178 | | - indexContainer.style.transform = 'translateX(-50%)' |
179 | | - indexContainer.style.zIndex = '999' // 确保显示在最上层 |
180 | | - indexDisplay.style.border = '1px solid #111' |
181 | | - indexContainer.appendChild(indexDisplay) |
182 | | - indexDisplay.innerText = `${currentIndex + 1} / ${urls.length}` |
183 | | - |
184 | | - // 监听滑块index并渲染 |
185 | | - swiper.addEventListener('change', (e) => { |
186 | | - // @ts-ignore |
187 | | - const index = e.detail.current |
188 | | - indexDisplay.innerText = `${index + 1} / ${urls.length}` |
189 | 36 | }) |
190 | | - |
191 | | - container.appendChild(swiper) |
192 | | - document.body.appendChild(container) |
193 | | - eventCenter.trigger('__taroEnterFullScreen', {}) |
194 | | - |
195 | | - return handle.success() |
196 | 37 | } |
0 commit comments