@conecli/cone-render 0.10.1-shop3.89 → 0.10.1-shop3.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import React, { useCallback, useEffect, useRef, useState } from 'react'
2
1
  getQualityImage,
3
2
  isH5AndJdShopView,
4
3
  isChartH5,
5
4
  isH5AndJdShopViewH5Scroll,
6
5
  isAppStowShop,
7
6
  getSgmCustomCode,
8
7
  isImageOptimizeEnable,
9
8
  getAvifSupport,
10
9
  getWebpSupport,
11
10
  draBusinessCustomReport
12
11
  getNativePageScrollRes,
13
12
  latestFromNativeMsgStorage,
14
13
  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAANQTFRFAAAAp3o92gAAAAF0Uk5TAEDm2GYAAAAKSURBVHicY2QAAAAEAAIhZK1qAAAAAElFTkSuQmCC'
15
14
  'https://img14.360buyimg.com/imagetools/jfs/t1/222907/25/7012/5824/61c4797cEbcd17c7f/6c76fc71e4fdb5a5.png'
16
15
  const styleSheets = document.styleSheets
17
16
  const internalStyleSheets = []
18
17
  for (let i = 0; i < styleSheets.length; i++) {
19
18
  const sheet = styleSheets[i]
20
19
  const ownerNode = sheet.ownerNode
21
20
  if (ownerNode && ownerNode.nodeName === 'STYLE') {
22
21
  internalStyleSheets.push(sheet)
23
22
  }
24
23
  }
25
24
  console.warn(
26
25
  '🚗 ~~ file: index.h5.tsx:47 ~~ getRuleBySelector() ~~ selector:',
27
26
  selector,
28
27
  )
29
28
  for (let i = 0; i < internalStyleSheets.length; i++) {
30
29
  try {
31
30
  const sheet = internalStyleSheets[i]
32
31
  const rules = sheet.cssRules || sheet.rules
33
32
  for (const rule of rules) {
34
33
  if (rule?.selectorText?.match(new RegExp(selector + '$'))) {
35
34
  return rule
36
35
  }
37
36
  }
38
37
  } catch (e) {
39
38
  console.warn('因安全限制无法访问样式表:', e)
40
39
  }
41
40
  }
42
41
  return null
43
42
  const {
44
43
  src = null,
45
44
  lazyLoad = true,
46
45
  imagRenderingSet = true,
47
46
  width = null,
48
47
  height = null,
49
48
  className = null,
50
49
  isSkuImage = false,
51
50
  hideErrorImage = false,
52
51
  style = null,
53
52
  backgroundColor = null,
54
53
  errorSrc = null,
55
54
  onLoad = null,
56
55
  onError = null,
57
56
  sizeScale = 1,
58
57
  ...otherOption
59
58
  } = props
60
59
  getNetWorkType === NetWorkTypeQuality.default &&
61
60
  (getNetWorkType = global.info.sysInfo.netWorkType)
62
61
  const [loadSuccess, setLoadSuccess] = useState(false)
63
62
  const [imageErrState, setImageErrState] = useState(false)
64
63
  const [componentShowState, setComponentShowState] = useState(false)
65
64
  const measureRef = useRef<HTMLElement | null>(null)
66
65
  const [measureComplete, setMeasureComplete] = useState(false)
67
66
  const [imgSrc, setImgSrc] = useState(src)
68
67
  const [hasRetrySuccess, setHasRetrySuccess] = useState(false)
69
68
  const hasRetryRef = useRef(false)
70
69
  const componentShowStateRef = useRef(false)
71
70
  const requestSrcRef = useRef(src)
72
71
  const needShowHighVersion =
73
72
  isH5AndJdShopViewH5Scroll &&
74
73
  !(
75
74
  global.info.queryInfo?.downgraded &&
76
75
  global.info.queryInfo.downgraded === 'true'
77
76
  )
78
77
  const enableAvifOptimize = isImageOptimizeEnable()
79
78
  const isVipShop = global?.info?.pageInfo?.isVipShop
80
79
  const avifSupport = getAvifSupport()
81
80
  const webpSupport = getWebpSupport()
82
81
 
83
82
  const getRequestSrc = useCallback(
84
83
  (src) => {
85
84
  const requestSrc = getQualityImage(imgSrc, {
86
85
  isSkuImage,
87
86
  size: measureRef?.current?.getBoundingClientRect()?.width,
88
87
  sizeScale
89
88
  })
90
89
  requestSrcRef.current = requestSrc
91
90
  return requestSrc
92
91
  },
93
92
  [src],
94
93
  )
95
94
 
