沐鳴登錄網站_dotnet高性能buffer

1 前言

我曾經寫過《雜談.netcore的Buffer相關新類型》的博客,簡單介紹過BinaryPrimitives、Span<>,Memory<>,ArrayPool<>,Memorypool<>這些基礎類型,在實際項目中,我們更需要的是更上層的高效緩衝區申請、buffer寫入、buffer讀取功能。本文將介紹如何利用這些基礎類型,封裝成易於使用的buffer相關操作類,這些類的源代碼在MemoryExtensions庫里。

2 buffer知識

buffer的申請

通過經驗與實驗數據,根據不同場景與buffer大小,選擇合適的申請方式。

申請式 特點 局限
stackalloc byte 非常快速 堆棧上分配內存塊,容量小且在方法返回時緩衝區丟棄
new byte[] 當小於1KB時速度快 頻繁創建導致內存碎片,GC壓力大
ArrayPool.Rent 適合大的緩衝區租賃,幾乎無內存分配 緩衝區小於1KB時,租賃不如new來得快

IBufferWriter 接口

此接口支持獲取緩衝區的寫入Span或GetMemory給外部直接寫入數據,寫入完成之後調用Advance(int)方法,告訴writer實際的寫入大小。

我們來對比一下MemoryStream的Write()方法,比如要寫一個int類型的值,我們不得不將int轉為4字節的byte[],然後傳byte[]到Write()方法。這個4字節的byte[]是一個副作用,它的存在原於外部無法獲取和擴大MemoryStream的緩衝區。

3 BufferWriter的實現

根據“buffer的申請”幾種方式,我們實現多種不同的BufferWriter。

RecyclableBufferWriter

可回收的自動擴容BufferWriter,適合於大的緩衝區的場景。它的緩衝區通過ArrayPool來租賃,用完之後,要Dispose()歸還到ArrayPool。優點是內存分配少,缺點是租賃比直接創建小的緩衝區還要慢。


  
   Copy
  var writer = new RecyclableBufferWriter<byte>(4);
writer.Write((byte)1);
writer.Write(new byte[] { 2, 3, 4 });
writer.WriteBigEndian(int.MaxValue);           
var writtern = writer.WrittenSpan; // 1,2,3,4,127,255,255,255

// return the buffer to pool
writer.Dispose();

ResizableBufferWriter

自動擴容的BufferWriter,適合小的動態緩衝區的場景。它的沖區通過new Array來創建,通過Array.Resize擴容。優點是cpu性能好,缺點是內存分配高。


  
   Copy
  var writer = new ResizableBufferWriter<byte>(4);
writer.Write((byte)1);
writer.Write(new byte[] { 2, 3, 4 });
writer.WriteBigEndian(int.MaxValue);           
var writtern = writer.WrittenSpan; // 1,2,3,4,127,255,255,255

FixedBufferWriter

固定大小緩衝區,就是我們自己new的Array,包裝為IBufferWriter對象。


  
   Copy
  var array = new byte[16];

var writer = array.CreateWriter();
writer.WriteBigEndian(18);
writer.WriteBigEndian(2.01f);

4 IBufferWriter 的擴展

經常會遇到將int、double等諸多数字類型寫入IBufferWriter的場景,期間還涉及平台的BigEndian或LittleEndian,我們給IBufferWriter<byte>編寫重載的擴展方法。

方法 說明
WriteBigEndian(this IBufferWriter , short) short
WriteBigEndian(this IBufferWriter , int) int
WriteBigEndian(this IBufferWriter , long) long
WriteBigEndian(this IBufferWriter , ushort) ushort
WriteBigEndian(this IBufferWriter , uint) uint
WriteBigEndian(this IBufferWriter , ulong) ulong
WriteBigEndian(this IBufferWriter , float) float
WriteBigEndian(this IBufferWriter , double) double
WriteLittleEndian(this IBufferWriter , short) short
WriteLittleEndian(this IBufferWriter , int) int
WriteLittleEndian(this IBufferWriter , long) long
WriteLittleEndian(this IBufferWriter , ushort) ushort
WriteLittleEndian(this IBufferWriter , uint) uint
WriteLittleEndian(this IBufferWriter , ulong) ulong
WriteLittleEndian(this IBufferWriter , float) float
WriteLittleEndian(this IBufferWriter , double) double

5 ref BufferReader

同樣的,我們也經常遇到從緩衝區中讀取為int、double等諸多数字類型的場景,所以也需要設計一個高效的BufferReader。


  
   Copy
  public ref struct BufferReader
{
    /// <summary>
    /// 未讀取的數據
    /// </summary>
    private ReadOnlySpan<byte> span;
}

給它設計ReadLittleEndian和ReadBigEndian相關Api

方法 說明
ReadBigEndian(out short) short
ReadBigEndian(out int) int
ReadBigEndian(out long) long
ReadBigEndian(out ushort) ushort
ReadBigEndian(out uint) uint
ReadBigEndian(out ulong) ulong
ReadBigEndian(out float) float
ReadBigEndian(out double) double
ReadLittleEndian(out short) short
ReadLittleEndian(out int) int
ReadLittleEndian(out long) long
ReadLittleEndian(out ushort) ushort
ReadLittleEndian(out uint) uint
ReadLittleEndian(out ulong) ulong
ReadLittleEndian(out float) float
ReadLittleEndian(out double) double

6 關於MemoryExtensions庫

本文提到的這些類或結構體,在MemoryExtensions庫里都有實現,可以直接使用,其中BufferWriter技術已經在WebApiClient里大量應用。

原文:https://www.cnblogs.com/kewei/p/14285873.html

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10107

沐鳴娛樂業務:_web名詞解釋

HTML:超文本標記語言,標準通用標記語言下的一個應用。

CSS:層疊樣式表(英文全稱:Cascading Style Sheets),是一種用來表現 HTML(標準通用標記語言的一個應用)或 XML(標準通用標記語言的一個子集)等文件樣式的語言,用於為 HTML 文檔定義布局。

JavaScript:一種直譯式腳本語言,其主要作用是在不與服務器交互的情況下修改 HTML 頁面內容, 為網頁添加各式各樣的動態功能。Ecma 國際以 JavaScript 為基礎制定了 ECMAScript 標準。

jQuery:是一個快速、簡潔的 JavaScript 框架,是一個優秀的JavaScript 代碼庫(或 JavaScript 框架)。

DOM:文檔對象模型(Document Object Model,簡稱 DOM), 是 W3C 組織推薦的處理可擴展標誌語言的標準編程接口。

UI:即 User Interface(用戶界面)的簡稱。泛指用戶的操作界面,包含於移動 APP、網頁、智能穿戴設備等。

CSS3:是 CSS(層疊樣式表)技術的升級版本,於 1999 年開始制訂,2001 年 5 月 23 日 W3C 完成了 CSS3 的工作草案,主要包括盒子模型、列表、超鏈接方式、語言模塊、背景和邊框、文字特效、多欄布局等模塊 。

CSS hack:通過在 CSS 樣式中加入一些特殊的符號,區別不同瀏覽器製作不同的 CSS 樣式的設置,解決瀏覽器显示網頁特效不兼容性問題。

