天天看点

javascript不依赖库开发windows应用程序

        其实javascript不仅可以做网页应用,也可以不依赖任何环境开发windows应用程序。windows系统自带mshta.exe,相当于一个javascript虚拟机,我们把.html文件扩展名改成.hta文件,网页就变成了hta应用程序,双击就可以执行。当然hta可以操作本地文件数据库等,功能比html强大许多,可以开发C/S应用程序。本人之前是个后台程序员,后来我转行之后,就成了编程的业余爱好者,今天这个demo使用了javascript和少许c++,仅供大家娱乐,参考,谨慎用于生产环境。

        先给大家上几张图,看一下javascript开发的windows应用效果,然后再上代码。这个demo是个音乐播放器,功能只有扫描磁盘上的音频文件随机播放。

javascript不依赖库开发windows应用程序
javascript不依赖库开发windows应用程序
javascript不依赖库开发windows应用程序

        也有一个搜索功能,搜索随机播放列表中的歌曲,简单的正则匹配

javascript不依赖库开发windows应用程序

        测试发现占用内存和cpu很低。

javascript不依赖库开发windows应用程序

        最后楼主用c++给他做了个exe壳子,这样就能把他设置为默认播放器了,双击音频文件就能用楼主开发的播放器打开,效果如下图

javascript不依赖库开发windows应用程序

大家可能也能看出,我用的html中的<audio>标签,audio标签支持mp3、m4a、ogg等格式,大家也可以用<embed>标签,embed标签支持的格式还多,还支持wma、aac、wav等格式,但是前提是电脑安装了windows media player,楼主电脑window media player坏了,所以楼主用了<audio>标签。

javascript不依赖库开发windows应用程序

        最终软件包含三个文件,app.ico是图标,main.hta就是楼主用javascript开发的windows应用程序,双击就可以打开,main.exe是楼主给他做的壳子,用于双击打开音频文件通过命令行将文件路径传递给main.hta。下面先上main,hta的代码,里面基本上和普通javascript语法相同,只是有一些用到了ActiveX控件的对象。

<!doctype html>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=9" >
<title>小小播放器v1.0</title>
<script>
	//窗体初始化
	(function(){
		window.resizeTo(400,80);
	}())