96
95
  const imageErrorRetry = (src) => {
97
96
  return new Promise((resolve, reject) => {
98
97
  if (fetch && window && window.Image) {
99
98
  fetch(src)
100
99
  .then((response) => {
101
100
  const { ok, status } = response
102
101
  if (ok) {
103
102
  const originUrl = src.replace(/\.(jpe?g|png).*/, '.$1')
104
103
  response
105
104
  .blob()
106
105
  .then((blob) => {
107
106
  if (URL) {
108
107
  const url = URL.createObjectURL(blob)
109
108
  const img = new window.Image()
110
109
  img.src = url
111
110
  img.onload = () => {
112
111
  reportSGM({
113
112
  status,
114
113
  text: '再次请求并且onload了',
115
114
  type: 'retryAndOnload',
116
115
  requestSrc: src,
117
116
  resolveUrl: url,
118
117
  })
119
118
  resolve({
120
119
  ok: true,
121
120
  url,
122
121
  })
123
122
  setTimeout(() => {
124
123
  URL.revokeObjectURL(url)
125
124
  }, 2000)
126
125
  }
127
126
  img.onerror = () => {
128
127
  reportSGM({
129
128
  status,
130
129
  text: '图片解析异常',
131
130
  type: 'imageParseError',
132
131
  requestSrc: src,
133
132
  })
134
133
  URL.revokeObjectURL(url)
135
134
  resolve({
136
135
  ok: true,
137
136
  url: originUrl,
138
137
  })
139
138
  }
140
139
  } else {
141
140
  resolve({
142
141
  ok: true,
143
142
  url: originUrl,
144
143
  })
145
144
  }
146
145
  })
147
146
  .catch((error) => {
148
147
  resolve({
149
148
  ok: true,
150
149
  url: originUrl,
151
150
  })
152
151
  console.error('LazyLoadImage imageErrorRetry() error:', error)
153
152
  })
154
153
  } else {
155
154
  if (status === 404) {
156
155
  resolve({
157
156
  ok: false,
158
157
  text: '访问图片不存在',
159
158
  type: 'noSuchUrlImage',
160
159
  })
161
160
  } else {
162
161
  resolve({
163
162
  ok: false,
164
163
  status: status,
165
164
  text: '其它图片问题',
166
165
  type: 'otherImageError',
167
166
  })
168
167
  }
169
168
  }
170
169
  })
171
170
  .catch((error) => {
172
171
  resolve({
173
172
  ok: false,
174
173
  text: '网络异常',
175
174
  type: 'networkError',
176
175
  })
177
176
  console.error('LazyLoadImage imageErrorRetry() error:', error)
178
177
  })
179
178
  } else {
180
179
  resolve({
181
180
  ok: false,
182
181
  text: '不支持重试',
183
182
  type: 'notSupportRetry',
184
183
  })
185
184
  }
186
185
  })
187
186
  }
188
187
 
189
188
  const reportSGM = ({
190
189
  status,
191
190
  text,
192
191
  type,
193
192
  requestSrc = imgSrc,
194
193
  resolveUrl = '',
195
194
  }) => {
196
195
  const { shopId, venderId } = global.info.queryInfo || {}
197
196
  draBusinessCustomReport({
198
197
  eventName: 'business',
199
198
  errorName: getSgmCustomCode(`${SgmCustomCode.IMAGE_LOAD}_${type}`),
200
199
  errorMessage: '图片加载失败异常',
201
200
  extraData: JSON.stringify({
202
201
  avifSupport,
203
202
  webpSupport,
204
203
  shopId,
205
204
  venderId,
206
205
  originSrc: src,
207
206
  requestSrc,
208
207
  resolveUrl,
209
208
  status,
210
209
  text,
211
210
  }),
212
211
  })
213
212
  }
214
213
  const imageErrorHandle = useCallback(
215
214
  (e) => {
216
215
  console.log(' ==============> 图片加载错误', e)
217
216
  if (!hasRetryRef.current) {
218
217
  hasRetryRef.current = true
219
218
  if (src) {
220
219
  try {
221
220
  imageErrorRetry(requestSrcRef.current).then((result) => {
222
221
  const { status, ok, text, type, url } = result || {}
223
222
  if (ok) {
224
223
  setImgSrc(url)
225
224
  setHasRetrySuccess(true)
226
225
  } else {
227
226
  errorSrc && setImgSrc(errorSrc)
228
227
  hideErrorImage && setImageErrState(true)
229
228
  typeof onError === 'function' && onError(e, src, props)
230
229
  reportSGM({
231
230
  status,
232
231
  text,
233
232
  type,
234
233
  requestSrc: requestSrcRef.current,
235
234
  })
236
235
  }
237
236
  })
238
237
  } catch (e) {
239
238
  console.error('LazyLoadImage imageErrorHandle() error:', e)
240
239
  errorSrc && setImgSrc(errorSrc)
241
240
  hideErrorImage && setImageErrState(true)
242
241
  typeof onError === 'function' && onError(e, src, props)
243
242
  }
244
243
  }
245
244
  } else {
246
245
  reportSGM({
247
246
  status: '',
248
247
  text: '渲染原始图片渲染异常',
249
248
  type: 'renderOriginImageError',
250
249
  })
251
250
  if (imgSrc.includes('blob:')) {
252
251
  reportSGM({
253
252
  status: '',
254
253
  text: '渲染本地blob图片异常',
255
254
  type: 'renderBlobImageError',
256
255
  })
257
256
  } else {
258
257
  reportSGM({
259
258
  status: '',
260
259
  text: '渲染本地非blob图片异常',
261
260
  type: 'renderNoBlobImageError',
262
261
  })
263
262
  }
264
263
  }
265
264
  },
266
265
  [src, hasRetryRef.current],
267
266
  )