PHP: 超文本預處理器(Hypertext Preprocessor),PHP 將程序嵌入到 HTML 文檔中去執行,是 Web 開發動態網頁製作技術之一。

IFRAME:是 HTML 標籤,作用是文檔中的文檔,或者浮動的框架(FRAME)。

Html5:萬維網的核心語言,標準通用標記語言下的一個應用超文本標記語言(HTML)的第五次重大修改,其主要的目標是將互聯網語義化,以便更好地被人類和機器閱讀,並同時更好地支持網頁中嵌入各種媒體。

OOP: 面向對象編程(Object Oriented Programming,OOP,面向對象程序設計)是一種計算機編程架構。

Bootstrap:是美國 Twitter 公司的設計師 Mark Otto 和 Jacob Thornton 合作基於 HTML、CSS、JavaScript 開發的簡潔、直觀的前端開發框架,使得 Web 開發更加快捷。

Less: 是一種 CSS 預處理語言,它擴充了 CSS 語言,增加了諸如變量、混入、函數等功能,讓 CSS 更易維護,方便製作主題和擴充。使用 CSS 的語法。

Sass: Sass(Syntactically Awesome Style Sheets)是一個相對新的編程語言,Sass 為 web 前端開發定義一套新的語法規則和函數,以加強和提升 CSS,Sass 的安裝需要 Ruby 環境。

MySQL:是一個關係型數據庫管理系統,由瑞典 MySQL AB公司開發,目前屬於 Oracle 旗下產品。

API:(Application Programming Interface,應用程序編程接口)是一些預先定義的函數,目的是提供應用程序與開發人員基於某軟件或硬件得以訪問一組例程的能力,而無需訪問源碼,也無需理解內部工作機制的細節。

HTTP:超文本傳輸協議(HTTP,HyperText Transfer Protocol)是互聯網上應用最為廣泛的一種網絡協議。

RESTful: 表現層狀態轉化(Representational State Transfer)軟件架構風格,提供了一組設計原則和約束條件。

Web:(World Wide Web)即全球廣域網,也稱為萬維網,它是一種基於超文本和 HTTP 的、全球性的、動態交互的、跨平台的分佈式信息系統。

Ajax: 即 “Asynchronous JavaScript And XML” ( 異 步JavaScript 和 XML),是指一種創建交互式網頁應用的網頁開發技術。

XML:可擴展標記語言,標準通用標記語言的子集,是一種用於標記电子文件使其具有結構性的標記語言。

jsON:(JavaScript Object Notation, js 對象簡譜) 是一種輕量級的數據交換格式。

JSONP:(JSON with Padding)是 JSON 的一種“使用模式”,可用於解決主流瀏覽器的跨域數據訪問的問題。

Laravel: Laravel是一套簡潔、優雅的php Web開發框架(PHP Web Framework)。

BLADE: 快速搭建一個 Web 應用程序的開源框架

Session:會話,指瀏覽器和服務器的一次交互。

Cookie:有時也用其複數形式 Cookies,指某些網站為了辨別用戶身份、跟蹤 session 而儲存在用戶本地終端上的數據(通常經過加密)。

jQuery Mobile:是 jQuery 框架的一個組件,用於創建移動端 Web 應用的的前端框架。

ES6: ECMAScript 語言規範第六版。ECMAScript 是一種由
Ecma 國際通過 ECMA-262 標準化的腳本程序設計語言,是 JavaScript的標準。

Node.js:是 JavaScript 運行在服務端的平台。

Express: 是一個簡潔而靈活的 node.js Web 應用框架。

vue: 是一套構建用戶界面的漸進式框架。

webpack: 是一個模塊打包工具,將 Web 開發的各種資源打包壓縮在指定的文件中。

Canvas: 畫布,是 html5 中新增的標籤,用於網頁實時生成圖像,並且可以操作圖像內容。

SVG:可縮放矢量圖形,是基於可擴展標記語言 XML(標準通用標記語言的子集)用於描述二維矢量圖形的一種圖形格式。

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10112

沐鳴:_在Vue.js中加載字體的最佳做法

博客原文:https://blog.zhangbing.site/2021/04/07/best-practices-for-loading-fonts-in-vue/

添加字體不應該對性能產生負面影響。在本文中,我們將探討在 vue 應用程序中加載字體的最佳實踐。


正確聲明font-face的字體

確保正確聲明字體是加載字體的重要方面。這是通過使用 font-face 屬性來聲明你選擇的字體來實現的。在你的Vue項目中,這個聲明可以在你的根css文件中完成。在進入這個問題之前,我們先來看看Vue應用的結構。

/root
  public/
    fonts/
      Roboto/
        Roboto-Regular.woff2
        Roboto-Regular.woff
    index.html
  src/
    assets/
      main.css
    components/
    router/
    store/
    views/
    main.js

我們可以像這樣在 main.css 中進行 font-face 聲明:

// src/assets/main.css

@font-face {
  font-family: "Roboto";
  font-weight: 400;
  font-style: normal;
  font-display: auto;
  unicode-range: U+000-5FF;
  src: local("Roboto"), url("/fonts/Roboto/Roboto-Regular.woff2") format("woff2"), url("/fonts/Roboto/Roboto-Regular.woff") format("woff");
}

首先要注意的是 font-display:auto。使用 auto 作為值可以讓瀏覽器使用最合適的策略來显示字體。這取決於一些因素,如網絡速度、設備類型、閑置時間等。

要想更多地控制字體的加載方式,你應該使用 font-display: block,它指示瀏覽器短暫地隱藏文本,直到字體完全下載完畢。其他可能的值有 swap、fallback 和 optional。你可以在這裏閱讀更多關於它們的信息。

需要注意的是 unicode-range: U+000-5FF,它指示瀏覽器只加載所需的字形範圍(U+000 – U+5FF)。你還想使用woff和woff2字體格式,它們是經過優化的格式,可以在大多數現代瀏覽器中使用。

另外需要注意的是 src 順序。首先,我們檢查字體的本地副本是否可用(local(“Roboto”))並使用它。很多Android設備都預裝了Roboto,在這種情況下,我們將使用預裝的副本。如果沒有本地副本,則在瀏覽器支持的情況下繼續下載woff2格式。否則,它會跳至支持的聲明中的下一個字體。

預加載字體

一旦你的自定義字體被聲明,你可以使用 <link rel=”preload”> 告訴瀏覽器提前預加載字體。在 public/index.html 中,添加以下內容:

<link rel="preload" as="font" href="./fonts/Roboto/Roboto-Regular.woff2" type="font/woff2" crossorigin="anonymous">

rel = “preload” 指示瀏覽器儘快開始獲取資源,as = “font” 告訴瀏覽器這是一種字體,因此它優先處理請求。還要注意crossorigin=“anonymous”,因為如果沒有這個屬性,預加載的字體會被瀏覽器丟棄。這是因為瀏覽器是以匿名方式獲取字體的,所以使用這個屬性就可以匿名請求。

