使用JS開發桌面端應用程序NW.js-3-開發問題小記
前言
因為我們的項目是2C的,而XP系統是最大的用戶量佔比,所以只能使用nw開發而不能用Electron,本文謹記開發nw過程中遇到的各種問題以及解決方案。
nw.Window.open打開新窗口不能設定指定位置
問題描述:
nw.Window.open
打開新窗口API中的參數option中position
欄位只能指定為center
或mouse
。如字面含義:center
為屏幕正中央,mouse
為滑鼠當前位置。
幾乎可以推測,nw的滑鼠右鍵菜單應該也是使用此介面,明顯是為了彈出右鍵菜單用的,除此之外幾乎沒有別的應用場景可以用到新打開窗口在滑鼠位置的。
所以,在nw的打開新窗口功能中,其實可以說 只能顯示在屏幕正中央。
nw.Window.open("http://xxcanghai.cnblogs.com/", {
//打開新窗口的參數Option
width:500,
height:500,
show:true,//是否顯示新窗口
position:"center"//新窗口顯示位置,只能使用center或mouse
}, function(new_win) {
console.log("已打開新窗口");
});
官網對position的描述:
position
{String}
benull
orcenter
ormouse
, controls where window will be put
解決方案:
一句話就是,先open一個隱藏窗口,之後在callbcal裡面再重設其位置,再顯示出來
詳細步驟:
1、重新封裝nw.Window.open方法,在原有的position欄位上擴充四個屬性,分別是 左上角,左下角,右上角,右下角,這裡使用枚舉對象來定義。
/**
* 擴充打開新窗口參數
*
* @export
* @interface openWindowOption
* @extends {NWJS_Helpers.WindowOpenOption}
*/
export interface openWindowOption extends NWJS_Helpers.WindowOpenOption {
/**
* 控制打開的新窗口的所在位置
*/
position?: "left_top" | "left_bottom" | "right_top" | "right_bottom" |
"center" | "mouse" | null;
}
/**
* 打開一個新窗口
*
* @export
* @param {string} url 新窗口的url
* @param {openWindowOption} [option] 新窗口的參數
* @param {(new_win?: NWJS_Helpers.win) => void} [callback] 打開成功後的回調函數,返回新窗口的nwWindow對象
*/
export function openWindow(url: string, option: openWindowOption = {}, callback: (new_win?: NWJS_Helpers.win) => void = function { }) {
/** 新增支持的窗口位置值,左上角,左下角,右上角,右下角 */
enum winPositionEnum {
left_top = "left_top",
left_bottom = "left_top",
right_top = "right_top",
right_bottom = "right_bottom"
};
/** 新窗口位置的4個英文字元串數組 */
const winPosiEnumArr: string = Object.keys(winPositionEnum);
}
2、雖然擴充了默認position屬性,但真正傳給nw的還得是他支持的,所以增加判斷如果使用的是新增欄位,則保存用戶自定義設置,同時改寫option參數。 除此之外,因為要統一隱藏窗口,所以還要改寫默認的show屬性,保存用戶設定的是否顯示窗口,隱藏打開窗口後,當設定完位置後再手動設置用戶初始設定的show選項。
option = Object.assign(
show: true
}, option);
/** 用戶傳過來的窗口位置參數字元串 */
var optPosi: string = "";
//如果用戶傳過來的position參數為我自定義的,則移除原有值
if (typeof option.position === "string" && winPosiEnumArr.indexOf(option.position) >= 0) {
optPosi = option.position;
delete option.position;
}
/** 用戶傳過來的窗口是否隱藏選項 */
var optShow: boolean = option.show;
option.show = false;
3、執行真正的nw.Window.open,同時在打開後的callback中根據自定義位置選項重新設定窗口位置。 最後再還原用戶原本設定的show屬性,以及觸發用戶原本傳進來的callback回調函數。
nw.Window.open(url, option, function (nwWin: NWJS_Helpers.win) {
/** 打開的隱藏窗口的寬度和高度 */
var { width, height } = nwWin;
/** 獲取第一個顯示器對象 */
const screen: NWJS_Helpers.screen = nw.Screen.screens[0];
/** 獲取顯示器的可用工作區域 */
const area = screen.work_area;
/** nw的chrome殼子的四個邊框高度 */
const border = {
left: 5 * screen.scaleFactor,
right: 5 * screen.scaleFactor,
top: 24 * screen.scaleFactor,
bottom: 5 * screen.scaleFactor
}
if (optPosi.length > 0) {
let x: number = nwWin.x;
let y: number = nwWin.y;
if (option.frame == undefined || option.frame == true) {
width += border.left + border.right;
height += border.top + border.bottom;
}
if (optPosi == winPositionEnum.left_top) {
x = 0;
y = 0;
} else if (optPosi == winPositionEnum.left_bottom) {
x = 0;
y = area.height - height;
} else if (optPosi == winPositionEnum.right_top) {
x = area.width - width;
y = 0;
} else if (optPosi == winPositionEnum.right_bottom) {
x = area.width - width;
y = area.height - height;
}
nwWin.x = Math.round(x);
nwWin.y = Math.round(y);
}
//還原用戶默認設定是否顯示窗口
if (optShow) {
nwWin.show;
}
//觸發用戶傳進來的callback
return callback.apply(this, Array.prototype.slice.call(arguments));
});
4、因為我只需要在四個角顯示,所以只擴充了4個枚舉類型,如果需要在指定坐標(x,y)顯示窗口,以上同理增加對position的對象類型{x:number,y:number}
檢測處理即可。
nw的系統API-openExternal在XP系統下無法打開本地磁碟路徑
問題描述:
nwjs官方提供了有關Shell相關的API,提供了簡單桌面相關操作的介面。之所說他簡單,是因為簡直太太太簡單甚至寒酸了,只有3個API分別是:
Shell.openExternal(uri)
打開外部鏈接;
Shell.openItem(file_path)
使用系統默認打開方式打開文件;
Shell.showItemInFolder(file_path)
和在資源管理器中顯示某文件
// Open URL with default browser.
nw.Shell.openExternal("https://github.com/nwjs/nw.js");
其中openExternal
介面可以使用系統默認瀏覽器打開鏈接,也可以使用系統資源管理器打開某本地磁碟路徑文件夾。此介面在Win7系統下沒有問題,但是在XP系統下無法打開本地磁碟路徑。
原因未知!
解決方案:做操作系統類型判斷,在XP系統下利用child_process.exec
方法,執行系統cmd命令行:start explorer + 路徑
來解決。
// 導入操作系統信息模塊
import os = require("os");
// 導入子進程模塊
import child_process = require("child_process");
/**
* 打開文件夾或用默認瀏覽器打開網頁鏈接
*
* @param {string} uri 文件夾路徑或網頁鏈接
*/
export function openExternal(uri: string): void {
if (typeof uri !== "string" || uri.length == 0) {
return null;
}
var isxp = (os.type === "Windows_NT") && (os.release.indexOf("5") >= 0);
if (isxp) {
child_process.exec("start explorer " + uri);// XP下使用explorer打開文件夾或網頁
} else {
return nw.Shell.openExternal(uri);
}
}
關於Nodejs的OS模塊:
主要提供獲取操作系統的各類信息,此處使用了os.type
和os.release
兩個方法。
os.type
方法返回一個字元串,表明操作系統的名字,"Linux"
表示在 Linux系統上,"Darwin"
表示在 macOS 系統上,"Windows_NT"
表示在 Windows系統上。
os.release
方法返回一個字元串, 指定操作系統的發行版。
關於windows系統的發行版本號:
其中:
"5.0.*"
為windows 2000系統;
"5.1.*"
為windows XP系統;
"5.2.*"
為windows XP 64位以及windows Server 2003系統
所以上述代碼中做了只要以"5"
開頭的都匹配。
?
?
關於Nodejs執行系統命令行:首先使用了Nodejs的核心模塊:child_process
子進程模塊,其中的exec
方法。對此官方對exec方法的描述是:
child_process.exec(command[, options][, callback])
command
options
< Object> 參數callback
衍生一個 shell,然後在 shell 中執行 command,且緩衝任何產生的輸出。
此處的shell在windows系統上就是cmd.exe
命令行(命令提示符)。
關於NodeJs如何在windows系統上執行.bat和.cmd批處理文件官網有更加詳細的解釋:http://nodejs.cn/api/en/child_process.html#child_process_spawning_bat_and_cmd_files_on_windows
關於windows系統內置命令 start此處使用了windows系統命令提示符的系統內置命令:start
。
他可以用來啟動各種內部命令,也可以啟動外部應用程序。此處啟動了explorer就屬於全局外部應用程序。
關於start命令的用法與解釋:(可以在命令行中使用start/?
獲得)
啟動一個單獨的窗口運行指定的程序或命令
START ["title"] [/D path] [/I] [/MIN] [/MAX][command/program] [parameters]
"title" 在窗口標題欄中顯示的標題
path 啟動目錄。新的環境將是傳遞給 cmd.exe 的原始環境,而不是當前環境
MIN 以最小化方式啟動窗口
MAX 以最大化方式啟動窗口
...省略...
在此處我使用的是用start命令啟動explorer
程序。
explorer.exe
是Windows程序管理器或者文件資源管理器,它用於管理Windows圖形殼。
簡單的來講,explorer就是我們的桌面,打開的所有磁碟或文件夾的應用程序。利用他可以實現:
1、使用系統註冊的默認方法打開某文件。
2、打開本地磁碟路徑某文件夾。
3、使用系統默認瀏覽器打開url地址。
4、以及調用任何在系統里註冊過的各類協議地址,如ftp://
或是mailto:***
等並用其註冊的應用程序打開。
而在explorer後面跟著文件夾地址即可實現使用資源管理器打開目錄,以及打開網頁鏈接
explorer的其他參數詳解:
Explorer.exe
Command-line switches that you can use to open the GUI Windows Explorer (Explorer.exe).
Options
/e
Open Windows Explorer in its default view.
(,)/root,object
Open the specified object in a window view.
/select,object
Open a window view with the specified folder, file or application selected.
/separate
Launch the explorer instance as a separate process.(This is an undocumented feature)
Node.js的child_process.exec執行命令的返回值中文亂碼
問題描述:
Nodejs的子線程模塊child_process的執行系統命名的介面exec,當命令返回所有非中文字元時都會亂碼。
如執行一個date /t
的命令顯示當前日期時間代碼:
child_process.exec("date /t", {}, function (error: Error, stdout: string, stderr: string) {
console.log(stdout);
})
正常應該返回:
?
但實際上返回了:
?
經查NodeJs默認使用了UTF-8
編碼,而中文操作系統的命令行的返迴流均為GB2312
編碼,而在流轉字元串時再使用UTF-8
解碼就導致了亂碼,而且沒辦法還原。
解決方案:
1、先通過child_process.exec
方法的option
參數中的encoding
欄位設定為"base64"
。另其返回值不包含亂碼
child_process.exec("date /t", {
encoding : "base64"//設定base64編碼
}, function (error: Error, stdout: string, stderr: string) {
console.log(stdout);
})
效果如下:
?
2、再通過一個Node編解碼模塊iconv-lite
,將返回值字元串再用base64
編碼,最後用GB2312
解碼。
import iconv = require("iconv-lite");
child_process.exec("date /t", {
encoding:"base64"
}, function (error: Error, stdout: string, stderr: string) {
console.log("解碼前:",stdout);
stdout = iconv.decode(iconv.encode(stdout, "base64"), "gb2312");
console.log("解碼後:",stdout);
})
如下圖,解決了中文亂碼問題:
?
※nodejs伺服器部署教程二
※OpenStack(企業私有雲)萬里長征第五步——虛擬機Migrate&Resize
※jsonp的原理和實現
※xtrabackup備份mysql資料庫的使用方法
TAG:達人科技 |
※純前端開發案例:用 SpreadJS 搭建信息系統軟體開發平台
※Mapbox發布新SDK幫助開發人員開發AR導航應用程序
※SuperSU開發者宣布:將停止開發所有ROOT應用
※Vue.js 2.0 漸進開發應用實踐
※在「小程序」PWA上開發WebRTC
※SpringBoot2快速開發應用系統:開篇
※谷歌發布ARCore 1.0,程序員如何開發AR應用?
※Wine 3.2開發版發布
※Wine 3.1開發版發布
※Wine 3.6開發版本發布了 支持PNG格式圖標!
※《Superhot VR》開發商:正在開發一款硬核VR體驗
※SpringMVC 開發 — 使用 Swagger 搭建介面請求頁面
※Sumerian VR開發工具向公眾開放使用
※使用C#開發Android應用之WebApp
※GENKI為任天堂Switch主機開發Type-C介面藍牙音頻發射器
※蘋果發布Siri快捷方式測試版,iOS 12開發者提前使用
※集70萬+開發者,APICloud為IoT定製了一個應用開發生態
※Windows漏洞利用開發教程Part 5:返回導向編程
※GENKI為Switch主機開發Type-C介面藍牙音頻發射器
※華為AI開發平台HiKey 970助力開發者打造各種的AI應用