使用JS开发桌面端应用程序NW.js-3-开发问题小记


前言

因为我们的项目是2C的,而XP系统是最大的用户量占比,所以只能使用nw开发而不能用Electron,本文谨记开发nw过程中遇到的各种问题以及解决方案

nw.Window.open打开新窗口不能设定指定位置

问题描述

nw.Window.open打开新窗口API中的参数option中position字段只能指定为centermouse。如字面含义: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} be null or center or mouse, controls where window will be put

nw.Window.open文档: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"开头的都匹配。
?
?

关于版本号对应详细操作系统详见:https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions

关于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程序。

关于windows系统的explorer.exe

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)

explorer.exe命令行参数详见:https://ss64.com/nt/explorer.html
Explorer.exe Command-Line Switches:http://www.infocellar.com/software/explorer-switches.htm
某篇中文介绍:http://blog.csdn.net/ycool1984/article/details/387569

所以解决方案就一句话就是:用Nodejs启动命令行,命令行启动start命令,start启动explorer.exe程序,explorer打开目录磁盘路径

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);
})

如下图,解决了中文乱码问题:
?

关于更多iconv-lite的介绍:https://www.npmjs.com/package/iconv-lite