使用 link=preload 可以增加自定義字體在需要之前被下載的機會。這個小調整大大加快了字體的加載時間,從而加快了您的Web應用程序中的文本渲染。

使用link = preconnect託管字體

當使用Google fonts等網站的託管字體時,你可以通過使用 link=preconnect 來獲得更快的加載時間。它告訴瀏覽器提前建立與域名的連接。

如果您使用的是Google字體提供的Roboto字體,則可以在 public/index.html 中執行以下操作:

<link rel="preconnect" href="https://fonts.gstatic.com">
...
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">

這樣就可以建立與原點https://fonts.gstatic.com 的初始連接,當瀏覽器需要從原點獲取資源時,連接已經建立。從下圖中可以看出兩者的區別。

當加載字體時沒有使用 link=preconnect 時,你可以看到連接所需的時間(DNS查找、初始連接、SSL等)。當像這樣使用link=preconnect 時,結果看起來非常不同。

在這裏,你會發現DNS查找、初始連接和SSL所花費的時間已經不存在了,因為前面已經進行了連接。

使用service workers緩存字體

字體是靜態資源,變化不大,所以它們是緩存的好候選。理想情況下,您的Web服務器應該為字體設置一個較長的 max-age expires 頭,這樣瀏覽器緩存字體的時間就會更長。如果你正在構建一個漸進式網絡應用(PWA),那麼你可以使用service workers來緩存字體,並直接從緩存中為它們提供服務。

要開始使用Vue構建PWA,請使用vue-cli工具生成一個新項目:

vue create pwa-app

選擇Manually select features選項,然後選擇Progressive Web App (PWA) Support

這些就是我們生成PWA模板所需要的唯一東西。完成后,你就可以把目錄改為 pwa-app,然後為app服務。

cd pwa-app
yarn serve

你會注意到在 src 目錄下有一個文件 registerServiceWorker,其中包含了默認的配置。在項目的根目錄下,如果vue.config.js 不存在,請創建它,如果存在,請添加以下內容:

// vue.config.js
module.exports = {
  pwa: {
    workboxOptions: {
      skipWaiting: true,
      clientsClaim: true,
    }
  }
}

vue-cli工具使用PWA plugin生成service worker。在底層,它使用Workbox來配置service worker和它控制的元素、要使用的緩存策略以及其他必要的配置。

在上面的代碼片段中,我們要確保我們的應用程序始終由service worker的最新版本控制。這是必要的,因為它確保我們的用戶總是查看應用程序的最新版本。您可以簽出Workbox配置文檔,以獲得對生成的service worker行為的更多控制。

接下來,我們將自定義字體添加到 public 目錄。我有以下結構:

root/
  public/
    index.html
    fonts/
      Roboto/
        Roboto-Regular.woff
        Roboto-Regular.woff2

一旦完成了Vue應用程序的開發,就可以通過從終端運行以下命令來構建它:

yarn build

這將結果輸出到 dist 文件夾中。如果你檢查文件夾的內容,你會注意到一個類似於 precache-manifest.1234567890.js 的文件。它包含了要緩存的資產列表,這隻是一個包含修訂版和URL的鍵值對的列表。

self.__precacheManifest = (self.__precacheManifest || []).concat([
  {
    "revision": "3628b4ee5b153071e725",
    "url": "/fonts/Roboto/Roboto-Regular.woff2"
  },
  ...
]);

public/ 文件夾中的所有內容都是默認緩存的,其中包括自定義字體。有了這個地方,你可以用像service這樣的包來serve你的應用程序,或者把 dist 文件夾託管在web服務器上查看結果。

在隨後的訪問中,字體是從緩存中加載的,這可以加快應用程序的加載時間。

結論

在這篇文章中,我們研究了在Vue應用程序中加載字體時應用的一些最佳實踐。使用這些實踐將確保你提供的字體看起來不錯,而不影響應用的性能。

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10203

沐鳴測速登錄地址_Js阻止事件冒泡與阻止默認事件:理解stopPropagation(),preventDefault(),return false的區別

這篇文章主要講解js中阻止事件冒泡,阻止默認事件的方法,理解stopPropagation(),preventDefault(),return false的區別。

1.event.stopPropagation()方法

event.stopPropagation() 方法阻止事件冒泡到父元素,阻止任何父事件處理程序被執行。不讓事件向documen上蔓延,但是默認事件任然會執行,當你掉用這個方法的時候,如果點擊一個連接,這個連接仍然會被打開。

提示:請使用 event.isPropagationStopped() 方法來檢查指定的事件上是否調用了該方法。

2.event.preventDefault()方法

取消事件的默認動作。該方法將通知 Web 瀏覽器不要執行與事件關聯的默認動作(如果存在這樣的動作)。例如:

form表單如果 type 屬性是 “submit”,在事件傳播的任意階段可以調用任意的事件句柄,通過調用該方法,可以阻止提交表單。

a元素中href連接,如果調用此方法是,連接不會被打開。

注意

1、如果 Event 對象的 cancelable 屬性是 fasle,那麼就沒有默認動作,或者不能阻止默認動作。無論哪種情況,調用該方法都沒有作用。

2、該方法會發生冒泡,冒泡會傳遞到上一層的父元素。

3.return false;

這個方法比較暴力,他會同事阻止事件冒泡也會阻止默認事件;寫上此代碼,連接不會被打開,事件也不會傳遞到上一層的父元素;

可以理解為return false就等於同時調用了event.stopPropagation()和event.preventDefault()

4.實例講解

這是html代碼,在div裏面套了一個a標籤,連接到fly63前端網。

<div id="box">
<a id="box_1" href="http://www.fly63.com">fly63前端網</a>
</div>

第一種:不阻止事件冒泡和默認事件

document.getElementById('box').onclick=function(e){
console.log("1");//不阻止事件冒泡會打印1,頁面跳轉;
}

第二種:阻止默認事件

document.getElementById('box').onclick=function(e){
console.log("1");
}
document.getElementById('box_1').onclick=function(e){
e.preventDefault();//阻止默認事件
}

我們會發現阻止了默認事件,點擊a標籤頁面不會跳轉,但是會打印出1。說明e.preventDefault()只能阻止默認動作,但是冒泡仍然會發生。

第三種:阻止事件冒泡

document.getElementById('box').onclick=function(e){
console.log("1");
}
document.getElementById('box_1').onclick=function(e){
e.stopPropagation();//阻止事件冒泡
}

點擊a標籤,頁面會跳轉到fly63前端網,但是在控制台中是沒有打印“1”的。

第三種:阻止事件冒泡和默認事件

document.getElementById('box').onclick=function(e){
console.log("1");
}
document.getElementById('box_1').onclick=function(e){
e.stopPropagation();
e.preventDefault();//阻止默認事件
}

等同於

document.getElementById('box_1').onclick=function(e){
return false;
}

頁面不會跳轉,也不會打印出1。這裏return false;等於同時調用了event.stopPropagation()和event.preventDefault()。

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10211

沐鳴註冊平台官網_理解vue中計算屬性computed,以及使用場景

