You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

browser-compatibility.js 5.9 kB

2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. (()=>{
  2. function runCodeWithFunction(obj) {
  3. return Function(`"use strict"; return (${obj})`)();
  4. }
  5. function supportsPseudoClass(clazz) {
  6. const style = document.createElement('style');
  7. style.innerHTML = clazz + '{}';
  8. document.head.appendChild(style); // required, or style.sheet === null
  9. const result = style.sheet.cssRules.length === 1;
  10. style.remove(); // document.head.removeChild(style);
  11. return result;
  12. }
  13. const features = [
  14. {name: "Optional chaining (?.) / 可选链操作符(?.)", version:{firefox:74,chrome:80,safari:13.4}, url: "https://caniuse.com/mdn-javascript_operators_optional_chaining", test: ()=>Boolean(runCodeWithFunction("undefined?.undefined || true"))},
  15. {name: "Nullish coalescing operator (??) / 空值合并操作符(??)", version:{firefox:72,chrome:80,safari:13.4}, url: "https://caniuse.com/mdn-javascript_operators_nullish_coalescing", test: ()=>Boolean(runCodeWithFunction("undefined ?? true"))},
  16. {name: "BigInt value (1n) / BigInt 数据类型(1n)", version:{firefox:68,chrome:67,safari:14}, url: "https://caniuse.com/bigint", test: ()=>Boolean(runCodeWithFunction("1n"))},
  17. {name: "CSS selector: :where() / CSS选择器: :where()", version:{firefox:78,chrome:88,safari:14}, url: "https://caniuse.com/mdn-css_selectors_where", test: ()=>supportsPseudoClass(":where()")},
  18. {name: "CSS selector: :not() / CSS选择器: :not()", version:{firefox:84,chrome:88,safari:9}, url: "https://caniuse.com/css-not-sel-list", test: ()=>supportsPseudoClass(":not(html)")},
  19. //{name: "CSS selector: :has() / CSS选择器: :has()", version:{firefox:121,chrome:105,safari:15.4}, url: "https://caniuse.com/css-has", test: ()=>supportsPseudoClass(":has(html)")},
  20. {name: "Private class fields (#name) / 类私有域(#name)", version:{firefox:90,chrome:74,safari:14.5}, url: "https://caniuse.com/mdn-javascript_classes_private_class_fields", test: ()=>Boolean(runCodeWithFunction("class test {#v = 0;}, true"))},
  21. {name: "Dialog element / Dialog 元素", version:{firefox:98,chrome:37,safari:15.4}, url: "https://caniuse.com/dialog", test: ()=>Boolean(window.HTMLDialogElement)},
  22. //{name: "Class static initialization blocks / 静态初始化块", version:{firefox:93,chrome:94,safari:16.4}, url: "https://caniuse.com/mdn-javascript_classes_static_initialization_blocks", test: ()=>Boolean(runCodeWithFunction("class test { static { this.staticProperty = true;};}, true"))},
  23. {name: "Array.prototype.toSorted()", version:{firefox:115,chrome:110,safari:16.0}, url: "https://caniuse.com/mdn-javascript_builtins_array_tosorted", test: ()=>Boolean(Array.prototype.toSorted)},
  24. {name: "Set.prototype.isDisjointFrom()", version:{firefox:127,chrome:122,safari:17.0}, url: "https://caniuse.com/mdn-javascript_builtins_set_isdisjointfrom", test: ()=>Boolean(Set.prototype.isDisjointFrom)},
  25. ];
  26. const unsupportFeatures = features.filter(feature=>{
  27. try {
  28. return !feature.test();
  29. } catch (e) {
  30. if (e.name !== 'SyntaxError')
  31. console.error(e);
  32. return true;
  33. }
  34. });
  35. if (unsupportFeatures.length) {
  36. const browserVersion = ((UA)=>{
  37. let regRes;
  38. if (regRes = /\b(Firefox|Chrome)\/([\d\.]+)/ig.exec(UA)) {
  39. return `${regRes[1]} ${regRes[2]}`;
  40. } else if (regRes = /\bVersion\/([\d\.]+)\s+.*\b(Safari)\//ig.exec(UA)) {
  41. return `${regRes[2]} ${regRes[1]}`;
  42. } else {
  43. UA;
  44. }
  45. })(navigator.userAgent);
  46. //支持的最低版本
  47. const needBrowserVersion = unsupportFeatures.reduce((pre,{version})=>{
  48. pre.firefox = Math.max(pre.firefox,version.firefox);
  49. pre.chrome = Math.max(pre.chrome,version.chrome);
  50. pre.safari = Math.max(pre.safari,version.safari);
  51. return pre;
  52. }, {firefox:0,chrome:0,safari:0});
  53. let alertStr;
  54. if (/^zh-(?:han(?:s|t)-)?/.test(navigator.language)) {
  55. alertStr =
  56. `<p lang="zh">🙁浏览器内核版本太老<br>
  57. 您的浏览器版本为: ${browserVersion}<br>
  58. 您的浏览器内核不支持本程序使用的以下技术
  59. <ol>
  60. ${unsupportFeatures.map(feature=>`<li><a href="${feature.url}">${feature.name}</a></li>`).join('')}
  61. </ol>
  62. 请更新您的浏览器内核到 Firefox(火狐) ≥ ${needBrowserVersion.firefox} 或 Chrome(谷歌) ≥ ${needBrowserVersion.chrome} 或 Safari ≥ ${needBrowserVersion.safari}。</p>`;
  63. } else {
  64. alertStr =
  65. `<p lang="en">🙁Browser kernel is too old<br>
  66. Your browser is: ${browserVersion}<br>
  67. Your browser kernel does not support the following technologies used by this program:
  68. <ol>
  69. ${unsupportFeatures.map(feature=>`<li><a href="${feature.url}">${feature.name}</a></li>`).join('')}
  70. </ol>
  71. Please update your browser core to Firefox ≥ ${needBrowserVersion.firefox} or Chrome ≥ ${needBrowserVersion.chrome} or Safari ≥ ${needBrowserVersion.safari}</p>`;
  72. }
  73. //alert(alertStr);
  74. document.write(alertStr);
  75. }
  76. if (/\b(?:MicroMessenger|WeChat|Weixin|QQ|AliApp)\b/.test(navigator.userAgent)) {
  77. const mask = document.createElement("div");
  78. mask.id = "denied-mask";
  79. const css = `
  80. #denied-mask {
  81. position: fixed;
  82. height: 100%;
  83. width: 100%;
  84. top: 0;
  85. left: 0;
  86. background-color: #000A;
  87. }
  88. .alert {
  89. font-size: 2em;
  90. font-weight: bold;
  91. color: white;
  92. text-align: center;
  93. }
  94. `;
  95. const style = mask.appendChild(document.createElement("style"));
  96. style.appendChild(document.createTextNode(css));
  97. const alertDiv = mask.appendChild(document.createElement("div"));
  98. alertDiv.className = "alert";
  99. alertDiv.innerHTML = `请勿使用APP内置浏览器,会有功能缺失<br>点击菜单使用正常浏览器打开↗`;
  100. const removeMe = mask.appendChild(document.createElement("button"));
  101. removeMe.append("我知道了");
  102. removeMe.onclick = ()=>{
  103. mask.remove();
  104. delete mask;
  105. };
  106. const event = window.addEventListener("load", ()=>{
  107. document.body.appendChild(mask);
  108. window.removeEventListener(event);
  109. });
  110. }
  111. })();