268
267
 
269
268
  const imageLoad = useCallback(
270
269
  (_src, event) => {
271
270
  setLoadSuccess(true)
272
271
  typeof onLoad === 'function' && onLoad(event, src, props)
273
272
  },
274
273
  [src],
275
274
  )
276
275
 
277
276
  const changeStyleIncludeWidthAndHeightAndBgColor = () => {
278
277
  const changeStyle = {}
279
278
  width && (changeStyle['width'] = width)
280
279
  height && (changeStyle['height'] = height)
281
280
  backgroundColor && (changeStyle['backgroundColor'] = backgroundColor)
282
281
  return changeStyle
283
282
  }
284
283
  useEffect(() => {
285
284
  try {
286
285
  const { mode } = otherOption
287
286
  if (mode && mode === 'heightFix') {
288
287
  className?.split(/\s/)?.forEach((item) => {
289
288
  const userDefinedClass = getRuleBySelector('.' + item)
290
289
  const userDefinedHeight = userDefinedClass?.style?.height
291
290
  if (userDefinedHeight === '' || userDefinedHeight === 'auto') {
292
291
  console.warn(
293
292
  "🚗 ~~ 发现一例用户使用图片组件设置了 mode='heightFix' 并且没有定义一个具体高度:",
294
293
  userDefinedHeight,
295
294
  {
296
295
  code: getSgmCustomCode(`imageUsageCheck`),
297
296
  msg: {
298
297
  userDefinedClass: item,
299
298
  userDefinedHeight,
300
299
  },
301
300
  },
302
301
  )
303
302
  draBusinessCustomReport({
304
303
  eventName: 'business',
305
304
  errorName: getSgmCustomCode(`imageUsageCheck`),
306
305
  errorMessage: JSON.stringify({
307
306
  userDefinedClass: item,
308
307
  userDefinedHeight,
309
308
  }),
310
309
  })
311
310
  }
312
311
  })
313
312
  }
314
313
  } catch (e) {
315
314
  console.warn('imageUsageCheck error:', e)
316
315
  }
317
316
  setMeasureComplete(true)
318
317
  if (needShowHighVersion) return
319
318
  const latestRes =
320
319
  latestFromNativeMsgStorage[TaroEventType.PAGE_SCROLL] || {}
321
320
  !componentShowStateRef.current && dealPageScrollInfo(latestRes)
322
321
  Taro.eventCenter.on(TaroEventType.PAGE_SCROLL, (res) => {
323
322
  !componentShowStateRef.current && dealPageScrollInfo(res)
324
323
  })
325
324
  }, [])
326
325
 
327
326
  const dealPageScrollInfo = (res) => {
328
327
  const { displayHeight, offSetY } = getNativePageScrollRes(res) || {}
329
328
  if (typeof displayHeight === 'undefined' || typeof offSetY === 'undefined')
330
329
  return
331
330
  if (measureRef.current) {
332
331
  const eleClientRect = measureRef.current.getBoundingClientRect()
333
332
  const getContainerHeightOffSetY = displayHeight * 1.5 + offSetY
334
333
  const eleOffsetTop = Math.ceil(eleClientRect.top)
335
334
  const eleOffsetHeight = Math.ceil(eleClientRect.height)
336
335
  if (!componentShowStateRef.current) {
337
336
  if (getContainerHeightOffSetY > eleOffsetTop) {
338
337
  componentShowStateRef.current = true
339
338
  setComponentShowState(true)
340
339
  }
341
340
  }
342
341
  }
343
342
  }
344
343
  return isH5AndJdShopView &&
345
344
  global?.config?.needImageLazy !== false &&
346
345
  !needShowHighVersion &&