在vue中,計算屬性是用於自動監聽依賴值的變化,從而動態返回內容,監聽是一個過程,在監聽的值變化時,可以觸發一個回調,並做一些事情。其特點:

監測的是依賴值,依賴值不變的情況下其會直接讀取緩存進行復用,變化的情況下才會重新計算。

數據可以進行邏輯處理,減少模板中計算邏輯。

對計算屬性中的數據進行監視。

計算屬性由兩部分組成:get和set,分別用來獲取計算屬性和設置計算屬性。默認只有get,如果需要set,要自己添加。另外set設置屬性,並不是直接修改自身的值,而是修改它的依賴。

1、應用場景

很多時候我們在頁面中可能需要對一些數據進行封裝轉換,如:計算總價,或對一些變量進行拼接等等。這時候就可以用到它

2、computed和方法的區別

其時在methods里定義一個方法來封裝邏輯也是可以的,但是computed的寫法要更簡介一些,,調用起來也容易,不需要加()

computed中其時是自帶get和set訪問器的,只不過在一般在定義的時候我們不需要一一現實,而且computed是帶有緩存的,如果多次重複使用屬性的話,computed里定義的方法只會調用一次

3、案例說明

計算屬性中可以用於進行一些比較複雜的操作,比如計算總價:

<div id="app">
<span v-text="price"></span>
<input v-model="list[0].price"></input>
</div>
<script>
new Vue({
el:'#app',
data:{
list:[
{name:'香蕉',price: 6},
{name:'哈密瓜',price: 10},
{name:'蘋果',price: 5},
],
},
computed:{
price:function(){
let result=0
for(let i in this.list){
result+=Number(this.list[i].price)
}
return result
}
}
})
</script>

頁面直接显示總價格為21。在輸入框綁定list第一個元素的price值。當修改輸入框中数字時候,我們會發現總價格會自動更新。

4、計算屬性的可緩存性

<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在組件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}

計算屬性是基於它們的響應式依賴進行緩存的。只在相關響應式依賴發生改變時它們才會重新求值。這就意味着只要 message 還沒有發生改變,多次訪問 reversedMessage 計算屬性會立即返回之前的計算結果,而不必再次執行函數。

這也同樣意味着下面的計算屬性將不再更新,因為 Date.now() 不是響應式依賴:

computed: {
  now: function () {
    return Date.now()
  }
}

5、與watch進行對比

watch:監測的是屬性值, 只要屬性值發生變化,其都會觸發執行回調函數來執行一系列操作。

computed:監測的是依賴值,依賴值不變的情況下其會直接讀取緩存進行復用,變化的情況下才會重新計算。

計算屬性不能執行異步任務,計算屬性必須同步執行,watch可執行異步任務,遇到異步任務,就交給偵聽屬性

watch也可以檢測computed屬性

總結

計算屬性適合用在模板渲染中,某個值是依賴了其它的響應式對象甚至是計算屬性計算而來;而偵聽屬性適用於觀測某個值的變化去完成一段複雜的業務邏輯。

computed能做的,watch都能做,反之則不行

能用computed的盡量用computed

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10212

沐鳴總代平台_JavaScript: 數組reduce實例方法

對比map、 forEach、 filter 等數組方法,reduce比它們更強。

一、 reduce定義和用法

reduce() 方法接收一個函數作為累加器,數組中的每個值(從左到右)開始縮減,最終計算為一個值。

reduce() 可以作為一個高階函數,用於函數的 compose。

注意: reduce() 對於空數組是不會執行回調函數的。

語法:

array.reduce(function(prev, cur, index, arr), init)

  • prev (上一次調用回調返回的值,或者是提供的初始值(initialValue))
  • cur (數組中當前被處理的元素)
  • index (當前元素在數組中的索引)
  • arr (調用的數組)
  • init (傳遞給函數的初始值)

二、reduce瀏覽器支持情況

三、reduce累加

帶初始值

var arr = [1,2,3,4]
var sum = arr.reduce((pre, item) => {
    return pre + item
}, 10)
console.log(sum) // 20

不帶初始值

var arr = [1,2,3,4]
var sum = arr.reduce((pre, item) => {
    return pre + item
},)
console.log(sum) // 10

四、reduce數組去重

var arr = [1,2,3,3,2,1,4]
arr.reduce((acc, cur) => {
  if (!(acc.includes(cur))) {
    acc.push(cur)
  }
  return acc
}, [])
// [1, 2, 3, 4]

五、reduce求數組項最大值

var arr = [1, 2, 3, 4];
arr.reduce((prev, cur) => {
    return Math.max(prev,cur);
});
//4

六、reduce將二維數組轉為一維數組

var arr = [[1,2], [3,4], [5,6]]
arr.reduce((acc, cur) => {
  return acc.concat(cur)
}, [])
// [1,2,3,4,5,6]

七、reduce對象里的屬性求和

var arr = [
    {subject: 'Math', score: 90},
    {subject: 'Chinese', score: 90},
    {subject: 'English', score: 100}
]
arr.reduce((pre, cur) => {
    return cur.score + pre
}, 0)
//280

八、reduce計算數組中每個元素出現的個數

var arr = [1, 2,3,3,2,1,2,1]
arr.reduce((acc, cur) => {
  if (!(cur in acc)) {
    acc[cur] = 1
  } else {
    acc[cur] += 1
  }
  return acc
}, {})
//{1: 3, 2: 3, 3: 2}

九、reduce按屬性給數組分類

var arr = [
    {subject: 'Math', score: 90},
    {subject: 'Chinese', score: 90},
    {subject: 'English', score: 100},
    {subject: 'Math', score: 80},
    {subject: 'Chinese', score: 95}
];
arr.reduce((acc, cur) => {
  if (!acc[cur.type]) {
    acc[cur.type] = [];
  }
  acc[cur.type].push(cur)
  return acc
}, {})

十、reduce實現map

var arr = [1, 2, 3, 4]
Array.prototype.reduceMap = function(callback) {
  return this.reduce((acc, cur, index, array) => {
    const item = callback(cur, index, array)
    acc.push(item)
    return acc
  }, [])
}
arr.reduceMap((item, index) => {
  return item + index
})
// [1, 3, 5, 7]

十一、reduce實現forEach

var arr = [1, 2, 3, 4]
Array.prototype.reduceForEach = function(callback) {
  this.reduce((acc, cur, index, array) => {
    callback(cur, index, array)
  }, [])
}

arr.reduceForEach((item, index, array) => {
  console.log(item, index)
})
// 1234
// 0123

十二、reduce實現filter

var arr = [1, 2, 3, 4]
Array.prototype.reduceFilter = function (callback) {
   return this.reduce((acc, cur, index, array) => {
    if (callback(cur, index, array)) {
      acc.push(cur)
    }
    return acc
  }, [])
}
arr.reduceFilter(item => item % 2 == 0) // 過濾出偶數項。
// [2, 4]

十三、reduce實現find

