util.mjs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import { inBrowser } from "@vant/use";
  2. const hasIntersectionObserver = inBrowser && "IntersectionObserver" in window && "IntersectionObserverEntry" in window && "intersectionRatio" in window.IntersectionObserverEntry.prototype;
  3. const modeType = {
  4. event: "event",
  5. observer: "observer"
  6. };
  7. function remove(arr, item) {
  8. if (!arr.length) return;
  9. const index = arr.indexOf(item);
  10. if (index > -1) return arr.splice(index, 1);
  11. }
  12. function getBestSelectionFromSrcset(el, scale) {
  13. if (el.tagName !== "IMG" || !el.getAttribute("data-srcset")) return;
  14. let options = el.getAttribute("data-srcset");
  15. const container = el.parentNode;
  16. const containerWidth = container.offsetWidth * scale;
  17. let spaceIndex;
  18. let tmpSrc;
  19. let tmpWidth;
  20. options = options.trim().split(",");
  21. const result = options.map((item) => {
  22. item = item.trim();
  23. spaceIndex = item.lastIndexOf(" ");
  24. if (spaceIndex === -1) {
  25. tmpSrc = item;
  26. tmpWidth = 999998;
  27. } else {
  28. tmpSrc = item.substr(0, spaceIndex);
  29. tmpWidth = parseInt(
  30. item.substr(spaceIndex + 1, item.length - spaceIndex - 2),
  31. 10
  32. );
  33. }
  34. return [tmpWidth, tmpSrc];
  35. });
  36. result.sort((a, b) => {
  37. if (a[0] < b[0]) {
  38. return 1;
  39. }
  40. if (a[0] > b[0]) {
  41. return -1;
  42. }
  43. if (a[0] === b[0]) {
  44. if (b[1].indexOf(".webp", b[1].length - 5) !== -1) {
  45. return 1;
  46. }
  47. if (a[1].indexOf(".webp", a[1].length - 5) !== -1) {
  48. return -1;
  49. }
  50. }
  51. return 0;
  52. });
  53. let bestSelectedSrc = "";
  54. let tmpOption;
  55. for (let i = 0; i < result.length; i++) {
  56. tmpOption = result[i];
  57. bestSelectedSrc = tmpOption[1];
  58. const next = result[i + 1];
  59. if (next && next[0] < containerWidth) {
  60. bestSelectedSrc = tmpOption[1];
  61. break;
  62. } else if (!next) {
  63. bestSelectedSrc = tmpOption[1];
  64. break;
  65. }
  66. }
  67. return bestSelectedSrc;
  68. }
  69. const getDPR = (scale = 1) => inBrowser ? window.devicePixelRatio || scale : scale;
  70. function supportWebp() {
  71. if (!inBrowser) return false;
  72. let support = true;
  73. try {
  74. const elem = document.createElement("canvas");
  75. if (elem.getContext && elem.getContext("2d")) {
  76. support = elem.toDataURL("image/webp").indexOf("data:image/webp") === 0;
  77. }
  78. } catch (err) {
  79. support = false;
  80. }
  81. return support;
  82. }
  83. function throttle(action, delay) {
  84. let timeout = null;
  85. let lastRun = 0;
  86. return function(...args) {
  87. if (timeout) {
  88. return;
  89. }
  90. const elapsed = Date.now() - lastRun;
  91. const runCallback = () => {
  92. lastRun = Date.now();
  93. timeout = false;
  94. action.apply(this, args);
  95. };
  96. if (elapsed >= delay) {
  97. runCallback();
  98. } else {
  99. timeout = setTimeout(runCallback, delay);
  100. }
  101. };
  102. }
  103. function on(el, type, func) {
  104. el.addEventListener(type, func, {
  105. capture: false,
  106. passive: true
  107. });
  108. }
  109. function off(el, type, func) {
  110. el.removeEventListener(type, func, false);
  111. }
  112. const loadImageAsync = (item, resolve, reject) => {
  113. const image = new Image();
  114. if (!item || !item.src) {
  115. return reject(new Error("image src is required"));
  116. }
  117. image.src = item.src;
  118. if (item.cors) {
  119. image.crossOrigin = item.cors;
  120. }
  121. image.onload = () => resolve({
  122. naturalHeight: image.naturalHeight,
  123. naturalWidth: image.naturalWidth,
  124. src: image.src
  125. });
  126. image.onerror = (e) => reject(e);
  127. };
  128. class ImageCache {
  129. constructor({ max }) {
  130. this.options = {
  131. max: max || 100
  132. };
  133. this.caches = [];
  134. }
  135. has(key) {
  136. return this.caches.indexOf(key) > -1;
  137. }
  138. add(key) {
  139. if (this.has(key)) return;
  140. this.caches.push(key);
  141. if (this.caches.length > this.options.max) {
  142. this.free();
  143. }
  144. }
  145. free() {
  146. this.caches.shift();
  147. }
  148. }
  149. export {
  150. ImageCache,
  151. getBestSelectionFromSrcset,
  152. getDPR,
  153. hasIntersectionObserver,
  154. loadImageAsync,
  155. modeType,
  156. off,
  157. on,
  158. remove,
  159. supportWebp,
  160. throttle
  161. };