util.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. export function isValidUrl(url) {
  2. return isOnlineUrl(url) || isDataUrl(url);
  3. }
  4. export function isOnlineUrl(url) {
  5. return /(ht|f)tp(s?):\/\/([^ \\/]*\.)+[^ \\/]*(:[0-9]+)?\/?/.test(url);
  6. }
  7. export function isDataUrl(url) {
  8. return /data:image\/(\w+);base64,(.*)/.test(url);
  9. }
  10. /**
  11. * 深度对比两个对象是否一致
  12. * from: https://github.com/epoberezkin/fast-deep-equal
  13. * @param {Object} a 对象a
  14. * @param {Object} b 对象b
  15. * @return {Boolean} 是否相同
  16. */
  17. /* eslint-disable */
  18. export function equal(a, b) {
  19. if (a === b) {
  20. return true;
  21. }
  22. if (a && b && typeof a == 'object' && typeof b == 'object') {
  23. var arrA = Array.isArray(a);
  24. var arrB = Array.isArray(b);
  25. var i;
  26. var length;
  27. var key;
  28. if (arrA && arrB) {
  29. length = a.length;
  30. if (length != b.length) {
  31. return false;
  32. }
  33. for (i = length; i-- !== 0; ) {
  34. if (!equal(a[i], b[i])) {
  35. return false;
  36. }
  37. }
  38. return true;
  39. }
  40. if (arrA != arrB) {
  41. return false;
  42. }
  43. var dateA = a instanceof Date;
  44. var dateB = b instanceof Date;
  45. if (dateA != dateB) {
  46. return false;
  47. }
  48. if (dateA && dateB) {
  49. return a.getTime() == b.getTime();
  50. }
  51. var regexpA = a instanceof RegExp;
  52. var regexpB = b instanceof RegExp;
  53. if (regexpA != regexpB) {
  54. return false;
  55. }
  56. if (regexpA && regexpB) {
  57. return a.toString() == b.toString();
  58. }
  59. var keys = Object.keys(a);
  60. length = keys.length;
  61. if (length !== Object.keys(b).length) {
  62. return false;
  63. }
  64. for (i = length; i-- !== 0; ) {
  65. if (!Object.prototype.hasOwnProperty.call(b, keys[i])) {
  66. return false;
  67. }
  68. }
  69. for (i = length; i-- !== 0; ) {
  70. key = keys[i];
  71. if (!equal(a[key], b[key])) {
  72. return false;
  73. }
  74. }
  75. return true;
  76. }
  77. return a !== a && b !== b;
  78. }
  79. /**
  80. * 简单的四则运算计算函数
  81. * @param {String} expression 数学表达式字符串
  82. * @return {Number} 计算结果
  83. */
  84. export function calc(expression) {
  85. try {
  86. // 移除所有空格
  87. expression = expression.replace(/\s/g, '');
  88. // 简单的四则运算实现
  89. const tokens = expression.match(/(\d+\.?\d*|\+|\-|\*|\/|\(|\))/g) || [];
  90. const output = [];
  91. const operators = [];
  92. const precedence = {
  93. '+': 1,
  94. '-': 1,
  95. '*': 2,
  96. '/': 2
  97. };
  98. for (let token of tokens) {
  99. if (/\d/.test(token)) {
  100. output.push(parseFloat(token));
  101. } else if (token === '(') {
  102. operators.push(token);
  103. } else if (token === ')') {
  104. while (operators.length > 0 && operators[operators.length - 1] !== '(') {
  105. output.push(operators.pop());
  106. }
  107. if (operators.length > 0 && operators[operators.length - 1] === '(') {
  108. operators.pop();
  109. }
  110. } else if (['+', '-', '*', '/'].includes(token)) {
  111. while (operators.length > 0 &&
  112. operators[operators.length - 1] !== '(' &&
  113. precedence[operators[operators.length - 1]] >= precedence[token]) {
  114. output.push(operators.pop());
  115. }
  116. operators.push(token);
  117. }
  118. }
  119. while (operators.length > 0) {
  120. output.push(operators.pop());
  121. }
  122. // 计算后缀表达式
  123. const stack = [];
  124. for (let token of output) {
  125. if (typeof token === 'number') {
  126. stack.push(token);
  127. } else {
  128. const b = stack.pop();
  129. const a = stack.pop();
  130. switch (token) {
  131. case '+': stack.push(a + b); break;
  132. case '-': stack.push(a - b); break;
  133. case '*': stack.push(a * b); break;
  134. case '/': stack.push(a / b); break;
  135. }
  136. }
  137. }
  138. return stack[0] || 0;
  139. } catch (error) {
  140. console.error('Calc error:', error);
  141. return 0;
  142. }
  143. }
  144. /**
  145. * 将带单位的字符串转换为像素值
  146. * @param {String} origin 原始字符串,支持 rpx、px、% 单位和 calc() 表达式
  147. * @param {Number} screenK 屏幕比例,默认为 0.5
  148. * @param {Number} scale 缩放比例,默认为 1
  149. * @param {Number} baseSize 当设置了 % 号时,设置的基准值
  150. * @param {Object} viewRect 视图矩形信息,用于 calc() 表达式中的属性引用
  151. * @return {Number} 转换后的像素值
  152. */
  153. export function toPx(origin, screenK = 0.5, scale = 1, baseSize = 0, viewRect = {}) {
  154. const REG = /-?[0-9]+(\.[0-9]+)?(rpx|px|%)/;
  155. const parsePx = (origin) => {
  156. const results = new RegExp(REG).exec(origin);
  157. if (!origin || !results) {
  158. return origin;
  159. }
  160. const unit = results[2];
  161. const value = parseFloat(origin);
  162. let res = 0;
  163. if (unit === 'rpx' || unit === 'px') {
  164. res = Math.round(value * (screenK || 0.5) * (scale || 1));
  165. } else if (unit === '%') {
  166. res = Math.round((value * baseSize) / 100);
  167. }
  168. return res;
  169. };
  170. const formula = /^calc\((.+)\)$/.exec(origin);
  171. if (formula && formula[1]) {
  172. // 进行 calc 计算
  173. const afterOne = formula[1].replace(
  174. /([^\s\(\+\-\*\/]+)\.(left|right|bottom|top|width|height)/g,
  175. (word) => {
  176. const [id, attr] = word.split('.');
  177. return viewRect[id][attr] || 0;
  178. }
  179. );
  180. const afterTwo = afterOne.replace(new RegExp(REG, 'g'), parsePx);
  181. return calc(afterTwo);
  182. } else {
  183. return parsePx(origin);
  184. }
  185. }