347
346
  !isAppStowShop ? (
348
347
  <View
349
348
  ref={measureRef}
350
349
  className={classNames(
351
350
  imageStyle['d-app-lazy-image'],
352
351
  {
353
352
  [imageStyle['d-lazy-sku-image']]: isSkuImage,
354
353
  },
355
354
  {
356
355
  [imageStyle['d-hide-image-error']]: imageErrState,
357
356
  },
358
357
  {
359
358
  [imageStyle['d-load-completed']]: loadSuccess,
360
359
  },
361
360
  {
362
361
  'd-imag-rendering-crisp-edges':
363
362
  !isVipShop && imagRenderingSet,
364
363
  },
365
364
  'J_html5ImageBg',
366
365
  className,
367
366
  )}
368
367
  style={{
369
368
  ...style,
370
369
  ...changeStyleIncludeWidthAndHeightAndBgColor(),
371
370
  }}
372
371
  {...otherOption}
373
372
  >
374
373
  {(componentShowState || lazyLoad === false) && (
375
374
  <img
376
375
  src={getQualityImage(
377
376
  imgSrc,
378
377
  isVipShop
379
378
  ? NetWorkTypeQuality['perfect']
380
379
  : NetWorkTypeQuality[getNetWorkType],
381
380
  )}
382
381
  onLoad={imageLoad.bind(this, imgSrc)}
383
382
  onError={imageErrorHandle}
384
383
  />
385
384
  )}
386
385
  </View>
387
386
  ) : enableAvifOptimize ? (
388
387
  [
389
388
  measureComplete ? (
390
389
  <Image
391
390
  key={hasRetrySuccess ? 'realImageRetry' : 'realImage'}
392
391
  style={{
393
392
  ...style,
394
393
  ...changeStyleIncludeWidthAndHeightAndBgColor(),
395
394
  }}
396
395
  className={classNames(
397
396
  imageStyle['d-lazy-image'],
398
397
  {
399
398
  [imageStyle['d-lazy-sku-image']]: isSkuImage,
400
399
  },
401
400
  {
402
401
  [imageStyle['d-hide-image-error']]: imageErrState,
403
402
  },
404
403
  {
405
404
  [imageStyle['d-load-completed']]: loadSuccess,
406
405
  },
407
406
  {
408
407
  'd-imag-rendering-crisp-edges': imagRenderingSet,
409
408
  },
410
409
  {
411
410
  [imageStyle["d-no-jd-dog"]]: isVipShop && !isSkuImage,
412
411
  },
413
412
  className,
414
413
  )}
415
414
  src={hasRetrySuccess ? imgSrc : getRequestSrc(imgSrc)}
416
415
  lazyLoad={isChartH5 ? false : lazyLoad}
417
416
  onError={imageErrorHandle}
418
417
  onLoad={imageLoad.bind(this, imgSrc)}
419
418
  {...otherOption}
420
419
  />
421
420
  ) : (
422
421
  <Image
423
422
  key="defaultImage"
424
423
  style={{
425
424
  ...style,
426
425
  ...changeStyleIncludeWidthAndHeightAndBgColor(),
427
426
  }}
428
427
  className={classNames(
429
428
  imageStyle['d-lazy-image'],
430
429
  {
431
430
  [imageStyle['d-lazy-sku-image']]: isSkuImage,
432
431
  },
433
432
  {
434
433
  [imageStyle['d-hide-image-error']]: imageErrState,
435
434
  },
436
435
  {
437
436
  [imageStyle['d-load-completed']]: loadSuccess,
438
437
  },
439
438
  {
440
439
  'd-imag-rendering-crisp-edges': imagRenderingSet,
441
440
  },
442
441
  {
443
442
  [imageStyle["d-no-jd-dog"]]: isVipShop && !isSkuImage,
444
443
  },
445
444
  className,
446
445
  )}
447
446
  src={isSkuImage ? DEFAULT_SKU_SRC : DEFAULT_SRC}
448
447
  />
449
448
  ),
450
449
  loadSuccess ? null : <View key="measureRef" ref={measureRef}></View>,
451
450
  ]
452
451
  ) : (
453
452
  <Image
454
453
  style={{
455
454
  ...style,
456
455
  ...changeStyleIncludeWidthAndHeightAndBgColor(),
457
456
  }}
458
457
  className={classNames(
459
458
  imageStyle['d-lazy-image'],
460
459
  {
461
460
  [imageStyle['d-lazy-sku-image']]: isSkuImage,
462
461
  },
463
462
  {
464
463
  [imageStyle['d-hide-image-error']]: imageErrState,
465
464
  },
466
465
  {
467
466
  [imageStyle['d-load-completed']]: loadSuccess,
468
467
  },
469
468
  {
470
469
  'd-imag-rendering-crisp-edges': imagRenderingSet,
471
470
  },
472
471
  className,
473
472
  )}
474
473
  src={getQualityImage(imgSrc, NetWorkTypeQuality[getNetWorkType])}
475
474
  lazyLoad={isChartH5 ? false : lazyLoad}
476
475
  onError={imageErrorHandle}
477
476
  onLoad={imageLoad.bind(this, imgSrc)}
478
477
  {...otherOption}
479
478
  />
480
479
  )