var arr = [1, 2, 3, 4]
var obj = [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }]
Array.prototype.reduceFind = function (callback) {
  return this.reduce((acc, cur, index, array) => {
    if (callback(cur, index, array)) {
      if (acc instanceof Array && acc.length == 0) {
        acc = cur
      }
    }    
    if ((index == array.length - 1) && acc instanceof Array && acc.length == 0) {
      acc = undefined
    }
    return acc
  }, [])
}
arr.reduceFind(item => item % 2 == 0) // 2
obj.reduceFind(item => item.a % 2 == 0) // {a: 2}
obj.reduceFind(item => item.a % 9 == 0) // undefined

碰到數組複雜操作的時候,就是reduce大顯身手的時候。深入研究reduce的用法,對開發大有裨益。

來自:https://segmentfault.com/a/1190000039774558

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10209

沐鳴娛樂_ES10(2019)新特性:Array.flat()和Array.flatMap()、String.trimStart()和String.trimEnd()等

2019年1月末的時候,ECMA TC39終於確定了ES2019版JavaScript的新增內容,ES2019 將會增加arrays, objects, strings, symbols, try/catch 和 jsON 等方面的特徵。

ES10新特性(2019)

行分隔符(U + 2028)和段分隔符(U + 2029)符號現在允許在字符串文字中,與jsON匹配

更加友好的 JSON.stringify

新增了Array的flat()方法和flatMap()方法

新增了String的trimStart()方法和trimEnd()方法

Object.fromEntries()

Symbol.prototype.description

String.prototype.matchAll

Function.prototype.toString()現在返回精確字符,包括空格和註釋

簡化try {} catch {},修改 catch 綁定

新的基本數據類型BigInt

globalThis

import()

Legacy RegEx

私有的實例方法和訪問器

1.行分隔符(U + 2028)和段分隔符(U + 2029)符號現在允許在字符串文字中,與JSON匹配

以前,這些符號在字符串文字中被視為行終止符,因此使用它們會導致SyntaxError異常。

2.更加友好的 JSON.stringify

如果輸入 Unicode 格式但是超出範圍的字符,在原先JSON.stringify返回格式錯誤的Unicode字符串。現在實現了一個改變JSON.stringify的第3階段提案,因此它為其輸出轉義序列,使其成為有效Unicode(並以UTF-8表示)

3.新增了Array的flat()方法和flatMap()方法

flat()和flatMap()本質上就是是歸納(reduce) 與 合併(concat)的操作。

Array.prototype.flat()

flat() 方法會按照一個可指定的深度遞歸遍曆數組,並將所有元素與遍歷到的子數組中的元素合併為一個新數組返回。

flat()方法最基本的作用就是數組降維

var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
 
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
 
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
 
//使用 Infinity 作為深度,展開任意深度的嵌套數組
arr3.flat(Infinity);
// [1, 2, 3, 4, 5, 6]

其次,還可以利用flat()方法的特性來去除數組的空項其次,還可以利用flat()方法的特性來去除數組的空項 var arr4 = [1, 2, , 4, 5]; arr4.flat(); // [1, 2, 4, 5]

var arr1 = [1, 2, 3, 4];
 
arr1.map(x => [x * 2]);
// [[2], [4], [6], [8]]
 
arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]
 
// 只會將 flatMap 中的函數返回的數組 “壓平” 一層
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]


4.新增了String的trimStart()方法和trimEnd()方法

新增的這兩個方法很好理解,分別去除字符串首尾空白字符,這裏就不用例子說聲明了。

5.Object.fromEntries()

Object.entries()方法的作用是返回一個給定對象自身可枚舉屬性的鍵值對數組,其排列與使用 for…in 循環遍歷該對象時返回的順序一致(區別在於 for-in 循環也枚舉原型鏈中的屬性)。

而Object.fromEntries() 則是 Object.entries() 的反轉。

Object.fromEntries() 函數傳入一個鍵值對的列表,並返回一個帶有這些鍵值對的新對象。這個迭代參數應該是一個能夠實現@iterator方法的的對象,返回一個迭代器對象。它生成一個具有兩個元素的類似數組的對象,第一個元素是將用作屬性鍵的值,第二個元素是與該屬性鍵關聯的值。

通過 Object.fromEntries, 可以將 Map 轉化為 Object:

const sym = Symbol('The description');

以前,訪問描述的唯一方法是將符號轉換為字符串:

assert.equal(String(sym), 'Symbol(The description)');

現在引入了getter Symbol.prototype.description以直接訪問描述:

assert.equal(sym.description, 'The description');


7.String.prototype.matchAll