</script>
<!-- hta应用程序特有标签 -->
<hta:application 
id=musicPlayer 
scroll=no 
innerborder=no 
icon=app.ico
contextMenu=no
selection=no
>
<style>
body{background: #ccc;text-align: center;}
button{
	font-size: 22px;
	color:#38f;
	background: #fff;
	border:1px solid #fff;
	border-radius: 10px;
	cursor: pointer;
}
input[type='text']{
	position: relative;
	bottom:4px;
	font-size: 12px;
	padding:5px;
	color:#38f;
	background: #fff;
	border:1px solid #fff;
	border-radius: 10px;
	width: 100px;
}
</style>
<body>
	<!-- 视图模块 -->
	<audio 
	style="width:100%;" 
	id="mediaPlayer" 
	onended="sys.next()" 
	autoplay="autoplay" 
	onerror="sys.error()" 
	src="">
	</audio>
	<div id="normalPanel">
		<button title="上一曲"
		onclick="sys.last()"
		>◄◄</button>
		<button title="暂停" style="border-radius: 24px;padding-bottom: 5px;"
		onclick="if(sys.playerHandel.paused){sys.playerHandel.play();this.innerText='■';this.title='暂停'}else{sys.playerHandel.pause();this.innerText='►';this.title='播放'}" 
		>■</button>
		<button title="下一曲"
		onclick="sys.next()"
		>►►</button>
		<input type="text" id="findInp" value="关键字搜索..." 
		onclick="if(this.value=='关键字搜索...'){this.value=''}" 
		/>
		<button title="搜索"
		onclick="sys.find()"
		>F</button>
		<button title="关于"
		onclick="sys.about()"
		>A</button>
	</div>
	<div id="abnormalPanel"
		style="display:none;"
	>
		<button title="关于"
		onclick="sys.about()"
		>A</button>
		<span style="padding: 5px;" id="abnormalPanelShowName"></span>
	</div>
</body>
<script>
/**
 * 小小播放器
 * @type {Object}
 */
 	this.windowsForm={
 		Text:function(str){
 			document.title=str;
 		}
 	}
 	this.commandLine=musicPlayer.commandLine.split(" ");//接收命令行参数
 	commandLine[0]="";
 	commandLine=commandLine.join(" ");
	this.sys={
		appName:"小小播放器v1.0",
		playList:[],actNum:1,totalNum:0,playerHandel:document.getElementById("mediaPlayer"),
		getPlaylist:function(){
			/*枚举音频文件取得播放列表*/
			var data=[];
			var fso=new ActiveXObject("Scripting.FileSystemObject");
			var f=fso.GetFolder("F:\\音乐");
			var fc=new Enumerator(f.files);
			var fileType=/(.mp3|.m4a|.wav)/i;
			for (; !fc.atEnd(); fc.moveNext()){
				if(fileType.test(fc.item())){
					data.push(fc.item());
				}
			}
			data.sort(function() {
			     return (0.5-Math.random());
			})
			this.playList=data;
			this.totalNum=data.length;
		},
		main:function(){//应用程序入口
			this.getPlaylist();
			this.play(1);
		},
		play:function(num){
			this.playerHandel.setAttribute("src","null");
			this.playerHandel.setAttribute("src",""+this.playList[num-1]);
			this.actNum=num;
			windowsForm.Text(this.appName+"[♫"+this.playList[num-1].name+"]");
		},
		next:function(){
			this.actNum=this.actNum==this.totalNum?1:this.actNum+1;
			this.play(this.actNum);
		},
		last:function(){
			this.actNum=this.actNum==1?this.totalNum:this.actNum-1;
			this.play(this.actNum);
		},
		find:function(){
			/*搜索歌曲*/
			var keyWd=document.getElementById("findInp").value;
			var str="<style>.musicItem{padding: 5px;margin:5px;border:1px solid #38f;background: #38f;color:#fff;font-size: 20px;border-radius:10px;cursor:pointer;}.musicItem:hover{padding: 5px;margin:5px;border:1px solid #38f;background: #fff;color:#38f;font-size: 20px;border-radius:10px;cursor:pointer;}</style><div style='position:absolute;left:0px;top:0px;width:100%;height:100%;overflow-y:auto;'>";
			for(var i=0;i<this.playList.length;i++){
				if(RegExp(keyWd,"i").test(this.playList[i].name)){
					str+="<div class='musicItem' onclick=parent.sys.play("+(i+1)+")>";
					str+=this.playList[i].name;
					str+="</div>";
				}
			}
			str+="</div>";
			var aPopup=window.createPopup();
			aPopup.document.body.innerHTML=str;
			aPopup.show(window.screenX, window.screenY+82,400,300);
		},
		about:function(){
			var str="about:";
			str+="<title>关于-小小播放器v1.0</title>";
			str+="<body style='text-align:justify;font-size:24px;background:#ccc;padding:10px;text-align:center;'><img src='app.ico'/><h1 style='font-size:36px;'>小小播放器v1.0</h1><hr><p>版权所有:© 2019 sdxjwkq01</p><p style='text-align:left;'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;小小播放器是一款小巧的音乐播放器,使用<span style='color:#ffa533;background:#fff;'>javascript</span>和<span style='color:#2d78f4;background:#fff;'>c++</span>开发,占用极低的内存及cpu,可以快速枚举出音乐库所有音乐并随机播放。支持音频格式为:mp3,m4a,wav。</p></body>";
			showModalDialog(str);
		},
		error:function(){
			alert("很抱歉!应用程序发生错误:\n\r音频格式错误!");
		}
	}
	/*正常模式和试听模式【作为默认播放器双击打开某个音频文件】*/
	if(commandLine!=" null"&&commandLine!=" "){
		window.resizeTo(500,140);
		document.getElementById("normalPanel").style.display="none";
		document.getElementById("abnormalPanel").style.display="block";
		var musicTitle=commandLine.split("\\");
		document.getElementById("abnormalPanelShowName").innerHTML=musicTitle[musicTitle.length-1];
		sys.playerHandel.setAttribute("controls","controls");
 		sys.playerHandel.onended=function(){sys.playerHandel.play()};
 		sys.playerHandel.setAttribute("src",commandLine);
 		sys.playerHandel.play();
 	}else{
 		sys.main();
 		this.onkeydown=function(e){
	 		switch(e.keyCode){
	 			case 39:{
	 				sys.next();//->键
	 				break;
	 			}
	 			case 37:{
	 				sys.last();//<-键
	 				break;
	 			}
	 			default:;
	 		}
	 	}
 	}
</script>
           

        里面有注释,代码很简单,就是扫描“F:\\音乐"文件夹下所有文件,枚举出音频文件存到数组,打乱顺序,开始播放,监听audio标签。大家也可以改成扫描全盘文件,这个需要用递归实现,也要用到ActiveX控件的FileSystem对象。

        到这里,音乐播放器主程序就实现了,下面讲一下他的壳子,main.exe

        本来想用c#做exe文件的,不过,考虑到有一些电脑没有.net环境,可能会运行失败,所以后来改成了c++实现,下面先上代码。

#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
/**
 * [main 应用程序入口]
 * @param  argc [参数个数]
 * @param  argv [参数指针]
 * @return      [description]
 */
int KillProcessByTitle(const char* sWindowName);
int main(int argc,char **argv) {
    char **temp = argv;//接收参数指针
    string exePath=*temp;
    /*exe文件寻址*/
    exePath=exePath.replace(exePath.find("main.exe"),8,"")+"main.hta";
    /*string转char* */
    const char* htaPath=exePath.c_str();
    KillProcessByTitle("小小播放器v1.0");
    if(argc==2){
    	++temp;
    	ShellExecute(NULL, NULL, htaPath, *temp, NULL, SW_HIDE);
    }else{
    	ShellExecute(NULL, NULL, htaPath, "null", NULL, SW_HIDE);
    }
    return 0;
}
/**
 * [KillProcessByTitle 根据窗口名称关闭窗口]
 * @param  sWindowName [description]
 * @return             [description]
 */
int KillProcessByTitle(const char* sWindowName)
{
    HWND hWindow=FindWindow(NULL,sWindowName);
    if(hWindow==NULL)
    {
        return 1;
    }
    PostMessage(hWindow,WM_CLOSE,0,0);//向窗口发送WM_CLOSE消息关闭对话框窗口,如果该对话框是进程的子对话框则要进行后面的关闭进程操作
    DWORD dwProcessID;
    HANDLE hProcess;
    if(GetWindowThreadProcessId(hWindow, &dwProcessID)==0)
    {   
        return 2;   
    }   
 
    hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessID);   
    if(hProcess==NULL)   
    {   
        return 3;   
    }   
 
    if(!TerminateProcess(hProcess, 0))   
    {   
        return 4;
    }  
 
    return 0;
}
           

        我的电脑没有vc++和vs,所以我用的gcc编译的,gcc比较小巧。

        楼主做的这个windows应用因为是在虚拟机中执行,所以不像正常的windows编程那样方便操作窗体句柄和处理windows的消息机制。我们可以看到c++的实现很简单,一个main函数,用于打开音频文件给main.hta传参,main.hta里面这一句this.commandLine=musicPlayer.commandLine.split(" ");//接收命令行参数  就是接收参数的。另一个KillProcessByTitle()函数就是根据窗体名称关闭窗体,这样就防止了main.hta同时打开多个窗口,当程序运行时,双击音频文件,会先结束程序再重新创建窗体。

        此案例理论上支持win7及以上系统,不需要携带webkit库等乱七八糟的东西,软件体积不到1MB。这样看来,hta应用程序还是很实用的。

        用javascript开发windows应用的方法就简单给大家讲到这里,此案例仅供参考,请勿用于生产环境。

继续阅读