480
+ import React, { useCallback, useEffect, useRef, useState } from 'react'
481
481
  getQualityImage,
482
482
  isH5AndJdShopView,
483
483
  isChartH5,
484
484
  isH5AndJdShopViewH5Scroll,
485
485
  isAppStowShop,
486
486
  getSgmCustomCode,
487
487
  isImageOptimizeEnable,
488
488
  getAvifSupport,
489
489
  getWebpSupport,
490
490
  draBusinessCustomReport
491
491
  getNativePageScrollRes,
492
492
  latestFromNativeMsgStorage,
493
493
  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAANQTFRFAAAAp3o92gAAAAF0Uk5TAEDm2GYAAAAKSURBVHicY2QAAAAEAAIhZK1qAAAAAElFTkSuQmCC'
494
494
  'https://img14.360buyimg.com/imagetools/jfs/t1/222907/25/7012/5824/61c4797cEbcd17c7f/6c76fc71e4fdb5a5.png'
495
495
  const styleSheets = document.styleSheets
496
496
  const internalStyleSheets = []
497
497
  for (let i = 0; i < styleSheets.length; i++) {
498
498
  const sheet = styleSheets[i]
499
499
  const ownerNode = sheet.ownerNode
500
500
  if (ownerNode && ownerNode.nodeName === 'STYLE') {
501
501
  internalStyleSheets.push(sheet)
502
502
  }
503
503
  }
504
504
  console.warn(
505
505
  '🚗 ~~ file: index.h5.tsx:47 ~~ getRuleBySelector() ~~ selector:',
506
506
  selector,
507
507
  )
508
508
  for (let i = 0; i < internalStyleSheets.length; i++) {
509
509
  try {
510
510
  const sheet = internalStyleSheets[i]
511
511
  const rules = sheet.cssRules || sheet.rules
512
512
  for (const rule of rules) {
513
513
  if (rule?.selectorText?.match(new RegExp(selector + '$'))) {
514
514
  return rule
515
515
  }
516
516
  }
517
517
  } catch (e) {
518
518
  console.warn('因安全限制无法访问样式表:', e)
519
519
  }
520
520
  }
521
521
  return null
522
522
  const {
523
523
  src = null,
524
524
  lazyLoad = true,
525
525
  imagRenderingSet = true,
526
526
  width = null,
527
527
  height = null,
528
528
  className = null,
529
529
  isSkuImage = false,
530
530
  hideErrorImage = false,
531
531
  style = null,
532
532
  backgroundColor = null,
533
533
  errorSrc = null,
534
534
  onLoad = null,
535
535
  onError = null,
536
536
  sizeScale = 1,
537
537
  ...otherOption
538
538
  } = props
539
539
  getNetWorkType === NetWorkTypeQuality.default &&
540
540
  (getNetWorkType = global.info.sysInfo.netWorkType)
541
541
  const [loadSuccess, setLoadSuccess] = useState(false)
542
542
  const [imageErrState, setImageErrState] = useState(false)
543
543
  const [componentShowState, setComponentShowState] = useState(false)
544
544
  const measureRef = useRef<HTMLElement | null>(null)
545
545
  const [measureComplete, setMeasureComplete] = useState(false)
546
546
  const [imgSrc, setImgSrc] = useState(src)
547
547
  const [hasRetrySuccess, setHasRetrySuccess] = useState(false)
548
548
  const hasRetryRef = useRef(false)
549
549
  const componentShowStateRef = useRef(false)
550
550
  const requestSrcRef = useRef(src)
551
551
  const needShowHighVersion =
552
552
  isH5AndJdShopViewH5Scroll &&
553
553
  !(
554
554
  global.info.queryInfo?.downgraded &&
555
555
  global.info.queryInfo.downgraded === 'true'
556
556
  )
557
557
  const enableAvifOptimize = isImageOptimizeEnable()
558
558
  const isVipShop = global?.info?.pageInfo?.isVipShop
559
559
  const avifSupport = getAvifSupport()
560
560
  const webpSupport = getWebpSupport()
561
561
 
562
562
  const getRequestSrc = useCallback(
563
563
  (src) => {
564
564
  const requestSrc = getQualityImage(imgSrc, {
565
565
  isSkuImage,
566
566
  size: measureRef?.current?.getBoundingClientRect()?.width,
567
567
  sizeScale
568
568
  })
569
569
  requestSrcRef.current = requestSrc
570
570
  return requestSrc
571
571
  },
572
572
  [src],
573
573
  )
574
574
 
