前端開發的都知道HTML標簽很多,但常用的也就那么幾個。個人覺得在標簽上面小程序做得很好,只有26個標簽,而且是我們常用到的。文章介紹一些常用的HTML標簽,以及一些非常有用的HTML屬性。
本次不詳細討論標簽的使用,有興趣的朋友可以關注我下篇關于常用標簽的使用注意事項的文章。
以下是小編最常用的標簽,可以說幾乎開發網頁就用到這么22個標簽。
22個最常用的標簽
1.點擊“下載” 鏈接,下載圖片或文件而不是預覽,直接添加一個download屬性就可以
<a href="large.jpg" download>下載</a>
2.disable="disable"禁止點擊屬性,要去除時,請用js刪除該屬性。
3.<button type="button"></button>必須指明類型type="button",否則默認為submit,造成頁面刷新。
4.input type="file" accept="image,excel,word” 上傳控件的accept屬性
默認是可以上傳所有文件。
accept:表示可以選擇的文件MIME類型,多個MIME類型用英文逗號分開。
5.favicon.ico圖標是網站的縮略標志,可以顯示在瀏覽器標簽、地址欄左邊和收藏夾,是展示網站個 性的縮略logo標志
<head>
<link rel="shortcut icon" href="/favicon.ico"/>
<link rel="bookmark" href="/favicon.ico"/>
</head>
6.圖片加載慢時用logo圖片代替,onerror當圖片不存或加載不出來才生效。
7.HTML使用標簽的refresh功能來刷新或跳轉頁面
<meta http-equiv="refresh" content="3" />表示頁面每隔3秒鐘刷新一次。
<meta http-equiv="refresh" content="3; url=<#ZC_BLOG_HOST#>" />表示頁面3秒后跳轉到 <#ZC_BLOG_HOST#>頁面。
說明:若果我們網站的首頁是一個index.asp頁面,當它遭到CC攻擊是,我們把index.asp頁面打開的內容保存到index.html(新建文本并保存)中。然后清空index.asp的內容(清空之前注意備份),將上面的refresh語句復制進來。這樣就可以有效的防止CC攻擊。
多國內企業正積極開拓國際市場,如Shopee、阿里的Lazada、字節的TikTok、拼多多海外版Temu、以及服裝快消領域的Shein等。當國內市場存量業務達到峰值預期時,海外業務成為各公司未來收入增長的主要動力,因此,國際化已成為越來越重要的職業發展方向。
國內IT企業收入天花板: 「10億X2元X365天=7300億元」,也就是10億人口,企業每天賺取用戶2元,保持365天,就是單業務增長的營收天花板(大部分業務賺不到2元,用戶量也沒到10億)。比如視頻如果60元一個月那會員營收天花板就可以這么預估. 甚至比這個還低, 畢竟用戶會流失, 拉新也要成本, 運營成本是在遞增的。
國際化不僅僅是多語言文案適配這么簡單,而是一全套的工程化解決方案。筆者覺得更重要的是「從業人員需要具備全球視野,對多元文化有包容心和敬畏心理,同時知識面要求也較高」。比如,了解SEA、US、UK等常見地區的簡寫,尊重伊斯蘭教的齋月節等習俗。對于服務全球用戶的產品來說,對應產品的要求更加復雜,多樣性體現在不同的文化習俗差異上,其實即便在龐大的中國內部也存在南北差異。了解的越多越發現這個世界的“多樣性”。
蘋果鍵盤有很多型號不同型號的布局不一樣https://www.apple.com/shop/product/MK2A3J/A/magic-keyboard-japanese
apple-keyboard
那如何模仿蘋果造一把可以賣到世界各地的鍵盤?
其中2,3,4都是為產品的全球化服務
https://en.wikipedia.org/wiki/Internationalization_and_localization
globalization
產品面向全球用戶,需要做語言適配,針對不同國家地區的用戶提供對應語言的版本。本質是「文本替換」,也要考慮文本閱讀方向,比如阿拉伯語和希伯來語是從右到左。
可以看下Apple的做法,對不同國家地區提供不同服務
常見地區語言對應關系可以看 ISO 3166-1(https://baike.baidu.com/item/ISO%203166-1/5269555?fr=ge_ala)
MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl
瀏覽器中的 Intl 是一個內置的 JavaScript 對象,用于國際化(Internationalization)支持。它提供了處理日期、時間、數字格式化以及貨幣和語言的能力,以便網站能夠根據用戶的語言和地區習慣來顯示內容。在 JavaScript 中,您可以使用 Intl 對象來執行以下操作:
全地球有N個民族,有的民族有自己的語言, 有的民族用其他國家民族傳遞過來的語言, 融化吸收然后發展自己的文字。
按照ISO標準(https://zh.m.wikipedia.org/wiki/ISO_639-1),語言可以用大類+小類表示, 比如「zh」就是漢語,是一個大類,而「zh-CN」就是簡體中文的縮寫, 新加坡華人眾多久了就有「zh-SG」, 表示的是新加坡使用的中文,其次還有「zh-HK/zh-TW和zh-Hant/zh-Hans」等等
語言聲明是三段式結構 [language]-[script]-[region] , 如zh-Hans-CN表示中國地區簡體中文, zh-Hant表示所有中文繁體
Language Code Table(http://www.lingoes.net/zh/translator/langcode.htm)
一起來看下蘋果官網是如何適配多國語言的
澳門apple https://www.apple.com/mo/
香港apple
英文 https://www.apple.com/hk/en/
中文 https://www.apple.com/hk/
中國大陸地區apple https://www.apple.com.cn/
臺灣apple https://www.apple.com/tw/
新加坡apple https://www.apple.com/sg/
日本apple https://www.apple.com/jp/
可以看到有的是根域名下通過ISO地區的path比如**/hk/**這樣來區分的,有的是直接換域名,比如中國大陸地區
按照普通的中文和英文順序,都是LTR,上到下,都是世界范圍通用的
而ar阿拉伯語, ur烏都語, he希伯來語都是特殊的從右到左, 即RTL的一般會通過標簽的dir屬性標識, 比如下面的解釋HTML dir Attribute(https://www.w3schools.com/tags/att_global_dir.asp)
HEBREW是指希伯來語,這是一種在以色列廣泛使用的語言,也是猶太教的宗教經典文本的原始語言。它屬于阿夫羅亞細亞語系,有著悠久的歷史和文化價值。「希伯來語有其獨特的書寫系統,從右向左書寫。」上圖的概念很少人普及, 因為非國際化產品不需要多語言, 做需要支持海外業務和全球應用的同學可以多了解下. 傳統的英文, 中文簡體, 拉丁文等都是上圖LATIN的閱讀順序, 如果用上「top, 下bottom, 左left, 右right」代表我們的習慣, 也就是「Z」這樣的順序. 即行到行是從上到下的順序, 行內閱讀順序是從左到右.
文檔流和閱讀順序
即left→right, top→bottom的順序,有主次分別,left→right的優先級高于top→bottom
而Web標準對其定義是下面這樣的
講個笑話, 古代書籍就是按照 writing-mode: vertical-rl 排版的
joke
比如 margin: left 或者 text-align: left 在多語言場景都是不合適的,你的左右不是其他人的左右。
而應該用 margin-inline-start 和 text-align: start 替代,即inline軸和block軸
// 下面兩兩相等,請拋棄left/right/top/bottom等屬性
// https://web.dev/learn/css/logical-properties/#terminology
margin-left: 1px
margin-inline-start: 1px
margin-right: 1px
margin-inline-end: 1px
margin-top: 1px
margin-block-start: 1px
margin-bottom: 1px
margin-block-end: 1px
text-align: left
text-align: start
text-align: right
text-align: end
max-width: 100px
max-inline-width: 100px
max-inline-size: 150px
max-height: 100px
max-block-width: 100px
padding-left: 1px
padding-inline-start: 1px
padding-top: 1px
padding-block-start: 1px
top: 0.2em;
inset-block-start: 0.2em;
bottom: 0.2em;
inset-block-end: 0.2em;
left: 2px;
inset-inline-start: 2px;
right: 2px;
inset-inline-end: 2px;
border-bottom: 1px solid red;
border-block-end: 1px solid red;
border-bottom-right-radius: 1em;
border-end-end-radius: 1em;
height: 160px;
block-size: 160px;
width: 160px;
inline-size: 160px;
也可以看下面的例子
如上兩個例子通過margin-inline-start等屬性,再在html元素上添加 dir: rtl 就可以實現多語言的閱讀順序兼容
由此, 常見的布局也會更新為以下形式,常見的物理盒模型用于尺寸計算, 邏輯盒模型用于國際化處理
盒子模型
上面寫了文檔有inline and block flow,對應english的left和right,top和bottom。而 writing-mode 可以修改content-flows,比如下面的值
/* 關鍵值 */
writing-mode: horizontal-tb;
writing-mode: vertical-rl;
writing-mode: vertical-lr;
可以這么理解 writing-mode: horizontal-tb ,前面的horizontal/vertical是指的inline軸的方向,
https://codepen.io/manfredhu/pen/xxWdpaK
視口寬高viewport在這里也有特殊含義. 比如寬高vw和vh也被取代,用 vi(viewport inline) 和 vb(viewport block)替代
1%寬度=1vw=1vi 1%高度=1vh=1vb
DOM的API可以通過「Element.scrollLeft」獲取到元素滾動的距離,下圖是一個實際例子
scrollLeft的rtl
這里在最后做了一個遮罩(綠色邊框區域),內部藍色部分類似一個走馬燈,通過overflow:hidden將藍色高亮部分超出的區域遮住
當藍色部分滾動到最后,綠色遮罩隱藏,達到一個遮蓋,滾動到最后消失的效果,代碼如下
const ref=document.querySelector('.tiktok-table__container') // 父節點,藍色區域
const ref2=document.querySelector('.tiktok-table__container > table') // 子節點,表格區域
const bufferWidth=30 // 留一點buffer空間
if (ref && ref2 && ref.clientWidth + ref.scrollLeft >=ref2.clientWidth - bufferWidth) {
// 滾動到最后隱藏綠色遮罩
setTableRightMask(false)
} else {
setTableRightMask(true)
}
但是在RTL下,神奇的事情就發生了,scrollLeft居然是負數
這是因為RTL的實現是通過HTML標簽增加屬性 dir="rtl” 實現的,會將文檔完全翻轉過來,所以scrollLeft就會是負數。因為此時(0, 0)這個原點已經是表格右邊了
解決方法也很簡單,取絕對值唄,這樣就忽略了方向的影響
根據ISO標準對全球國家地區進行劃分https://en.wikipedia.org/wiki/ISO_3166-2. 如 "US" 表示美國,"CN" 表示中國. 還有常見的如「zh-CN, en-US, en-GB等」
舉個說下Intl API對于locale的定義
const korean=new Intl.Locale('ko', {
script: 'Kore',
region: 'KR',
hourCycle: 'h23',
calendar: 'gregory',
});
const japanese=new Intl.Locale('ja-Jpan-JP-u-ca-japanese-hc-h12');
console.log(korean.baseName, japanese.baseName);
// Expected output: "ko-Kore-KR" "ja-Jpan-JP"
可以看到Intl. Locale就是把傳入的字符串拆解為 [language]-[script]-[region] 的組成.
const japanese=new Intl.Locale('ja-Jpan-JP-u-ca-japanese-hc-h12');
const japanese2=new Intl.Locale('ja-Jpan-JP-u-hc-h12-ca-japanese');
-u (unicode)可以理解為額外擴展插件, 插件系統支持以下擴展. 如上使用calendar擴展和hourCycle擴展
calendarca (extension)caseFirstkf (extension)collationco (extension)hourCyclehc (extension)numberingSystemnu (extension)numerickn (extension)
calendar:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar)
caseFirst:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/caseFirst)
collation:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/collation)
hourCycle:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/hourCycle)
numberingSystem:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/numberingSystem)
numeric:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/numeric)
<html lang="en-US">
<!-- 說明頁面語言是美式英文 -->
<p>I felt some <span lang="de">schadenfreude</span>.</p> <!-- lang不是只有html標簽才有, 其他標簽也可以添加 -->
<a href="/path/to/german/version" hreflang="de" lang="de">Deutsche Version</a> <!-- a標簽上可以用lang表示顯示的文本的語言, 也可以用hreflang表示跳轉頁面的語言 -->
語言屬性通常代表語言標識符的主要部分。它標識了用于表達語言的基本信息。例如,在 BCP 47 標準中,語言標識符通常包含了語言的主要代碼部分,例如 "en" 代表英語,"es" 代表西班牙語。
const locales=['en', 'de', 'ja'];
const displayNames=new Intl.DisplayNames('en-US', { type: 'language' });
locales.forEach(locale=> console.log(displayNames.of(locale)));
// English
// German
// Japanese
如果已經有如上代碼, 再進一步給這些內容添加樣式是非常簡單的, 我們可以使用CSS的選擇器. 如 [lang|="fr"] 或者 :lang(fr)
[lang|="fr"] 選擇屬性 lang=fr 或者lang屬性以fr開頭的元素, 如 lang=fr-CA
腳本屬性是語言標識符的可選部分,表示使用的書寫系統或文字的風格。這是一個輔助信息,用于更精確地表示特定語言的書寫習慣。例如,"Hans" 代表簡體中文,"Latn" 代表拉丁文。
script的of支持傳入BCP47規范的二字碼(https://en.wikipedia.org/wiki/IETF_language_tag), 如zh
const scriptNames=new Intl.DisplayNames('en-US', { type: 'script' });
console.log(scriptNames.of('Hans')); // output:Simplified
console.log(scriptNames.of('Hant')); // output:Traditional
console.log(scriptNames.of('Latn')); // output:Latin
const scriptNames=new Intl.DisplayNames('zh-CN', { type: 'script' });
console.log(scriptNames.of('Hans')); // output:簡體
console.log(scriptNames.of('Hant')); // output:繁體
console.log(scriptNames.of('Latn')); // output:拉丁文
region 的of支持傳入https://en.wikipedia.org/wiki/ISO_3166-2 里的國家二字碼
const regionNamesInEnglish=new Intl.DisplayNames(['en'], { type: 'region' });
const regionNamesInTraditionalChinese=new Intl.DisplayNames(['zh-Hant'], { type: 'region' });
console.log(regionNamesInEnglish.of('US'));
// Expected output: "United States"
console.log(regionNamesInTraditionalChinese.of('US'));
// Expected output: "美國"
文本的閱讀順序聲明
可以通過html標簽的dir屬性設置
<html dir="ltr">
<html dir="rtl">
writing-mode: horizontal-tb;
writing-mode: vertical-lr;
writing-mode: vertical-rl;
文本行的布局方向, 以及塊的排列方向。如果想作用在整個文檔需要設置html標簽, 則全局生效
「第一個屬性horizontal/vertical指的是行塊的排列, 第二個屬性則是指文本內容的流向(content flows)」
形如 「?」 這種符號類,在多語言下是不一樣的
比如ar阿拉伯語和ur烏爾都斯語問號是RTL的,即 「?」(https://zh.m.wiktionary.org/wiki/%D8%9F)是OK的
而he希伯來語是LTR的,即 「?」 是OK的
是不是很神奇?一個問號也能玩出花來
線索管理頁-英文和阿拉伯語
常見的需要RTL的語言有下面這些
const rtlLangs=[
'ar', // 阿拉伯語
'ur', // 巴基斯坦
'he', // 以色列
'he-IL', // 希伯來語(以色列)
'fa-IR', // 波斯語(伊朗)
'ps' // 帕斯圖語
];
l10n本地化的一個比較多工作量的部分是文本的翻譯, 一種文本到N種文本的翻譯需要引入本地化團隊. 技術實現上選擇也很多
通過 key: text 映射, 比如 t('key') 最后程序跑出來就是text文案, 這種方式不會依賴其他東西, 跟普通網頁一樣內容都是CDN文件. 缺點是文案做為靜態資源需要用戶額外獲取, 如果處理不好替換錯誤就展示 key 內容而不是
以下例子以Vue為例, 配置如「en.json, fr.json」等等的靜態配置文案, 打包嵌入CDN的JS文件里
Vue i18n example:https://codesandbox.io/p/sandbox/o7n6pkpwoy?file=%2Fstore.js%3A10%2C14
程序運行時通過接口拿文案,可以通過html標簽添加query參數 lang=xxx 標記頁面語言, 或者cookie標記語言選擇
加載翻譯的腳本, 在切換語言的時候替換掉加載的文本。好處是加載的腳本是當前語言所需要的, 不會有其他語言的冗余. 缺點是依賴一個翻譯服務, 如果翻譯服務宕機了網頁就不能正常訪問了
User -> gateway -> SSR -> i18n cache -> read-time translation services(實時翻譯服務)
DevPal - ICU message editor:https://devpal.co/icu-message-editor/?data=I%20have%20%7Bnum%2C%20plural%2C%20one%7B%7Bnumber%7D%20%23%20apple%7D%20other%7B%23%20apples%7D%7D%2Cbut%20it%27s%20too%20small%0A
ICU語法即通用的有if-else邏輯的DSL,如下DSL可以根據傳入的值換取不同的表示,常用于國際化業務
I have {num, plural, one{{number} # apple} other{# apples}},but it's too small
如果你用過vim一定知道w(word)可以移動到下個單詞, 英文里把文本分為單詞、句子和段落,同理中文也是
const segmenter=new Intl.Segmenter('en-US', { granularity: 'word' });
const text='This is a sample text for demonstration purposes.';
// 使用 Segmenter 對文本進行分割
const segments=[...segmenter.segment(text)];
console.log(segments);
// 0: {segment: 'This', index: 0, input: 'This is a sample text for demonstration purposes.', isWordLike: true}
// 1: {segment: ' ', index: 4, input: 'This is a sample text for demonstration purposes.', isWordLike: false}
// 2: {segment: 'is', index: 5, input: 'This is a sample text for demonstration purposes.', isWordLike: true}
// 3: {segment: ' ', index: 7, input: 'This is a sample text for demonstration purposes.', isWordLike: false}
// 4: {segment: 'a', index: 8, input: 'This is a sample text for demonstration purposes.', isWordLike: true}
// 5: {segment: ' ', index: 9, input: 'This is a sample text for demonstration purposes.', isWordLike: false}
// 6: {segment: 'sample', index: 10, input: 'This is a sample text for demonstration purposes.', isWordLike: true}
// 7: {segment: ' ', index: 16, input: 'This is a sample text for demonstration purposes.', isWordLike: false}
// 8: {segment: 'text', index: 17, input: 'This is a sample text for demonstration purposes.', isWordLike: true}
// 9: {segment: ' ', index: 21, input: 'This is a sample text for demonstration purposes.', isWordLike: false}
// 10: {segment: 'for', index: 22, input: 'This is a sample text for demonstration purposes.', isWordLike: true}
// 11: {segment: ' ', index: 25, input: 'This is a sample text for demonstration purposes.', isWordLike: false}
// 12: {segment: 'demonstration', index: 26, input: 'This is a sample text for demonstration purposes.', isWordLike: true}
// 13: {segment: ' ', index: 39, input: 'This is a sample text for demonstration purposes.', isWordLike: false}
// 14: {segment: 'purposes', index: 40, input: 'This is a sample text for demonstration purposes.', isWordLike: true}
// 15: {segment: '.', index: 48, input: 'This is a sample text for demonstration purposes.', isWordLike: false}
Intl. Segmenter分段器可以把句子, 段落, 文章等按照配置切割為不同的segment數組, 結構類似正則, 有segment屬性
再舉個例子, 中文語境下「真的」其實是一個詞
// 創建分段器,指定語言環境和分段類型為'word'
const segmenter=new Intl.Segmenter(['en', 'zh'], { granularity: 'word' });
// 要分割的字符串
const text='Hello世界Hello world';
// 使用分段器分割字符串
const segments=segmenter.segment(text);
// 遍歷并打印每個分段的結果
for (const segment of segments) {
console.log(`Segment: ${segment.segment}, Index: ${segment.index}, IsWordLike: ${segment.isWordLike}`);
}
// Segment: Hello, Index: 0, IsWordLike: true
// Segment: 世界, Index: 5, IsWordLike: true
// Segment: Hello, Index: 7, IsWordLike: true
// Segment: , Index: 12, IsWordLike: false
// Segment: world, Index: 13, IsWordLike: true
const str="我真的很強, 強哥的強";
const segmenterJa=new Intl.Segmenter("zh-CN", { granularity: "word" });
const segments=segmenterJa.segment(str);
console.log(Array.from(segments));
// 0: {segment: '我', index: 0, input: '我真的很強, 強哥的強', isWordLike: true}
// 1: {segment: '真的', index: 1, input: '我真的很強, 強哥的強', isWordLike: true}
// 2: {segment: '很', index: 3, input: '我真的很強, 強哥的強', isWordLike: true}
// 3: {segment: '強', index: 4, input: '我真的很強, 強哥的強', isWordLike: true}
// 4: {segment: ',', index: 5, input: '我真的很強, 強哥的強', isWordLike: false}
// 5: {segment: ' ', index: 6, input: '我真的很強, 強哥的強', isWordLike: false}
// 6: {segment: '強', index: 7, input: '我真的很強, 強哥的強', isWordLike: true}
// 7: {segment: '哥', index: 8, input: '我真的很強, 強哥的強', isWordLike: true}
// 8: {segment: '的', index: 9, input: '我真的很強, 強哥的強', isWordLike: true}
// 9: {segment: '強', index: 10, input: '我真的很強, 強哥的強', isWordLike: true}
國際化會有時區劃分問題, 時區產生于太陽下地球自轉導致的晝夜交替. 而全球不同國家地區當地時間與UTC時間是不一致的. 全球大部分人都可以說自己早上起床, 晚上睡覺. 上下文是通的. 但是這個早上的時間根據UTC來定義是不一樣的
時間的往事--記一次與夏令時的斗智斗勇:https://jiangyixiong.top/2021/05/25/%E6%97%B6%E9%97%B4%E7%9A%84%E5%BE%80%E4%BA%8B%E2%80%94%E2%80%94%E8%AE%B0%E4%B8%80%E6%AC%A1%E4%B8%8E%E5%A4%8F%E4%BB%A4%E6%97%B6%E7%9A%84%E6%96%97%E6%99%BA%E6%96%97%E5%8B%87
GMT 標準時間 全球時區查詢:https://time.artjoey.com/cn
通過NTP協議(https://zh.wikipedia.org/wiki/%E7%B6%B2%E8%B7%AF%E6%99%82%E9%96%93%E5%8D%94%E5%AE%9A), 讓計算機在全球網絡里保持時間一致
東八區={CST(中國標準時),SGT(新加坡時間),AWST(澳洲西部標準時)... }
// 所在地區的時區標識符, 如 America/New_York
const timeZone=new Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log("用戶時區偏移:" + timeZone); // 用戶時區偏移:Asia/Shanghai
// 獲取本地時間與UTC時間偏移值,最小單位是分鐘. 如"-480", 表示-8小時. 其中正負表示UTC前后, 如美國東部時間是UTC-5, 中國北京時間是UTC+8
const date=new Date();
const timeZoneOffset=date.getTimezoneOffset();
console.log("時區偏移:" + timeZoneOffset); // 時區偏移:-480
Intl是新的瀏覽器API, 與Math類似是全局靜態對象, 專門用于處理國際化和本地化業務. 其下的DateTimeFormat可以處理時間相關國際化問題
DST (Daylight saving time),日光節約時,夏令時/冬令時等等名稱。「它會在每年春天的某一天將時鐘向后撥一小時,又在秋天的某一天將時鐘向前撥動一個小時。」非國際化業務很少遇到這個情況,主要因為「中國不實行夏令時/冬令時。」
2021-03-14 01:59:59 GMT-08:00(太平洋標準時間,PST)
2021-03-14T01:59:59.000-08:00(ISO格式表示)
2021-03-14T09:59:59.000Z(轉換為UTC時間并以ISO格式表示)
// 下一秒時間突變
2021-03-14 03:00:00 GMT-07:00(太平洋夏令時間,PDT)
2021-03-14T03:00:00.000-07:00(ISO格式表示)
2021-03-14T10:00:00.000Z(轉換為UTC時間并以ISO格式表示)
// 原始時間字符串
const timeString="2021-03-14T09:59:59.000Z";
// 將時間字符串轉換為 Date 對象
const date=new Date(timeString);
const pstOutput=date.toLocaleString("en-US", { timeZone: "America/Los_Angeles", hour12: false });
console.log(pstOutput); // 3/14/2021, 01:59:59
// 獲取時間戳
const timestamp=date.getTime();
// 增加1秒
const newTimestamp=timestamp + 1000;
// 創建新的 Date 對象并格式化為 PDT 時間
const newDate=new Date(newTimestamp);
const pdtOutput=newDate.toLocaleString("en-US", { timeZone: "America/Los_Angeles", hour12: false });
console.log(pdtOutput); // 3/14/2021, 03:00:00
dayjs: https://day.js.org/docs/zh-CN/i18n/i18n
國際化支持 https://github.com/iamkun/dayjs/tree/dev/src/locale
原理:通過拉取多語言文案輸出不同的formated日期時間字符串
可以看這個demo
Days of the week:https://codesandbox.io/s/dayjs-dynamic-locale0import-forked-wnk2zq?file=/src/index.js
因我本地系統設置了每周第一天為星期日
const date=new Date();
const formattedDate=new Intl.DateTimeFormat('en-US').format(date);
console.log(formattedDate); // 10/29/2023
const formattedDate=new Intl.DateTimeFormat('zh-CN').format(date);
console.log(formattedDate); // 2023/10/29
// 創建 DateTimeFormat 對象,并指定語言和地區
const dateFormatterCN=new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: 'long', // 使用完整的月份名稱
day: 'numeric',
});
console.log(dateFormatterCN.format(new Date('2024-04-28'))); // 2024年4月28日
const dateFormatterUS=new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'long', // 使用完整的月份名稱
day: 'numeric',
});
console.log(dateFormatterUS.format(new Date('2024-04-28'))); // April 28, 2024
「Intl.RelativeTimeFormat」 是 JavaScript 中的國際化 API,用于格式化相對時間,例如“1 小時前”或“2 天后”。這個 API 可以根據不同的語言和地區設置,以自然語言的方式呈現相對時間,使應用程序能夠更好地適應多語言環境。
const rtf1=new Intl.RelativeTimeFormat('zh', { style: 'short' });
console.log(rtf1.format(3, 'quarter'));
// Expected output: "3個季度后"
console.log(rtf1.format(-1, 'day'));
// Expected output: "1天前"
const rtf2=new Intl.RelativeTimeFormat('jp', { numeric: 'auto' });
console.log(rtf2.format(2, 'day'));
// Expected output: "后天"
我們知道中文語境是一萬以上可以縮寫為1萬, 或者是 1 0000. 也就是4位數字. 比如 1 2345 6789或者1’2345’6789(’是萬位分隔符)可以一眼看出來是一億兩千三百四十五萬六千七百八十九. 而如果是123, 456, 789可能很多人會愣很久重新數才知道是多少. 但是現在很多銀行APP都在推跟歐美一樣的屬于后者的千位分隔符. 可以看這篇討論覺得寫的在理
設計產品時,你是如何掉入從眾的陷阱中的?– 人人都是產品經理:https://www.woshipm.com/pd/1500589.html)
類似以上例子可以再看下面的舉例, 可以發現在德語和法語下, 千分位分隔符分別是.和 (空格)
const number=1234567.89;
const formattedNumber=new Intl.NumberFormat('zh-CN').format(number);
console.log(formattedNumber); // 1,234,567.89
const number=1234567.89;
const formattedNumber=new Intl.NumberFormat('en-US').format(number);
console.log(formattedNumber); // 1,234,567.89
const number=1234567.89;
const formattedNumber=new Intl.NumberFormat('de-DE').format(number);
console.log(formattedNumber); // 1.234.567,89
const number=1234567.89;
const formattedNumber=new Intl.NumberFormat('fr-FR').format(number);
console.log(formattedNumber); // 1 234 567,89
英文復數是要加s的, 比如apples
const numbers=[1, 2, 5, 10, 100];
for (const number of numbers) {
const pluralRules=new Intl.PluralRules('en-US'); // 使用英語環境
const pluralForm=pluralRules.select(number);
console.log(`In English, ${number} item${pluralForm !=='one' ? 's' : ''}.`);
}
// In English, 1 item.
// In English, 2 items.
// In English, 5 items.
// In English, 10 items.
// In English, 100 items.
再比如順序, 第一第二第三, 英文分別為 first, second, third, fourth, fifth. 聰明的你一定發現規律了. 除了123后面就是數字+th. 簡寫是1st 2nd. 根據下表可以發現規律
數字英文第N1One1st2Two2nd3Three3rd4Four4th10Ten10th11Eleven11th12Twelve12th13Thirteen13th20Twenty20th21Twenty-one21st30Thirty22nd31Thirty-one21st100One hundred100th
const enOrdinalRules=new Intl.PluralRules("en-US", { type: "ordinal" });
const suffixes=new Map([
["one", "st"],
["two", "nd"],
["few", "rd"],
["other", "th"],
]);
const formatOrdinals=(n)=> {
const rule=enOrdinalRules.select(n);
const suffix=suffixes.get(rule);
return `${n}${suffix}`;
};
formatOrdinals(0); // '0th'
formatOrdinals(1); // '1st'
formatOrdinals(2); // '2nd'
formatOrdinals(3); // '3rd'
formatOrdinals(4); // '4th'
formatOrdinals(11); // '11th'
formatOrdinals(21); // '21st'
formatOrdinals(42); // '42nd'
formatOrdinals(103); // '103rd'
常見的整數分隔符號有千分位分隔, 比如 1000,000 也有萬位分隔比如 1000 0000 . 不同語言不一樣
常見的小數分隔符號 . , 比如 1000.00 . 不同語言不一樣
const number=1234567.89;
// 格式化為默認數字格式
const formattedNumber=new Intl.NumberFormat().format(number);
console.log(formattedNumber); // 輸出: 1,234,567.89
// 格式化為指定語言環境的數字格式
const formattedNumberDE=new Intl.NumberFormat('de-DE').format(number);
console.log(formattedNumberDE); // 輸出: 1.234.567,89
// 格式化為指定語言環境的數字格式
const formattedNumberFR=new Intl.NumberFormat('fr-FR').format(number);
console.log(formattedNumberFR); // 輸出: 1 234 567,89
const formattedNumberCN=new Intl.NumberFormat('zh-CN').format(number);
console.log(formattedNumberCN) // 輸出: 1,234,567.89
也可以通過參數配置控制小數部分最多/最少有多少位
const number=1234567.89123;
const formattedNumber=new Intl.NumberFormat('en-US', {
style: 'decimal', // 可選 'decimal' 表示常規數字格式
maximumFractionDigits: 3, // 小數部分最多顯示三位
}).format(number);
console.log(formattedNumber); // 輸出: 1,234,567.891
正常百分比是0-100數字+%, 但是法語環境百分比符號習慣是 '% '而不是'%', 多了一個空格
const percentage=0.75;
// 使用默認語言環境
const formattedPercentageDefault=new Intl.NumberFormat('fr-FR', {
style: 'percent'
}).format(percentage);
console.log(formattedPercentageDefault); // 輸出: '75 %'
// 使用指定語言環境
const formattedPercentageFR=new Intl.NumberFormat('fr-FR', {
style: 'percent',
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(percentage);
console.log(formattedPercentageFR); // 輸出: '75,00 %'
// 使用默認語言環境
const formattedPercentageUS=new Intl.NumberFormat('en-US', {
style: 'percent'
}).format(percentage);
console.log(formattedPercentageUS); // 輸出: '75%'
// 使用指定語言環境
const formattedPercentageCN=new Intl.NumberFormat('zh-CN', {
style: 'percent',
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(percentage);
console.log(formattedPercentageCN); // 輸出: '75.00%'
console.log(new Intl.NumberFormat('en-US', { notation: "compact" , compactDisplay: "short", maximumFractionDigits: 2 }).format(987654321)) // 987.65M
console.log(new Intl.NumberFormat('zh-CN', { notation: "compact" , compactDisplay: "short", maximumFractionDigits: 2 }).format(987654321)) // 9.88億
比如人民幣是 ¥ , 美元是 $ , 歐元 , 英鎊 £
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).formatToParts().filter(i=> i.type==='currency')[0].value // '$'
new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY' }).formatToParts().filter(i=> i.type==='currency')[0].value // '¥'
new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).formatToParts().filter(i=> i.type==='currency')[0].value // ''
用常見的幾個經濟體和身邊用的多的case舉例說明, 注意看輸出
// 美元 $是美元符號
const numberUSD=123456789.12;
const formattedNumberUSD=new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(numberUSD);
console.log(formattedNumberUSD); // $123,456,789.12
// 人民幣 ¥是人民幣符號
const numberCNY=123456789.12;
const formattedNumberCNY=new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY' }).format(numberCNY);
console.log(formattedNumberCNY); // ¥123,456,789.12
// 歐元 是歐元符號
const numberEUR=123456789.12;
const formattedNumberEUR=new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(numberEUR);
console.log(formattedNumberEUR); // 123.456.789,12
// 日元
const numberJPY=123456789.12;
const formattedNumberJPY=new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' }).format(numberJPY);
console.log(formattedNumberJPY); // ¥123,456,789
// 英鎊 £是英鎊符號
const numberGBP=123456789.12;
const formattedNumberGBP=new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP' }).format(numberGBP);
console.log(formattedNumberGBP); // £123,456,789.12
// 港幣
const numberHKD=123456789.12;
const formattedNumberHKD=new Intl.NumberFormat('zh-HK', { style: 'currency', currency: 'HKD' }).format(numberHKD);
console.log(formattedNumberHKD); // HK$123,456,789.12
// 韓元
const numberKRW=123456789.12;
const formattedNumberKRW=new Intl.NumberFormat('ko-KR', { style: 'currency', currency: 'KRW' }).format(numberKRW);
console.log(formattedNumberKRW); // ?123,456,789.12
貨幣的兼容性兜底可以用 Number.prototype.toLocaleString 實現, 也可以用formatjs提供的polyfill
// 美元 $是美元符號
const numberUSD=123456789.12;
const formattedNumberUSD=new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(numberUSD);
const formatttdNumberUSDByLocaleString=Number(numberUSD).toLocaleString('en-US', { style: 'currency', currency: 'USD' });
console.log(formattedNumberUSD); // $123,456,789.12
console.log(numberUSD.toLocaleString()) // 123,456,789.12
console.log(formatttdNumberUSDByLocaleString) // $123,456,789.12
比如美國是美元, 中國有人民幣. 可以直接格式化出來
currencyNames=new Intl.DisplayNames(["zh-Hans"], { type: "currency" });
console.log(currencyNames.of("USD")); // "美元"
console.log(currencyNames.of("EUR")); // "歐元"
console.log(currencyNames.of("TWD")); // "新臺幣"
console.log(currencyNames.of("CNY")); // "人民幣"
currencyNames=new Intl.DisplayNames(["zh-Hant"], { type: "currency" });
console.log(currencyNames.of("USD")); // "美元"
console.log(currencyNames.of("EUR")); // "歐元"
console.log(currencyNames.of("TWD")); // "新臺幣"
console.log(currencyNames.of("CNY")); // "人民幣"
常見的電話本, 地址簿排序. 不同語言因為字母轉換后排序不一致. 「Intl.Collator」 是 JavaScript 的國際化 API 之一,用于字符串比較和排序,以便在多語言環境中執行正確的排序操作。它允許你創建一個 「Collator」 對象,用于根據特定語言和區域設置執行字符串比較和排序,考慮到不同語言的差異。
console.log(['Z', 'a', 'z', '?'].sort(new Intl.Collator('de').compare));
// Expected output: Array ["a", "?", "z", "Z"]
console.log(['Z', 'a', 'z', '?'].sort(new Intl.Collator('sv').compare));
// Expected output: Array ["a", "z", "Z", "?"]
console.log(['Z', 'a', 'z', '?'].sort(new Intl.Collator('de', { caseFirst: 'upper' }).compare));
// Expected output: Array ["a", "?", "Z", "z"]
//創建一個Intl.Collator對象
const collator=new Intl.Collator('en-US', { sensitivity: 'base', usage: 'sort' });
// 可以看出以下輸出是按照拼音排序, guang jin mei ming tian yang
console.log(['今','天','陽','光', '明', '媚'].sort(new Intl.Collator('zh').compare)); // ['光', '今', '媚', '明', '天', '陽']
可以發現 options可以傳遞參數usage和sensitivity, 有如下取值
有如下的應用方式
const collator=new Intl.Collator('en-US', { sensitivity: 'base', usage: 'sort' }); //創建一個Intl.Collator對象
const result=collator.compare('apple', 'Banana');
console.log(result); // 根據配置輸出 -1(apple 在 Banana 前面)
我們知道英文字母默認按照ASCII排序, 而如果需要AaBb這樣排序只能自己寫排序回調
// 創建一個自定義Collator對象
const customCollator=new Intl.Collator('en-US', {
sensitivity: 'base',
usage: 'sort',
ignorePunctuation: true,
caseFirst: 'false',
});
// 自定義比較函數, 忽略空格并不區分大小寫
function customCompare(a, b) {
// 移除字符串中的空格并轉為小寫后再比較
const stringA=a.replace(/\\s/g, '').toLowerCase();
const stringB=b.replace(/\\s/g, '').toLowerCase();
if (stringA < stringB) {
return -1;
}
if (stringA > stringB) {
return 1;
}
return 0;
}
const data=['Apple', 'banana', 'cherry', 'apple pie', 'Banana Split', 'cherry tart'];
const data2=data.slice()
// 老方式: 使用sort回調排序
console.log(data.sort(customCompare)); // 輸出排序結果:['Apple', 'apple pie', 'banana', 'Banana Split', 'cherry', 'cherry tart']
// 新方式: 使用自定義Collator對象進行排序
console.log(data2.sort(customCollator.compare)); // 輸出排序結果:['Apple', 'apple pie', 'banana', 'Banana Split', 'cherry', 'cherry tart']
可以發現兩種方式結果一樣, 但是明顯Intl. Collator更加優雅, 是配置化的.
「Intl.ListFormat」 是 JavaScript 的國際化 API 之一,它用于格式化列表,以便在多語言環境中創建自然語言的列表表示。Intl.ListFormat 允許你指定列表項的連接方式(如逗號、"和" 等),以及列表項的樣式和語言設置。
const listFormatter=new Intl.ListFormat('en-US', { style: 'long', type: 'disjunction' });
const items=['apples', 'bananas', 'cherries'];
const formattedList=listFormatter.format(items);
console.log(formattedList); // 根據配置輸出例如:"apples, bananas, or cherries"
const listFormatter=new Intl.ListFormat('en-US', { style: 'short', type: 'conjunction' });
const items=['apples', 'bananas', 'cherries'];
const formattedList=listFormatter.format(items);
console.log(formattedList); // 根據配置輸出例如:"apples, bananas, & cherries"
const listFormatter=new Intl.ListFormat('en-US', { style: 'narrow', type: 'conjunction' });
const items=['apples', 'bananas', 'cherries'];
const formattedList=listFormatter.format(items);
console.log(formattedList); // 根據配置輸出例如:"apples, bananas, cherries"
可以發現 options可以傳遞參數style和type, 有如下取值
日歷是一種常見的東西, 在中國我們經常接觸到公歷和農歷,公歷全稱格里高利歷, 英文gregory。
現在國家節日很多都是跟隨農歷的,比如春節,中秋節等。以前家家人手一本農歷, 上面會今日宜做什么, 現在很少見但是老人家還是信這個。
而與此相同, 每個地方都有自己的歷法
const date=new Date(); // 當前日期, Mon Oct 30 2023 20:00:50 GMT+0800 (中國標準時間)
const formattedDate=new Intl.DateTimeFormat('ar-SA-u-ca-islamic', { year: 'numeric', month: 'long', day: 'numeric' }).format(date);
console.log(formattedDate); // ?? ???? ????? ???? ??
const date=new Date(1994, 1, 26);
const formattedDate=new Intl.DateTimeFormat('zh-CN-u-ca-chinese', { year: 'numeric', month: 'long', day: 'numeric' }).format(date);
console.log(formattedDate); // 1994甲戌年正月17
// 不同語言下不同日歷的名稱
const calendarNames=new Intl.DisplayNames('en-US', { type: 'calendar' });
console.log(calendarNames.of('gregory')); // 輸出:Gregorian
console.log(calendarNames.of('islamic')); // 輸出:Islamic
const calendarNames=new Intl.DisplayNames('zh-CN', { type: 'calendar' });
console.log(calendarNames.of('gregory')); // 輸出:公歷
console.log(calendarNames.of('islamic')); // 輸出:伊斯蘭歷
除了上述gregory格里高利歷, 取值還有下面這些
不得不說日本的和歷, 真的是很神奇. 不是中文的周一到周日, 也不是Sunday-Saturday. 首先日本還有皇帝, 有皇帝就有年號. 常見下面的一些年份
可以看到日本的日歷起始時周日(日), 但是周一到周六分別對應月火水木金土. 與眾不同
// 獲取今天過去7天的日期
// 日期對象
const today=new Date();
// 創建一個選項對象,指定輸出的語言和風格
const optionsCN={ weekday: 'long' };
const optionsJP={ weekday: 'long' };
// 獲取過去一周的日期
console.log('\n過去一周的日期:');
const CNArr=[]
const JPArr=[]
for (let i=0; i < 7; i++) {
const pastDate=new Date(today);
pastDate.setDate(today.getDate() - i);
CNArr.unshift(new Intl.DateTimeFormat('zh-CN', optionsCN).format(pastDate))
JPArr.unshift(new Intl.DateTimeFormat('ja-JP', optionsJP).format(pastDate))
}
console.log('CNArr', CNArr.join(' ')) // CNArr 星期二 星期三 星期四 星期五 星期六 星期日 星期一
console.log('JPArr', JPArr.join(' ')) // JPArr 火曜日 水曜日 木曜日 金曜日 土曜日 日曜日 月曜日
const dateTimeFields=new Intl.DisplayNames('en-US', { type: 'dateTimeField' });
console.log(dateTimeFields.of('era')); // 輸出:Era, 紀元的意思
console.log(dateTimeFields.of('year')); // 輸出:Year
console.log(dateTimeFields.of('month')); // 輸出:Month
console.log(dateTimeFields.of('day')); // 輸出:Day
console.log(dateTimeFields.of('weekday')); // 輸出:Day of the week
console.log(dateTimeFields.of('hour')); // 輸出:Hour
console.log(dateTimeFields.of('minute')); // 輸出:Minute
console.log(dateTimeFields.of('second')); // 輸出:Second
console.log(dateTimeFields.of('quarter')); // 輸出:Quarter
const dateTimeFields=new Intl.DisplayNames('ja-JP', { type: 'dateTimeField' });
console.log(dateTimeFields.of('era')); // 輸出:時代
console.log(dateTimeFields.of('year')); // 輸出:年
console.log(dateTimeFields.of('month')); // 輸出:月
console.log(dateTimeFields.of('day')); // 輸出:日
console.log(dateTimeFields.of('weekday')); // 輸出:曜日
console.log(dateTimeFields.of('hour')); // 輸出:時
console.log(dateTimeFields.of('minute')); // 輸出:分
console.log(dateTimeFields.of('second')); // 輸出:秒
console.log(dateTimeFields.of('quarter')); // 輸出:四半期
en-US一般每周第一天是周日, 而zh-CN一般每周第一天是周一. 可以通過如下信息判斷
Intl. Locale函數返回屬性里firstDay是一個數字,其中 0或7 表示星期日,1 表示星期一,依此類推。不同的地區和文化可能會將每周的第一天設置為不同的日期,因此這個屬性可以幫助你確定每周的起始日期,例如,星期天或星期一。
(new Intl.Locale('zh-CN')).weekInfo // {"firstDay":1,"weekend":[6,7],"minimalDays":1}
(new Intl.Locale('en-US')).weekInfo // {"firstDay":7,"weekend":[6,7],"minimalDays":1}
const locale='zh-CN'
console.log(new Intl.DateTimeFormat(locale, { weekday: "long" }).format(new Date(0, 0, new Intl.Locale(locale).weekInfo.firstDay))) // '星期一'
const locale='en-US'
console.log(new Intl.DateTimeFormat(locale, { weekday: "long" }).format(new Date(0, 0, new Intl.Locale(locale).weekInfo.firstDay))) // 'Sunday'
能生效的原因就是 new Date(0,0,7) 等價于 new Date(1900,0,7) 對應1900.1.7(UTC+0), 此時對應us的sunday. 而 new Date(0,0,1) 對應1900.1.1(UTC+0), 對應cn的星期一
Intl-region-language-calendar:https://codesandbox.io/p/devbox/intl-region-language-calendar-xm7ls8?embed=1&file=%2Fsrc%2FApp.tsx
const localeUS='en-US'
new Intl.DateTimeFormat(localeUS, { weekday: "long" }).format(new Date(0, 0, new Intl.Locale(localeUS).weekInfo.firstDay)) // 'Sunday'
const localeCN='zh-CN'
new Intl.DateTimeFormat(localeCN, { weekday: "long" }).format(new Date(0, 0, new Intl.Locale(localeCN).weekInfo.firstDay)) // '星期一'
const locale="en-US";
const firstDay=new Intl.Locale(locale).weekInfo.firstDay;
const formatInstace=new Intl.DateTimeFormat(locale, { weekday: "long" });
for (let i=0; i < 7; i++) {
console.log(formatInstace.format(new Date(0, 0, firstDay + i)));
}
// Sunday
// Monday
// Tuesday
// Wednesday
// Thursday
// Friday
// Saturday
const localeCN="zh-CN";
const firstDayCN=new Intl.Locale(localeCN).weekInfo.firstDay;
const formatInstaceCN=new Intl.DateTimeFormat(localeCN, { weekday: "long" });
for (let i=0; i < 7; i++) {
console.log(formatInstaceCN.format(new Date(0, 0, firstDayCN + i)));
}
// 星期一
// 星期二
// 星期三
// 星期四
// 星期五
// 星期六
// 星期日
可以通過API, Intl.supportedValuesOf 獲取到所有支持的
const calendars=Intl.supportedValuesOf("calendar");
console.log(calendars); // 輸出所有支持的日歷系統
// (18) ['buddhist', 'chinese', 'coptic', 'dangi', 'ethioaa', 'ethiopic', 'gregory', 'hebrew', 'indian', 'islamic', 'islamic-civil', 'islamic-rgsa', 'islamic-tbla', 'islamic-umalqura', 'iso8601', 'japanese', 'persian', 'roc']
const currencies=Intl.supportedValuesOf("currency");
console.log(currencies); // 輸出所有支持的貨幣代碼
// (159) ['AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CUC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'INR', 'IQD', 'IRR', 'ISK', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', …]
const timeZones=Intl.supportedValuesOf("timeZone");
console.log(timeZones); // 輸出所有支持的時區
// (428) ['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', 'Africa/Algiers', 'Africa/Asmera', 'Africa/Bamako', 'Africa/Bangui', 'Africa/Banjul', 'Africa/Bissau', 'Africa/Blantyre', 'Africa/Brazzaville', 'Africa/Bujumbura', 'Africa/Cairo', 'Africa/Casablanca', 'Africa/Ceuta', 'Africa/Conakry', 'Africa/Dakar', 'Africa/Dar_es_Salaam', 'Africa/Djibouti', 'Africa/Douala', 'Africa/El_Aaiun', 'Africa/Freetown', 'Africa/Gaborone', 'Africa/Harare', 'Africa/Johannesburg', 'Africa/Juba', 'Africa/Kampala', 'Africa/Khartoum', 'Africa/Kigali', 'Africa/Kinshasa', 'Africa/Lagos', 'Africa/Libreville', 'Africa/Lome', 'Africa/Luanda', 'Africa/Lubumbashi', 'Africa/Lusaka', 'Africa/Malabo', 'Africa/Maputo', 'Africa/Maseru', 'Africa/Mbabane', 'Africa/Mogadishu', 'Africa/Monrovia', 'Africa/Nairobi', 'Africa/Ndjamena', 'Africa/Niamey', 'Africa/Nouakchott', 'Africa/Ouagadougou', 'Africa/Porto-Novo', 'Africa/Sao_Tome', 'Africa/Tripoli', 'Africa/Tunis', 'Africa/Windhoek', 'America/Adak', 'America/Anchorage', 'America/Anguilla', 'America/Antigua', 'America/Araguaina', 'America/Argentina/La_Rioja', 'America/Argentina/Rio_Gallegos', 'America/Argentina/Salta', 'America/Argentina/San_Juan', 'America/Argentina/San_Luis', 'America/Argentina/Tucuman', 'America/Argentina/Ushuaia', 'America/Aruba', 'America/Asuncion', 'America/Bahia', 'America/Bahia_Banderas', 'America/Barbados', 'America/Belem', 'America/Belize', 'America/Blanc-Sablon', 'America/Boa_Vista', 'America/Bogota', 'America/Boise', 'America/Buenos_Aires', 'America/Cambridge_Bay', 'America/Campo_Grande', 'America/Cancun', 'America/Caracas', 'America/Catamarca', 'America/Cayenne', 'America/Cayman', 'America/Chicago', 'America/Chihuahua', 'America/Ciudad_Juarez', 'America/Coral_Harbour', 'America/Cordoba', 'America/Costa_Rica', 'America/Creston', 'America/Cuiaba', 'America/Curacao', 'America/Danmarkshavn', 'America/Dawson', 'America/Dawson_Creek', 'America/Denver', 'America/Detroit', 'America/Dominica', 'America/Edmonton', 'America/Eirunepe', …]
Intl是瀏覽器對i18n提供的底層API, 用于處理國際化相關內容. 附帶browerstack 云真機測試工具(caniuse推薦): https://live.browserstack.com/dashboard如果沒處理好兼容性問題直接使用API, 會報JS Error. 內容為Intl.DisplayNames is not a constructor
對應的, 一些操作系統低版本的用戶(長期不升級系統)會遇到JS Error導致白屏
Google pixel4(2019, October 15發行)
可以用formatjs提供的polyfill做低版本兼容: https://formatjs.io/docs/getting-started/installation
async function loadPolyfill() {
// 如果當前環境不支持 Intl 或者 Intl.DisplayNames
if (!window.Intl || !window.Intl.DisplayNames) {
window.Intl=window.Intl || {}
// 加載 polyfill
await import('@formatjs/intl-getcanonicallocales/polyfill-force')
await import('@formatjs/intl-locale/polyfill-force')
await import('@formatjs/intl-displaynames/polyfill-force')
await import('@formatjs/intl-displaynames/locale-data/en')
return false
} else {
// 當前環境支持 Intl.DisplayNames API,不需要 Polyfill
return true
}
}
眾所周知Babel有一個babel-preset-env(https://www.babeljs.cn/docs/babel-preset-env#how-does-it-work), 用于在編譯代碼時智能(基于core-js-compat(https://www.npmjs.com/package/core-js-compat))引入helper和polyfill 智能的含義: 可以設置最低兼容的瀏覽器(https://github.com/browserslist/browserslist#queries)和代碼, 動態引用所需的helper和polyfill
// babel.config.js
module.exports={
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage', // 根據每個文件里面,用到了哪些es的新特性和targets導入polyfill,更加精簡
corejs: 3, // 指定 core-js 版本
targets: "> 0.25%, not dead" // 指定目標瀏覽器, 選取全球使用率超過 0.25% 的瀏覽器版本
},
],
],
};
「babel底層使用core-js(https://github.com/zloirock/core-js)進行polyfill, 但是core-js不包含Intl API部分的polyfill(https://github.com/zloirock/core-js?tab=readme-ov-file#missing-polyfills), 所以babel并不能為Intl API做polyfill」
npm i @formatjs/intl
import {createIntl, createIntlCache} from '@formatjs/intl'
// This is optional but highly recommended
// since it prevents memory leak
const cache=createIntlCache()
const intlFr=createIntl(
{
locale: 'fr-FR',
messages: {},
},
cache
)
const intlEn=createIntl(
{
locale: 'en-US',
message: {},
cache
}
)
// Call imperatively
console.log(intlFr.formatNumber(2000000000000)) // 2 000 000 000 000
console.log(intlEn.formatNumber(2000000000000)) // 2,000,000,000,000
作者:ManfredHu
來源-微信公眾號:字節前端 ByteFE
出處:https://mp.weixin.qq.com/s/PByp6Pmc3vp7b0acyPT8yA
.大家應該都知道wordpecss網址的文章如圖1分享到QQ空間,是可以顯示并自動獲取文章的縮略圖片,這樣顯得有檔次的感覺。
圖1文章分享到QQ空間可以顯示縮略圖片
1.2 那如果文章分享到微信朋友圈呢?博主試過在電腦網頁或者直接微信分享文章,到朋友圈都只能看到空白的縮略圖片,如圖2這樣總感覺不好看
網上也看到很多教程,需要開通微信公眾號等等方面,博主覺得沒必要,畢竟公眾號每年也要教幾百塊錢的哈,還不如用來續費服務器噠,后來無意中發現一個很簡單的辦法,可以分享文章到微信朋友圈可以抓取文章圖片的方法,反正我目前測試是可以的,分享經驗的目地只是大家交流學習哦。如有錯誤之處請大家提出,謝謝(如圖3打開手機游覽器,進入自己的網站然后找到箭頭所示分享到朋友圈,圖4的可以正常顯示鏈接文章的圖片了。)
*請認真填寫需求信息,我們會在24小時內與您取得聯系。