鑰匙要點
- >利用node.js構建一個服務器,該服務器擴展了現有功能以包括Wi-Fi網絡信息,從而使儀表板更全面。 >實現ractive.js,以更有效地管理客戶端來管理實時更新和交互,從而通過動態內容更新來增強用戶體驗。
- > process wi-fi命令在服務器上輸出以提取和顯示可用的網絡詳細信息,確保數據結構並準備好客戶端使用。
- >設計和使用帶有ractive.js的HTML模板顯示Wi-Fi網絡數據,從而啟用了可以提高導航和可用性的交互式和響應性的網絡元素。
- > >通過添加新的端點並有效地處理Ajax來擴展儀表板的功能,以確保儀表板保持可擴展且可維護。

在服務器端,我們將重複使用並擴展為電池組創建的內容。在本教程中,我們將專注於Ubuntu,但是服務器代碼的結構是使您只需要編寫幾個適配器來支持Mac或Windows的機器。
> bash命令首先,我們通過為新端點添加命令和回調來擴展原始配置方法。有必要重命名以防止與電池小部件的命令發生衝突。
<span>function switchConfigForCurrentOS () { </span> <span>switch(process.platform) { </span> <span>case 'linux': </span> <span>return { </span> <span>batteryCommand: 'upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep -E "state|time to empty|to full|percentage"', </span> <span>batteryProcessFunction: processBatteryStdoutForLinux, </span> <span>wifiCommand: 'iwlist wlan0 scanning | egrep "Cell |Address|Channel|Frequency|Encryption|Quality|Signal level|Last beacon|Mode|Group Cipher|Pairwise Ciphers|Authentication Suites|ESSID"', </span> <span>wifiProcessFunction: processWifiStdoutForLinux </span> <span>}; </span> <span>case 'darwin': //MAc OsX </span> <span>... </span> <span>} </span> <span>}</span>處理命令輸出
我們處理命令輸出的方式確實與已經為電池所做的事情相似。我們逐行瀏覽輸出,然後對其進行處理以從讀取中提取有意義的參數。但是在這種情況下,我們會收到有關項目列表的閱讀,而不是單個項目的列表!因此,我們需要確定何時在輸出中真正啟動新項目,並為每個項目創建一個新對象。然後,我們將過濾有效的行,將讀取的屬性添加到當前項目中。
在詳細查看ProcessWifilineForlinux中發生的情況之前,我要重點介紹幾點:<span>function processWifiStdoutForLinux(stdout) { </span> <span>var networks = {}; </span> <span>var net_cell = ""; </span> <span>var cell = {}; </span> stdout<span>.split('\n').map(trimParam).forEach(function (line) { </span> <span>if (line.length > 0) { </span> <span>//check if the line starts a new cell </span> <span>if (stringStartsWith(line, NET_CELL_PREFIX)) { </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> cell <span>= {}; </span> line <span>= line.split("-"); </span> net_cell <span>= line[0].trim(); </span> line <span>= line[1]; </span> <span>} </span> <span>//Either way, now we are sure we have a non empty line with (at least one) key-value pair </span> <span>// and that cell has been properly initialized </span> <span>processWifiLineForLinux(cell, line); </span> <span>} </span> <span>}); </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> <span>return networks; </span> <span>}</span>
- >由於我們僅在下一個啟動的描述時向哈希添加一個單元格,因此我們會錯過最終if語句(捕獲輸出中的最後一個網絡)。
- >上面的代碼假定兩個單元格無法共享相同的名稱。這是一個合理的假設,因為網絡沒有被其名稱索引(該信息由Essid字段捕獲)。它們被列出並分配了一個漸進式標識符 “ cell 0x”
- 。 >。
- 我們在存儲屬性之前要做的最後一件事是呼叫MapWifikeySforlinux,在這種情況下,它們只是返回鍵未改變的鍵。
即使處理每行的處理功能也與我們為電池創建的功能非常相似:由於每行都有一個字段名稱及其值,我們首先檢查需要以特殊方式處理的邊緣案例,以及剩餘的行我們只是將它們分開並安裝鑰匙值對。> - 我們在存儲屬性之前要做的最後一件事是呼叫MapWifikeySforlinux,在這種情況下,它們只是返回鍵未改變的鍵。
<span>function switchConfigForCurrentOS () { </span> <span>switch(process.platform) { </span> <span>case 'linux': </span> <span>return { </span> <span>batteryCommand: 'upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep -E "state|time to empty|to full|percentage"', </span> <span>batteryProcessFunction: processBatteryStdoutForLinux, </span> <span>wifiCommand: 'iwlist wlan0 scanning | egrep "Cell |Address|Channel|Frequency|Encryption|Quality|Signal level|Last beacon|Mode|Group Cipher|Pairwise Ciphers|Authentication Suites|ESSID"', </span> <span>wifiProcessFunction: processWifiStdoutForLinux </span> <span>}; </span> <span>case 'darwin': //MAc OsX </span> <span>... </span> <span>} </span> <span>}</span>>端點
由於Node的HHTP模塊和我們在上一位教程中創建的助手方法,因此將新端點添加到我們的服務器上是微不足道的。我們只需要定義要響應的路徑的正則表達式,然後在傳入請求上觸發的服務器回調中添加IF語句:
在這一點上,我們要做的就是創建一個回調,該回調將運行命令,轉換其輸出並最終將JSON結果發送給客戶端,並包含在HTTP.Createserver提供的HTTP響應中。<span>function processWifiStdoutForLinux(stdout) { </span> <span>var networks = {}; </span> <span>var net_cell = ""; </span> <span>var cell = {}; </span> stdout<span>.split('\n').map(trimParam).forEach(function (line) { </span> <span>if (line.length > 0) { </span> <span>//check if the line starts a new cell </span> <span>if (stringStartsWith(line, NET_CELL_PREFIX)) { </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> cell <span>= {}; </span> line <span>= line.split("-"); </span> net_cell <span>= line[0].trim(); </span> line <span>= line[1]; </span> <span>} </span> <span>//Either way, now we are sure we have a non empty line with (at least one) key-value pair </span> <span>// and that cell has been properly initialized </span> <span>processWifiLineForLinux(cell, line); </span> <span>} </span> <span>}); </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> <span>return networks; </span> <span>}</span>在最後一步中,請注意,我們重複了我們為電池端點方便定義的ONSUCCESS函數(對於OnError處理程序而言相同的東西)。
<span>function processWifiLineForLinux(cell<span>, line</span>) { </span> <span>var key; </span> <span>var val; </span> line <span>= line.trim(); </span> <span>if (line.length > 0) { </span> <span>switch (true) { </span> <span>case stringStartsWith(line, NET_ADDRESS_PREFIX): </span> line <span>= line.split(':'); </span> line<span>.splice(0, 1); </span> <span>//INVARIANT: Address in the format Address: DC:0B:1A:47:BA:07 </span> <span>if (line.length > 0) { </span> cell<span>[NET_ADDRESS_PREFIX] = line.join(":"); </span> <span>} </span> <span>break; </span> <span>case stringStartsWith(line, NET_QUALITY_PREFIX): </span> <span>//INVARIANT: this line must have a similar format: Quality=41/70 Signal level=-69 dBm </span> line <span>= line.split(NET_SIGNAL_PREFIX); </span> cell<span>[NET_QUALITY_PREFIX] = line[0].split("=")[1].trim(); </span> <span>if (line.length > 1) { </span> cell<span>[NET_SIGNAL_PREFIX] = line[1].split("=")[1].trim(); </span> <span>} </span> <span>break; </span> <span>case stringStartsWith(line, NET_EXTRA_PREFIX): </span> <span>//INVARIANT: this line must have a similar format: Extra: Last beacon: 1020ms ago </span> line <span>= line.split(":"); </span> <span>//we can ignore the prefix of the string </span> <span>if (line.length > 2) { </span> cell<span>[line[1].trim()] = line[2].trim(); </span> <span>} </span> <span>break; </span> <span>default: </span> <span>//INVARIANT: the field must be formatted as "key : value" </span> line <span>= line.split(":"); </span> <span>if (line.length > 1) { </span> <span>//Just stores the key-value association, so that coupling with client is reduced to the min: </span> <span>//values will be examined only on the client side </span> cell<span>[line[0].trim()] = line[1].trim(); </span> <span>} </span> <span>} </span> <span>} </span> <span>return cell; </span> <span>}</span>>客戶端
現在,讓我向您介紹此示例中最有趣的部分。我們將為Web客戶端大量使用RACTIVE.JS。這是一個輕巧,功能強大的框架,將雙向綁定(AngularJS風格)與HTML模板結合在一起 或車把)。 模板上的壓力(甚至比Angularjs更重要,而不是反應),這確實是ractive.js的標誌之一,以及其巨大的快速性能,這是由於聰明的引擎始終計算最小可能的DOM元素的結果當數據更改時刷新。 我們將在儀表板上添加兩個面板:
- 一個用於我們周圍環境中網絡列表的一個(顯示了每個項目的簡短摘要)。
- > 僅選擇網絡並顯示該Wi-Fi連接的詳細信息。
首先,讓我們討論HTML模板以顯示我們的數據,然後我們將查看如何將服務器的數據綁定到它們。
> wi-fi列表我們需要的最複雜的模板是顯示可用網絡列表的模板。第一批行只是定義容器面板,然後使用ractive.js的綁定來有條件地顯示有關服務器錯誤的圖標警告,以及一個按鈕,以暫停/簡歷服務器進行輪詢:
雙stache {{}},如鬍子和車把,是動態注入內容的標記。 ractive.js允許我們在括號內使用表達式並運行功能,只要這些功能和所使用的數據在全球範圍內可用(例如,Math. -Round)或已添加到JavaScript對象的數據字段中,模板。 括號內表達式的結果將被逃脫,因此將是純文本。但是有時您可能需要在元素中添加幾行。還有一種其他方法可以做到,但是如果您真的認為需要它,則可以使用三重速度{{{{}}}。 使用Triple-STACHE是安全的,因為腳本將被逃脫且未執行,但它比雙靜止速度慢,因此您應該盡量避免它。模板的第二部分更有趣。我們通過{{#wifinetworks:num}}迭代網絡列表,捕獲數字變量中每個項目的索引。 對於列表中的每個項目,我們添加了一個回調處理點擊(請參閱下文),並顯示其值的摘要。 請注意,關閉標籤如何不必匹配打開標籤文字:
<span>function switchConfigForCurrentOS () { </span> <span>switch(process.platform) { </span> <span>case 'linux': </span> <span>return { </span> <span>batteryCommand: 'upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep -E "state|time to empty|to full|percentage"', </span> <span>batteryProcessFunction: processBatteryStdoutForLinux, </span> <span>wifiCommand: 'iwlist wlan0 scanning | egrep "Cell |Address|Channel|Frequency|Encryption|Quality|Signal level|Last beacon|Mode|Group Cipher|Pairwise Ciphers|Authentication Suites|ESSID"', </span> <span>wifiProcessFunction: processWifiStdoutForLinux </span> <span>}; </span> <span>case 'darwin': //MAc OsX </span> <span>... </span> <span>} </span> <span>}</span>開頭是一個函數的if標籤,這將使它在關閉的函數中再次運行它。因此,我們可以使用有意義的消息對兩個標籤進行配對,只是為了維護的目的。
>選擇的Wi-Fi詳細信息
<span>function processWifiStdoutForLinux(stdout) { </span> <span>var networks = {}; </span> <span>var net_cell = ""; </span> <span>var cell = {}; </span> stdout<span>.split('\n').map(trimParam).forEach(function (line) { </span> <span>if (line.length > 0) { </span> <span>//check if the line starts a new cell </span> <span>if (stringStartsWith(line, NET_CELL_PREFIX)) { </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> cell <span>= {}; </span> line <span>= line.split("-"); </span> net_cell <span>= line[0].trim(); </span> line <span>= line[1]; </span> <span>} </span> <span>//Either way, now we are sure we have a non empty line with (at least one) key-value pair </span> <span>// and that cell has been properly initialized </span> <span>processWifiLineForLinux(cell, line); </span> <span>} </span> <span>}); </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> <span>return networks; </span> <span>}</span>網絡詳細信息的面板非常簡單:我們僅在ractive對像中為所選網絡字段分配值時才顯示它。然後,我們顯示網絡的名稱(ESSID字段),並顯示我們從服務器收到的所有鍵值對。 這是為了獲得最低的耦合,但是您當然可以對其進行修改以突出顯示某些信息或以更有意義的方式顯示它們。
> javascript
我們將設置一個民意調查的守護程序,該守護程序異步以給定的時間間隔對服務器進行查詢。每個AJAX呼叫都將提供Wi-Fi網絡的更新列表。當我們收到服務器的JSON響應時,我們要做的就是確認我們收到了成功的響應,並更新了我們在ractive對像中存儲網絡列表的字段。>設置
正如我們在上一篇文章中顯示的那樣,要將模板綁定到某些數據,我們只需要創建一個新的ractive對象,將其與模板的ID(#MeTervizTemplate)相連(下面的#MeTervizTemplate),而目標DOM元素(即節點)那將是DOM樹中模板的父 以下)。 然後,我們只需要在模板中添加所有要在ractive.data字段中使用的對像或值即可。可以使用ractive.set()對初始化(如下)或更高版本進行此操作。<span>function processWifiLineForLinux(cell<span>, line</span>) { </span> <span>var key; </span> <span>var val; </span> line <span>= line.trim(); </span> <span>if (line.length > 0) { </span> <span>switch (true) { </span> <span>case stringStartsWith(line, NET_ADDRESS_PREFIX): </span> line <span>= line.split(':'); </span> line<span>.splice(0, 1); </span> <span>//INVARIANT: Address in the format Address: DC:0B:1A:47:BA:07 </span> <span>if (line.length > 0) { </span> cell<span>[NET_ADDRESS_PREFIX] = line.join(":"); </span> <span>} </span> <span>break; </span> <span>case stringStartsWith(line, NET_QUALITY_PREFIX): </span> <span>//INVARIANT: this line must have a similar format: Quality=41/70 Signal level=-69 dBm </span> line <span>= line.split(NET_SIGNAL_PREFIX); </span> cell<span>[NET_QUALITY_PREFIX] = line[0].split("=")[1].trim(); </span> <span>if (line.length > 1) { </span> cell<span>[NET_SIGNAL_PREFIX] = line[1].split("=")[1].trim(); </span> <span>} </span> <span>break; </span> <span>case stringStartsWith(line, NET_EXTRA_PREFIX): </span> <span>//INVARIANT: this line must have a similar format: Extra: Last beacon: 1020ms ago </span> line <span>= line.split(":"); </span> <span>//we can ignore the prefix of the string </span> <span>if (line.length > 2) { </span> cell<span>[line[1].trim()] = line[2].trim(); </span> <span>} </span> <span>break; </span> <span>default: </span> <span>//INVARIANT: the field must be formatted as "key : value" </span> line <span>= line.split(":"); </span> <span>if (line.length > 1) { </span> <span>//Just stores the key-value association, so that coupling with client is reduced to the min: </span> <span>//values will be examined only on the client side </span> cell<span>[line[0].trim()] = line[1].trim(); </span> <span>} </span> <span>} </span> <span>} </span> <span>return cell; </span> <span>}</span>
我們將使用與電池相同的機制進行守護程序,並暫停/重新啟動服務器查詢。為了簡潔起見,我們不會在此處重複,但是如果您想加深此主題,您可以查看本文或GitHub存儲庫。
ajax調用我們的新守護程序要做的唯一的事情就是進行Ajax調用,然後在成功或現場信號網絡問題的情況下更新我們的數據,以防發生錯誤。
我們還應該檢查我們獲得的JSON文件是否格式化。我們不必擔心腳本注入,因為ractive.js在將其添加到DOM之前已經逃脫了字段值。 值得注意的是,jquery.getjson()方法是上述$ .ajax()方法的快捷方式,只要是: 1。您在URL中不包含'callback ='字符串(這將允許執行JSON代碼)。<span>var server = http.createServer(function (request<span>, response</span>) { </span> <span>var requestUrl = request.url; </span> <span>var filePath = BASE_URL + requestUrl; </span> <span>if (requestUrl === '/' || requestUrl === '') { </span> response<span>.writeHead(301, </span> <span>{ </span> <span>Location: BASE_URL + 'public/demo.html' </span> <span>}); </span> response<span>.end(); </span> <span>} else if (RE_BATTERY.test(requestUrl)) { </span> <span>getBatteryStatus(response, onBatteryInfo, onError); </span> <span>} else if (RE_NETWORKS.test(requestUrl)) { </span> <span>getWifiStatus(response, onWifiInfo, onError); </span> <span>} </span> <span>... </span> <span>}</span>2。您可以信任您正在調用的服務器。 由於我們不使用用戶提供的URL內容,因此會認為這不應該擔心。 但是,如果要妥協我們的服務器,那麼我們將沒有障礙來保護我們免受注射代碼的侵害。如果未設置明確的“數據類型”標頭,則jQuery將嘗試猜測響應中的內容,而惡意服務器的響應可能包含JavaScript代碼。 儘管這種可能性並不常見,但我們不能完全排除它。因此,以更多的打字價格增加了額外的保護層並不是一個壞主意。
更新儀表板
此步驟中最相關的附加組件是我們響應列表的點擊s並顯示所選網絡的詳細信息:<span>function switchConfigForCurrentOS () { </span> <span>switch(process.platform) { </span> <span>case 'linux': </span> <span>return { </span> <span>batteryCommand: 'upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep -E "state|time to empty|to full|percentage"', </span> <span>batteryProcessFunction: processBatteryStdoutForLinux, </span> <span>wifiCommand: 'iwlist wlan0 scanning | egrep "Cell |Address|Channel|Frequency|Encryption|Quality|Signal level|Last beacon|Mode|Group Cipher|Pairwise Ciphers|Authentication Suites|ESSID"', </span> <span>wifiProcessFunction: processWifiStdoutForLinux </span> <span>}; </span> <span>case 'darwin': //MAc OsX </span> <span>... </span> <span>} </span> <span>}</span>為此,我們定義了臨時事件處理程序。如上所述,當我們單擊任何列表條目時,它將被調用,然後與點擊關聯的事件將攜帶有關所選網絡本身的信息。 現在,如果我們不使用ractive.js,假設我們只使用jQuery,則必須:
- 調用一種方法,該方法將採用選定的網絡的ID;
> >使用它來找到該ID的網絡對象(可能存儲在字典中); - > 找到“選定網絡面板”的DOM元素;
- > >刪除面板內的舊DOM樹,然後迭代地創建一個新列表,顯示鍵值關聯,混合了我們的JavaScript代碼中的許多HTML字符串。
- > ractive.js將為我們照顧所有這一切,它將比我們(平均而言)的能力更好,而僅更改最小的DOM子樹。 首先,發送到點擊處理程序的事件對象將具有一個上下文字段,其中包含綁定到DOM元素的數據。換句話說,我們“免費”獲得網絡數據對象。 一旦有了,我們唯一要做的就是使用它來更新已經綁定到模板的ractive對象。 ractive.js的引擎將完成其餘的,更新DOM並顯示更改。
完成的!我們的儀表板“ Pimped”。正如我在介紹中所說的那樣,這只是一個起點。
如果您遵循的話,現在應該能夠輕鬆顯示複雜項目的列表,處理項目選擇並安全地與服務器通信。 您可以將這些技能用於許多其他任務,不一定涉及筆記本電腦的統計數據。從顯示用戶周圍的餐館清單到列舉家用電器,您可以通過網絡界面或手機進行控制。選擇是您的,沒有限制。 如果您想加深本文所涵蓋的主題,我建議您看看這些良好的資源:- 使用node.js創建電池:入門和服務器
- > 關於ractive.js
- > jQuery $ .getjson方法
- 關於stackoverflow的討論jquery.get()方法
>構建Wi-Fi儀表板的前提是什麼?您還需要在計算機上安裝NODE.JS和NPM(節點軟件包管理器)。如果您沒有安裝這些,則可以從官方Node.js網站下載它們。此外,您還需要文本編輯器來編寫代碼。您可以使用您選擇的任何文本編輯器,但是一些受歡迎的編輯器包括Visual Studio代碼,Atom和Sublime Text。
如何安裝Node-Wifi Module?
>
>如何使用node-wifi模塊連接到Wi-Fi網絡?您可以用來連接到Wi-Fi網絡的“連接”功能。您需要將對像傳遞到包含網絡的SSID和密碼的此功能。以下是一個示例: var wifi = require('node-wifi');if(err){
console.log(err);}
console.log('成功連接到網絡');
>}) >如何掃描可用的Wi-Fi網絡?
var wifi = require('node-wifi');
wifi.scan(function(erry,networks){
}
console.log(networks);
>我如何從Wi-Fi網絡中斷開連接? WiFi模塊提供了一個“斷開連接”功能,您可以使用該功能與Wi-Fi網絡斷開連接。您無需將任何參數傳遞給此功能。這是一個示例: var wifi = require('node-wifi');
var wifi = require('node-wifi');
wifi.disconnect(function(err){erra){
}
console.log('成功與網絡斷開連接');
})>如何獲得當前的Wi-Fi狀態?
wifi.getCurrentConnections(function(err,currentConnections){
(err);
}
console.log(currentConnections);
});
如何處理node-wifi模塊中的錯誤? -WIFI模塊遵循標準node.js錯誤處理模式。所有功能都將回調作為最後一個參數。此回調是一個有兩個參數的函數:一個錯誤對象和結果。如果發生錯誤,則錯誤對象將包含有關錯誤的信息。否則,錯誤對象將為null,結果將包含操作的結果。
>>
>我可以將Node-Wifi模塊與其他node.js模塊一起使用嗎?
以上是如何使用node.js和ractive.js構建Wi-Fi儀表板的詳細內容。更多資訊請關注PHP中文網其他相關文章!

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

Dreamweaver Mac版
視覺化網頁開發工具

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境