575
575
  const imageErrorRetry = (src) => {
576
576
  return new Promise((resolve, reject) => {
577
577
  if (fetch && window && window.Image) {
578
578
  fetch(src)
579
579
  .then((response) => {
580
580
  const { ok, status } = response
581
581
  if (ok) {
582
582
  const originUrl = src.replace(/\.(jpe?g|png).*/, '.$1')
583
583
  response
584
584
  .blob()
585
585
  .then((blob) => {
586
586
  if (URL) {
587
587
  const url = URL.createObjectURL(blob)
588
588
  const img = new window.Image()
589
589
  img.src = url
590
590
  img.onload = () => {
591
591
  reportSGM({
592
592
  status,
593
593
  text: '再次请求并且onload了',
594
594
  type: 'retryAndOnload',
595
595
  requestSrc: src,
596
596
  resolveUrl: url,
597
597
  })
598
598
  resolve({
599
599
  ok: true,
600
600
  url,
601
601
  })
602
602
  setTimeout(() => {
603
603
  URL.revokeObjectURL(url)
604
604
  }, 2000)
605
605
  }
606
606
  img.onerror = () => {
607
607
  reportSGM({
608
608
  status,
609
609
  text: '图片解析异常',
610
610
  type: 'imageParseError',
611
611
  requestSrc: src,
612
612
  })
613
613
  URL.revokeObjectURL(url)
614
614
  resolve({
615
615
  ok: true,
616
616
  url: originUrl,
617
617
  })
618
618
  }
619
619
  } else {
620
620
  resolve({
621
621
  ok: true,
622
622
  url: originUrl,
623
623
  })
624
624
  }
625
625
  })
626
626
  .catch((error) => {
627
627
  resolve({
628
628
  ok: true,
629
629
  url: originUrl,
630
630
  })
631
631
  console.error('LazyLoadImage imageErrorRetry() error:', error)
632
632
  })
633
633
  } else {
634
634
  if (status === 404) {
635
635
  resolve({
636
636
  ok: false,
637
637
  text: '访问图片不存在',
638
638
  type: 'noSuchUrlImage',
639
639
  })
640
640
  } else {
641
641
  resolve({
642
642
  ok: false,
643
643
  status: status,
644
644
  text: '其它图片问题',
645
645
  type: 'otherImageError',
646
646
  })
647
647
  }
648
648
  }
649
649
  })
650
650
  .catch((error) => {
651
651
  resolve({
652
652
  ok: false,
653
653
  text: '网络异常',
654
654
  type: 'networkError',
655
655
  })
656
656
  console.error('LazyLoadImage imageErrorRetry() error:', error)
657
657
  })
658
658
  } else {
659
659
  resolve({
660
660
  ok: false,
661
661
  text: '不支持重试',
662
662
  type: 'notSupportRetry',
663
663
  })
664
664
  }
665
665
  })
666
666
  }
667
667
 
668
668
  const reportSGM = ({
669
669
  status,
670
670
  text,
671
671
  type,
672
672
  requestSrc = imgSrc,
673
673
  resolveUrl = '',
674
674
  }) => {
675
675
  const { shopId, venderId } = global.info.queryInfo || {}
676
676
  draBusinessCustomReport({
677
677
  eventName: 'business',
678
678
  errorName: getSgmCustomCode(`${SgmCustomCode.IMAGE_LOAD}_${type}`),
679
679
  errorMessage: '图片加载失败异常',
680
680
  extraData: JSON.stringify({
681
681
  avifSupport,
682
682
  webpSupport,
683
683
  shopId,
684
684
  venderId,
685
685
  originSrc: src,
686
686
  requestSrc,
687
687
  resolveUrl,
688
688
  status,
689
689
  text,
690
690
  }),
691
691
  })
692
692
  }
693
693
  const imageErrorHandle = useCallback(
694
694
  (e) => {
695
695
  console.log(' ==============> 图片加载错误', e)
696
696
  if (!hasRetryRef.current) {
697
697
  hasRetryRef.current = true
698
698
  if (src) {
699
699
  try {
700
700
  imageErrorRetry(requestSrcRef.current).then((result) => {
701
701
  const { status, ok, text, type, url } = result || {}
702
702
  if (ok) {
703
703
  setImgSrc(url)
704
704
  setHasRetrySuccess(true)
705
705
  } else {
706
706
  errorSrc && setImgSrc(errorSrc)
707
707
  hideErrorImage && setImageErrState(true)
708
708
  typeof onError === 'function' && onError(e, src, props)
709
709
  reportSGM({
710
710
  status,
711
711
  text,
712
712
  type,
713
713
  requestSrc: requestSrcRef.current,
714
714
  })
715
715
  }
716
716
  })
717
717
  } catch (e) {
718
718
  console.error('LazyLoadImage imageErrorHandle() error:', e)
719
719
  errorSrc && setImgSrc(errorSrc)
720
720
  hideErrorImage && setImageErrState(true)
721
721
  typeof onError === 'function' && onError(e, src, props)
722
722
  }
723
723
  }
724
724
  } else {
725
725
  reportSGM({
726
726
  status: '',
727
727
  text: '渲染原始图片渲染异常',
728
728
  type: 'renderOriginImageError',
729
729
  })
730
730
  if (imgSrc.includes('blob:')) {
731
731
  reportSGM({
732
732
  status: '',
733
733
  text: '渲染本地blob图片异常',
734
734
  type: 'renderBlobImageError',
735
735
  })
736
736
  } else {
737
737
  reportSGM({
738
738
  status: '',
739
739
  text: '渲染本地非blob图片异常',
740
740
  type: 'renderNoBlobImageError',
741
741
  })
742
742
  }
743
743
  }
744
744
  },
745
745
  [src, hasRetryRef.current],
746
746
  )