matchAll() 方法返回一個包含所有匹配正則表達式及分組捕獲結果的迭代器。 在 matchAll 出現之前,通過在循環中調用regexp.exec來獲取所有匹配項信息(regexp需使用/g標誌:

const regexp = RegExp('foo*','g');
const str = 'table football, foosball';
 
while ((matches = regexp.exec(str)) !== null) {
  console.log(`Found ${matches[0]}. Next starts at ${regexp.lastIndex}.`);
  // expected output: "Found foo. Next starts at 9."
  // expected output: "Found foo. Next starts at 19."
}

如果使用matchAll ,就可以不必使用while循環加exec方式(且正則表達式需使用/g標誌)。使用matchAll 會得到一個迭代器的返回值,配合 for…of, array spread, or Array.from() 可以更方便實現功能:

const regexp = RegExp('foo*','g');
const str = 'table football, foosball';
let matches = str.matchAll(regexp);
 
for (const match of matches) {
  console.log(match);
}
// Array [ "foo" ]
// Array [ "foo" ]
 
// matches iterator is exhausted after the for..of iteration
// Call matchAll again to create a new iterator
matches = str.matchAll(regexp);
 
Array.from(matches, m => m[0]);
// Array [ "foo", "foo" ]


8.Function.prototype.toString()現在返回精確字符,包括空格和註釋

function /* comment */ foo /* another comment */() {}
 
// 之前不會打印註釋部分
console.log(foo.toString()); // function foo(){}
 
// ES2019 會把註釋一同打印
console.log(foo.toString()); // function /* comment */ foo /* another comment */ (){}
 
// 箭頭函數
const bar /* comment */ = /* another comment */ () => {};
 
console.log(bar.toString()); // () => {}


9.修改 catch 綁定

在 ES10 之前,我們必須通過語法為 catch 子句綁定異常變量,無論是否有必要。很多時候 catch 塊是多餘的。 ES10 提案使我們能夠簡單的把變量省略掉。

不算大的改動。之前是

try {} catch(e) {} 

現在是

try {} catch {}


10.新的基本數據類型BigInt

現在的基本數據類型(值類型)不止5種(ES6之後是六種)了哦!加上BigInt一共有七種基本數據類型,分別是: String、Number、Boolean、Null、Undefined、Symbol、BigInt

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10197

沐鳴網址_ES7(2016)新特性:Array.prototype.includes()、指數操作符

ES7(2016)新增了兩個新特性:

1. 數組includes()方法,用來判斷一個數組是否包含一個指定的值,根據情況,如果包含則返回true,否則返回false。

2. a ** b指數運算符,它與 Math.pow(a, b)相同。

1.Array.prototype.includes()

includes() 函數用來判斷一個數組是否包含一個指定的值,如果包含則返回 true,否則返回false。

includes 函數與 indexOf 函數很相似,下面兩個表達式是等價的:

arr.include(x)
//等價於
arr.indexOf(x)>=0

接下來我們來判斷数字中是否包含某個元素:

在ES7之前的做法

使用indexOf()驗證數組中是否存在某個元素,這時需要根據返回值是否為-1來判斷:

let arr = ['react', 'angular', 'vue'];
if (arr.indexOf('react') !== -1){
    console.log('react存在');
}

使用ES7的includes()

使用includes()驗證數組中是否存在某個元素,這樣更加直觀簡單:

let arr = ['react', 'angular', 'vue'];
if (arr.includes('react')){
    console.log('react存在');
}

2.指數操作符

在ES7中引入了指數運算符**,**具有與Math.pow(..)等效的計算結果。

不使用指數操作符

使用自定義的遞歸函數calculateExponent或者Math.pow()進行指數運算:

function calculateExponent(base, exponent){
    if (exponent === 1){
        return base;
    }else{
        return base * calculateExponent(base, exponent - 1);
    }
}
console.log(calculateExponent(2, 10)); // 輸出1024
console.log(Math.pow(2, 10)); // 輸出1024

使用指數操作符

使用指數運算符**,就像+、-等操作符一樣:

console.log(2**10);// 輸出1024

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10193

沐鳴平台網址_使用Nuxt生成靜態網站

靜態網站如今再次流行起來了。信息站和品牌宣傳站不再需要使用WordPress之類的內容管理系統來動態更新。

使用靜態網站生成器,您可以從無源CMS,API等動態源以及Markdown文件等文件中獲取內容。

Nuxt是基於vue.js的出色的靜態網站生成器,可輕鬆用於構建靜態網站。使用Nuxt,從動態內容構建靜態網站所需要做的就是創建模板,以從API和Markdown文件等動態源動態显示內容。然後,在Nuxt配置文件中,我們靜態定義路由,以便它可以通過相同的路由將內容生成為靜態文件。

在本文中,我們將使用Nuxt構建新聞網站,並將使用https://newsapi.org/的News API 作為內容。您必須先了解vue.js,然後才能使用Nuxt建立網站,因為Nuxt是基於Vue.js的框架。

首先,我們在News API網站上註冊API密鑰。如果我們只想獲取頭條新聞,它是免費的。我們開始來使用Nuxt CLI構建網站。我們通過鍵入以下命令來運行:

npx create-nuxt-app news-website

這將在news-website文件夾中創建初始項目文件。運行該嚮導時,我們不為服務器端框架選擇任何內容,不為UI框架選擇任何內容,不為測試框架選擇任何內容,不為Nuxt模式選擇通用文件,最後根據您的情況選擇是否包含Axios請求庫,使用lint進行代碼整理和prettify進行代碼美化。

接下來,我們需要安裝一些軟件包。我們需要@nuxtjs/dotenv用於在本地讀取環境變量的程序包和country-list用於在我們的網站上獲取國家列表的庫。要安裝它們,我們運行:

npm i @nuxtjs/dotenv country-list

現在我們可以開始建立我們的網站了。在default.vue文件中,我們將現有代碼替換為:

<template>  
  <div>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <nuxt-link class="navbar-brand" to="/">News Website</nuxt-link>
      <button
        class="navbar-toggler"
        type="button"
        data-toggle="collapse"
        data-target="#navbarSupportedContent"
        aria-controls="navbarSupportedContent"
        aria-expanded="false"
        aria-label="Toggle navigation"
      >
        <span class="navbar-toggler-icon"></span>
      </button> <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item active">
            <nuxt-link class="nav-link" to="/">Home</nuxt-link>
          </li>
          <li class="nav-item dropdown">
            <a
              class="nav-link dropdown-toggle"
              href="#"
              id="navbarDropdown"
              role="button"
              data-toggle="dropdown"
              aria-haspopup="true"
              aria-expanded="false"
            >Headliny by Country</a>
            <div class="dropdown-menu" aria-labelledby="navbarDropdown">
              <nuxt-link
                class="dropdown-item"
                :to="`/headlines/${c.code}`"
                v-for="(c, i) of countries"
                :key="i"
              >{{c.name}}</nuxt-link>
            </div>
          </li>
        </ul>
      </div>
    </nav>
    <nuxt />
  </div>
</template>

<script>
import { requestsMixin } from "~/mixins/requestsMixin";
const { getData } = require("country-list");

export default {
  mixins: [requestsMixin],
  data() {
    return {
      countries: getData()
    };
  }
};
</script>

<style>
.bg-light {
  background-color: lightcoral !important;
}
</style>

這是用於定義我們網站布局的文件。我們在此處添加了Bootstrap導航欄。該欄包含主頁鏈接和國家列表的下拉列表。這些nuxt-link組件都是指向頁面的鏈接,這些頁面用於在生成靜態文件時獲取國家/地區的標題。可以通過調用函數從該部分的country-list包中獲取國家。在本節中,我們通過覆蓋類的默認顏色來更改導航欄的背景顏色。本部分底部的組件將显示我們的內容。

scriptgetDatastyle.bg-lightnuxttemplate

接下來,我們創建一個mixins文件夾並創建一個名為requestsMixin.jsfile的文件。在其中,我們添加:

const APIURL = "https://newsapi.org/v2";  
const axios = require("axios");
export const requestsMixin = {  
  methods: {  
    getHeadlines(country) {  
      return axios.get(  
        `${APIURL}/top-headlines?country=${country}&apiKey=${process.env.VUE_APP_APIKEY}`  
      );  
    }, getEverything(keyword) {  
      return axios.get(  
        `${APIURL}/everything?q=${keyword}&apiKey=${process.env.VUE_APP_APIKEY}`  
      );  
    }  
  }  
};

該文件包含用於從News API獲取按國家/地區和關鍵字作為標題的代碼。

然後,在pages文件夾中,我們創建headlines文件夾,然後在文件headlines夾中,創建_countryCode.vue文件。在文件中,我們添加:

<template>  
  <div class="container">  
    <h1 class="text-center">Headlines in {{getCountryName()}}</h1>  
    <div v-if="headlines.length > 0">  
      <div class="card" v-for="(h, i) of headlines" :key="i">  
        <div class="card-body">  
          <h5 class="card-title">{{h.title}}</h5>  
          <p class="card-text">{{h.content}}</p>  
          <button class="btn btn-primary" :href="h.url" target="_blank" variant="primary">Read</button>  
        </div>  
        <img :src="h.urlToImage" class="card-img-bottom" />  
      </div>  
    </div>  
    <div v-else>  
      <h2 class="text-center">No headlines found.</h2>  
    </div>  
  </div>  
</template>

<script>  
import { requestsMixin } from "~/mixins/requestsMixin";  
const { getData } = require("country-list");

export default {  
  mixins: [requestsMixin],  
  data() {  
    return {  
      headlines: [],  
      countries: getData()  
    };  
  },  
  beforeMount() {  
    this.getHeadlinesByCountry();  
  },  
  methods: {  
    async getHeadlinesByCountry() {  
      this.country = this.$route.params.countryCode;  
      const { data } = await this.getHeadlines(this.country);  
      this.headlines = data.articles;  
    }, 

    getCountryName() {  
      const country = this.countries.find(  
        c => c.code == this.$route.params.countryCode  
      );  
      return country ? country.name : "";  
    }  
  }  
};  
</script>

在該文件中,我們接受route參數,countryCode然後從該位置調用我們之前製作並包含在此組件中的this.getHeadlines函數,requestsMixin以從News API獲取標題。然後結果將显示在該template部分的Bootstrap卡中。在模板中,我們通過從country-list數據中找到國家名稱來獲得國家名稱。如果找不到標題,我們會显示一條消息。通常,如果要製作一個接受URL參數的頁面,則必須製作一個帶有下劃線作為第一個字符以及所需URL參數的變量名的文件。因此,在此示例中,_countryCode.vue中我們將countryCode使用該參數this.$route.params.countryCode。

接下來,index.vue在pages文件夾中,將現有代碼替換為:

<template>  
  <div class="container">  
    <h1 class="text-center">Home</h1>  
    <div class="card" v-for="(h, i) of headlines" :key="i">  
      <div class="card-body">  
        <h5 class="card-title">{{h.title}}</h5>  
        <p class="card-text">{{h.content}}</p>  
        <button class="btn btn-primary" :href="h.url" target="_blank" variant="primary">Read</button>  
      </div>  
      <img :src="h.urlToImage" class="card-img-bottom" />  
    </div>  
  </div>  
</template>  
<script>  
import { requestsMixin } from "~/mixins/requestsMixin";  
const { getData } = require("country-list");

export default {  
  mixins: [requestsMixin],  
  data() {  
    return {  
      headlines: []  
    };  
  },  
  beforeMount() {  
    this.getHeadlinesByCountry();  
  },  
  methods: {  
    async getHeadlinesByCountry() {  
      const { data } = await this.getHeadlines("us");  
      this.headlines = data.articles;  
    }  
  }  
};  
</script>

<style>  
</style>

這使我們可以在主頁上显示美國的標題。它的工作原理與_countryCode.vue頁面相似,不同之處在於,我們僅獲得美國的頭條新聞,而不接受URL參數來根據URL獲得來自不同國家/地區的頭條新聞。

接下來,我們create-env.js在項目的根文件夾中創建一個,並添加以下內容:

const fs = require('fs')  
fs.writeFileSync('./.env', `API_KEY=${process.env.API_KEY}`)

這使我們可以部署到Netlify,因為我們需要.env根據輸入的環境變量動態創建文件。另外,我們.env手動創建文件,然後將API_KEY鍵作為鍵,將News API API鍵作為值。

接下來的nuxt.config.js,我們將現有代碼替換為:

require("dotenv").config();  
const { getData } = require("country-list");

export default {  
  mode: "universal",  
  /*  
   ** Headers of the page  
   */  
  head: {  
    title: "News Website",  
    meta: [  
      { charset: "utf-8" },  
      { name: "viewport", content: "width=device-width, initial-scale=1" },  
      {  
        hid: "description",  
        name: "description",  
        content: process.env.npm_package_description || ""  
      }  
    ],  
    link: [  
      { rel: "icon", type: "image/x-icon", href: "/favicon.ico" },  
      {  
        rel: "stylesheet",  
        href:  
         "https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"  
      }  
    ],  
    script: [  
      { src: "https://code.jquery.com/jquery-3.3.1.slim.min.js" },  
      {  
        src:  
          "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"  
      },  
      {  
        src:  
          "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"  
      }  
    ]  
  },  
  /*  
   ** Customize the progress-bar color  
   */  
  loading: { color: "#fff" },  
  /*  
   ** Global CSS  
   */  
  css: [],  
  /*  
   ** Plugins to load before mounting the App  
   */  
  plugins: [],  
  /*  
   ** Nuxt.js dev-modules  
   */  
  buildModules: [],  
  /*  
   ** Nuxt.js modules  
   */  
  modules: [  
    // Doc: https://axios.nuxtjs.org/usage    
    "@nuxtjs/axios",  
    "@nuxtjs/dotenv"  
  ],  
  /*  
   ** Axios module configuration  
   ** See https://axios.nuxtjs.org/options
   */  
  axios: {},  
  /*  
   ** Build configuration  
   */  
  build: {  
    /*  
     ** You can extend webpack config here  
     */  
    extend(config, ctx) {}  
  },  
  env: {  
    apiKey: process.env.API_KEY || ""  
  },  
  router: {  
    routes: [  
      {  
        name: "index",  
        path: "/",  
        component: "pages/index.vue"  
      },  
      {  
        name: "headlines-id",  
        path: "/headlines/:countryCode?",  
        component: "pages/headlines/_countryCode.vue"  
      }  
    ]  
  },  
  generate: {  
    routes() {  
      return getData().map(d => `headlines/${d.code}`);  
    }  
  }  
};

在head對象中,我們更改了title以便显示所需的標題而不是默認標題。在link中,我們添加了Bootstrap CSS,在script中,我們添加了Bootstrap JavaScript文件和jQuery,它們是Bootstrap的依賴項。由於我們要構建靜態站點,因此不能使用BootstrapVue,因為它是動態的。我們不希望在生成的輸出中使用任何動態JavaScript,因此我們必須使用普通的Bootstrap。在modules中,我們添加”@nuxtjs/dotenv”了從.env創建到Nuxt應用程序的文件中讀取環境變量的功能。我們還進行了添加,require(“dotenv”).config();以便我們可以將process.env.API_KEY其添加到此配置文件中。我們必須這樣做,所以我們不必檢入.env文件。在裏面env部分,我們有了apiKey: process.env.API_KEY || “”,這是通過使用讀取.env文件中的API KEY而獲得的dotenv。

在router中,我們定義了動態路由,以便當用戶單擊具有給定URL的鏈接或單擊具有此類URL的鏈接時可以查看它們。Nuxt還使用這些路由來生成靜態文件。在generate中,我們定義了Nuxt遍歷的路徑,以生成靜態網站的靜態文件。在這種情況下,路由數組由我們之前創建的標題頁面的路由組成。它將遍歷它們以獲取它們的數據,然後渲染它們並從渲染的結果生成文件。文件夾結構將與路線相對應。因此,由於我們path是/headlines/:countryCode,因此生成的工件將具有該headlines文件夾以及所有國家/地區代碼作為子文件夾的名稱,並且在每個文件夾內將有一個index.html 與呈現的內容。

現在,我們準備將我們的網站部署到Netlify。通過轉到https://www.netlify.com/創建一個Netlify帳戶。免費計劃將滿足我們的需求。然後將代碼提交到託管在GitHub,Gitlab或Bitbucket上的Git存儲庫。然後,當您登錄Netlify時,單擊Git中的New site。從那裡,您可以添加託管在其中一項服務中的Git存儲庫。然後,當要求您輸入Build Command時,輸入node ./create-env.js && npm run generate,發布目錄將為dist。

之後,將.env文件中的API密鑰輸入到網站設置的“環境變量”部分,您可以通過單擊“構建和部署”菜單上的“環境”鏈接來進入。輸入API_KEY作為密鑰,然後輸入News API API密鑰作為值。然後單擊保存按鈕。

一旦將所有內容提交並推送到由GitHub,Gitlab或Bitbucket託管的Git存儲庫中,Netlify將自動構建和部署。

原文鏈接:https://dev.to/aumayeung/generate-static-websites-with-nuxt-1ia1

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/7177

沐鳴娛樂_探索小程序實現

隨着小程序的發展與功能的逐步完善,越來越多的產品需要小程序與 APP 的功能能有一些共性,社區跨平台的解決方案越來越多,比如 taro 等為代表的把一套代碼編譯成多端運行的機制,本文會使用 Swift 作為原生語言,在 iOS 應用上運行一個小程序 Demo, 使用 Android && react Native 也可以採用同樣的思路實現。

相關代碼倉庫: https://github.com/taixw2/rmini

編譯層

編譯的目的是為了抹平小程序的與 H5 的差異,利用 vue 實現數據綁定,利用 Web Component 實現小程序的組件功能。

從官網文檔中可以看出來,運行一個小程序需要框架(數據綁定渲染)、組件(小程序渲染單元)、api(與原始交互的能力)。

框架實現

轉換成單頁應用(一種可行的方案)

把所有頁面打包成一個 js, 再由 js 管理所有的路由和狀態,這種方案適合在 web 端運行,並且是單引擎的方案,在模擬原生的右滑返回等效果也會不盡人意。

轉換成多頁面

眾所周知,小程序是一個雙引擎的框架,上面的方案顯然不能達到要求, 雙引擎的特點是在運行 JavaScript 的黑盒子中,無法訪問到 DOM && BOM 等。將所有的邏輯代碼在原生的 JavaScriptCore 中運行,WebView 中的 Javascript 引擎負責數據綁定,需要解決的難點是 JavascriptCore 中的 setData 怎麼通知 WebView 渲染, WebView 的事件怎麼執行 JavascriptCore,接着往下看。

抹平WXML

wxml 是一種類 html 標記語言,他負責所有的渲染規則,包括條件渲染、列表渲染、數據綁定等,與其再實現一種框架,還不如直接利用 vue 實現同樣的功能,再利用各種轉換庫將 wxml 中的事件轉換成 Vue 能夠識別的事件,如利用 post-html 可以做到如下的轉換:

每一個事件綁定的方法全都在原生的 JSContext 中運行,所以此時的事件只需要傳遞給 JSContext 的作用。

抹平WXSS

wxss 作為小程序的樣式語言,其餘 css 的主要區別就是多了一個 rpx 單位,以下是官網的換算表:


根據上表可得知, rpx = (750 / 屏幕寬度) * px ;

在傳統的移動端頁面,我們的高清方案,一般需要獲取 dpr, 然後修改動態修改 viewport 和 html 上的 font-size,但是小程序的代碼因為是放在了設備本地,所以可以在下載小程序頁面之後,我們還有一次編譯機會,這時就可以把 rpx 根據當前設備的屏幕寬度替換成對應的 px。

還有一個 @import ,則利用 scss 或 less 就可以合併到同一個 css 文件中,

而全局樣式則可以在構建 WXML 的時候再植入進入

抹平組件

組件具有獨特的功能和自己的渲染規則,比如 scroll-view 具有 scroll-x 和 scroll-y 等屬性控制滾動條。在 HTML5 中有一個重大的功能 web-component ,它能夠自定義 html 元素,並且能夠監控屬性的變化,非常適合實現小程序組件。如:(使用了 lit-element 框架)

這裏用了 lit-element 這個框架,能夠簡化一些操作。

抹平 Page 和 App

App 負責整個應用的生命周期以及存一些全局的數據, getApp 能獲取到 app 的信息。 所以類似的結構可能是這樣的:

getApp 能夠直接訪問到內部對象,並且在最頂層聲明,這樣每一個的地方都能訪問到 getApp。

初始化一個頁面都需要是實例化 PageClass, 即使再次進入(不是返回到這個頁面)這個頁面頁需要再次重新實例化,每次實例化都需要關聯一個 webviewId, 這個 ID 與原始的 webview 關聯,這樣每個 PageClass 中的 setData 都能找到對應的 webview 進行再次渲染,所以對應的代碼可能是這樣的:

抹平 API

通過 API 能夠直接調用原生的功能,比如 wx.request , 如果直接在 webview 中的 JSContext 中運行的話,則可能存在跨域,但是放在原生就不會存在這個問題。

實現JSContext 調用原生代碼的功能,需要給 JSContext 中植入一個 JSBridge,如: JSBridge.invoke 和 JSBridge.on , invoke 負責同步任務,on 負責異步任務,原生再利用反射(原生的反射真麻煩)調用對應的原生方法,原生可以利用 while(true) 掛起 JSContext,既可以達到同步和異步的方法。

打包 Javascript

Javascript 代碼打包后被放在 JavascriptCore 中運行,唯一與 Webview 中的 JSContext 打交道的只有 setData , 先看一下打包流程:

  1. 利用 App.json 構建入口文件
  2. 利用 rollup 等工具將所有 Javascript 打包成一個文件(目前沒有分包)

打包流程及其簡單,接下來看一下兩個 Javascript 引擎的交互過程。

打通 JSContext 到 WebView JavascriptCore

每次進入一個頁面的時候都需要為這個頁面的 webview 分配一個 id, 這個 id 至關重要,作為 native 與 JSContext (原生運行 javascript 的上下文對象) 與 webview 交互的唯一標識,JSContext 中需要實例化一個新的 PageClass 關聯這個 id, native 中通過 id 保留 webview 的引用。在 JSContext 中植入一個 JSBridge 用於與原生交互,如: JSBridge.setData(webviewId, appId, data), 當 JSBridge 的 setData 被調用后,通過 appId + webviewId 就能找到對應的 webview, 再將 setData 傳入 webview 中,在 Vue 接收到 data 後進行渲染, 整個過程如圖:

打通 Webview JavascriptCore 到 JSContext

有了前面的鋪墊,接下來再看 webview 如何調用 JSContext 的方法, Webview 唯一能與 JSContext 交互的方式只有事件,事件觸發后,需要通過某種方式觸發 JSContext 中的方法,最後調用 setData 再返回來重新渲染 webview。

webview 中綁定的方法名眾多,如: bindtap=”a”, bindtap=”b”, bindtap=”c” 等,但是可以通過 “抹平 WXML” 的時候最終只保留一個出口,如:

v-on:click=”callClick(‘a’, $event)” 等,這樣 vue 中的 method 只需要實現對應的幾個事件便可:

結尾

利用原生作為橋樑,在兩個引擎之間通信,webview 中的 JSContext 負責接收渲染通知,以及發送事件到 Native 的 JSContext 中,JSContext 獨立運行,所以既訪問不到 window 對象,也訪問不到 document 對象。

原文 http://www.cnblogs.com/Amy-so/p/12152225.html

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/7192