747
747
 
748
748
  const imageLoad = useCallback(
749
749
  (_src, event) => {
750
750
  setLoadSuccess(true)
751
751
  typeof onLoad === 'function' && onLoad(event, src, props)
752
752
  },
753
753
  [src],
754
754
  )
755
755
 
756
756
  const changeStyleIncludeWidthAndHeightAndBgColor = () => {
757
757
  const changeStyle = {}
758
758
  width && (changeStyle['width'] = width)
759
759
  height && (changeStyle['height'] = height)
760
760
  backgroundColor && (changeStyle['backgroundColor'] = backgroundColor)
761
761
  return changeStyle
762
762
  }
763
763
  useEffect(() => {
764
764
  try {
765
765
  const { mode } = otherOption
766
766
  if (mode && mode === 'heightFix') {
767
767
  className?.split(/\s/)?.forEach((item) => {
768
768
  const userDefinedClass = getRuleBySelector('.' + item)
769
769
  const userDefinedHeight = userDefinedClass?.style?.height
770
770
  if (userDefinedHeight === '' || userDefinedHeight === 'auto') {
771
771
  console.warn(
772
772
  "🚗 ~~ 发现一例用户使用图片组件设置了 mode='heightFix' 并且没有定义一个具体高度:",
773
773
  userDefinedHeight,
774
774
  {
775
775
  code: getSgmCustomCode(`imageUsageCheck`),
776
776
  msg: {
777
777
  userDefinedClass: item,
778
778
  userDefinedHeight,
779
779
  },
780
780
  },
781
781
  )
782
782
  draBusinessCustomReport({
783
783
  eventName: 'business',
784
784
  errorName: getSgmCustomCode(`imageUsageCheck`),
785
785
  errorMessage: JSON.stringify({
786
786
  userDefinedClass: item,
787
787
  userDefinedHeight,
788
788
  }),
789
789
  })
790
790
  }
791
791
  })
792
792
  }
793
793
  } catch (e) {
794
794
  console.warn('imageUsageCheck error:', e)
795
795
  }
796
796
  setMeasureComplete(true)
797
797
  if (needShowHighVersion) return
798
798
  const latestRes =
799
799
  latestFromNativeMsgStorage[TaroEventType.PAGE_SCROLL] || {}
800
800
  !componentShowStateRef.current && dealPageScrollInfo(latestRes)
801
801
  Taro.eventCenter.on(TaroEventType.PAGE_SCROLL, (res) => {
802
802
  !componentShowStateRef.current && dealPageScrollInfo(res)
803
803
  })
804
804
  }, [])
805
805
 
806
806
  const dealPageScrollInfo = (res) => {
807
807
  const { displayHeight, offSetY } = getNativePageScrollRes(res) || {}
808
808
  if (typeof displayHeight === 'undefined' || typeof offSetY === 'undefined')
809
809
  return
810
810
  if (measureRef.current) {
811
811
  const eleClientRect = measureRef.current.getBoundingClientRect()
812
812
  const getContainerHeightOffSetY = displayHeight * 1.5 + offSetY
813
813
  const eleOffsetTop = Math.ceil(eleClientRect.top)
814
814
  const eleOffsetHeight = Math.ceil(eleClientRect.height)
815
815
  if (!componentShowStateRef.current) {
816
816
  if (getContainerHeightOffSetY > eleOffsetTop) {
817
817
  componentShowStateRef.current = true
818
818
  setComponentShowState(true)
819
819
  }
820
820
  }
821
821
  }
822
822
  }
823
823
  return isH5AndJdShopView &&
824
824
  global?.config?.needImageLazy !== false &&
825
825
  !needShowHighVersion &&
826
826
  !isAppStowShop ? (
827
827
  <View
828
828
  ref={measureRef}
829
829
  className={classNames(
830
830
  imageStyle['d-app-lazy-image'],
831
831
  {
832
832
  [imageStyle['d-lazy-sku-image']]: isSkuImage,
833
833
  },
834
834
  {
835
835
  [imageStyle['d-hide-image-error']]: imageErrState,
836
836
  },
837
837
  {
838
838
  [imageStyle['d-load-completed']]: loadSuccess,
839
839
  },
840
840
  {
841
841
  'd-imag-rendering-crisp-edges':
842
842
  !isVipShop && imagRenderingSet,
843
843
  },
844
844
  'J_html5ImageBg',
845
845
  className,
846
846
  )}
847
847
  style={{
848
848
  ...style,
849
849
  ...changeStyleIncludeWidthAndHeightAndBgColor(),
850
850
  }}
851
851
  {...otherOption}
852
852
  >
853
853
  {(componentShowState || lazyLoad === false) && (
854
854
  <img
855
855
  src={getQualityImage(
856
856
  imgSrc,
857
857
  isVipShop
858
858
  ? NetWorkTypeQuality['perfect']
859
859
  : NetWorkTypeQuality[getNetWorkType],
860
860
  )}
861
861
  onLoad={imageLoad.bind(this, imgSrc)}
862
862
  onError={imageErrorHandle}
863
863
  />
864
864
  )}
865
865
  </View>
866
866
  ) : enableAvifOptimize ? (
867
867
  [
868
868
  measureComplete ? (
869
869
  <Image
870
870
  key={hasRetrySuccess ? 'realImageRetry' : 'realImage'}
871
871
  style={{
872
872
  ...style,
873
873
  ...changeStyleIncludeWidthAndHeightAndBgColor(),
874
874
  }}
875
875
  className={classNames(
876
876
  imageStyle['d-lazy-image'],
877
877
  {
878
878
  [imageStyle['d-lazy-sku-image']]: isSkuImage,
879
879
  },
880
880
  {
881
881
  [imageStyle['d-hide-image-error']]: imageErrState,
882
882
  },
883
883
  {
884
884
  [imageStyle['d-load-completed']]: loadSuccess,
885
885
  },
886
886
  {
887
887
  'd-imag-rendering-crisp-edges': imagRenderingSet,
888
888
  },
889
889
  {
890
890
  [imageStyle["d-no-jd-dog"]]: isVipShop && !isSkuImage,
891
891
  },
892
892
  className,
893
893
  )}
894
894
  src={hasRetrySuccess ? imgSrc : getRequestSrc(imgSrc)}
895
895
  lazyLoad={isChartH5 ? false : lazyLoad}
896
896
  onError={imageErrorHandle}
897
897
  onLoad={imageLoad.bind(this, imgSrc)}
898
898
  {...otherOption}
899
899
  />
900
900
  ) : (
901
901
  <Image
902
902
  key="defaultImage"
903
903
  style={{
904
904
  ...style,
905
905
  ...changeStyleIncludeWidthAndHeightAndBgColor(),
906
906
  }}
907
907
  className={classNames(
908
908
  imageStyle['d-lazy-image'],
909
909
  {
910
910
  [imageStyle['d-lazy-sku-image']]: isSkuImage,
911
911
  },
912
912
  {
913
913
  [imageStyle['d-hide-image-error']]: imageErrState,
914
914
  },
915
915
  {
916
916
  [imageStyle['d-load-completed']]: loadSuccess,
917
917
  },
918
918
  {
919
919
  'd-imag-rendering-crisp-edges': imagRenderingSet,
920
920
  },
921
921
  {
922
922
  [imageStyle["d-no-jd-dog"]]: isVipShop && !isSkuImage,
923
923
  },
924
924
  className,
925
925
  )}
926
926
  src={isSkuImage ? DEFAULT_SKU_SRC : DEFAULT_SRC}
927
927
  />
928
928
  ),
929
929
  loadSuccess ? null : <View key="measureRef" ref={measureRef}></View>,
930
930
  ]
931
931
  ) : (
932
932
  <Image
933
933
  style={{
934
934
  ...style,
935
935
  ...changeStyleIncludeWidthAndHeightAndBgColor(),
936
936
  }}
937
937
  className={classNames(
938
938
  imageStyle['d-lazy-image'],
939
939
  {
940
940
  [imageStyle['d-lazy-sku-image']]: isSkuImage,
941
941
  },
942
942
  {
943
943
  [imageStyle['d-hide-image-error']]: imageErrState,
944
944
  },
945
945
  {
946
946
  [imageStyle['d-load-completed']]: loadSuccess,
947
947
  },
948
948
  {
949
949
  'd-imag-rendering-crisp-edges': imagRenderingSet,
950
950
  },
951
951
  className,
952
952
  )}
953
953
  src={getQualityImage(imgSrc, NetWorkTypeQuality[getNetWorkType])}
954
954
  lazyLoad={isChartH5 ? false : lazyLoad}
955
955
  onError={imageErrorHandle}
956
956
  onLoad={imageLoad.bind(this, imgSrc)}
957
957
  {...otherOption}
958
958
  />
959
959
  )