最近学习web.view。试了一下用web.view做程序界面,还是非常强大的,可以用很多前端的框架、插件等,灵活性很强,可以做出很炫的界面,这一点是winform界面编程很难比拟的。
下面代码是一个根据关键字查找文件名的小程序,不是很完善,功能也很简单,主要是想分享一下web.view做界面的过程,欢迎大家批评指正!

import win.ui;
/*DSG{{*/
var winform = win.form(text="web.view制作界面: 查找文件名的小工具 (by:Mr_Mao)";right=1015;bottom=631)
winform.add()
/*}}*/
import fsys;
import fsys.path;
import fsys.dlg.dir;
import inet.url;
import process;
import web.view;
var wv = web.view(winform);
wv.enableDefaultContextMenus(false)
wv.external = {
openDialog = function(){
var folder = fsys.dlg.dir();
if(folder) folder = fsys.path.addBackslash(folder)
return folder;
};
isDir = function(str){
if(fsys.isDir(string.trim(str)) )return true;
};
openFile = function(path){
if(path){
var truePath = inet.url.decode(path)
process.execute(truePath)
}
};
deleteFile =function(path){
if(path){
var truePath = inet.url.decode(path)
if(win.msgboxTest("你确定要删除这个文件吗?","请确认:",winform.hwnd)){
var bool = io.remove(truePath) //删除本地物理文件
if(bool) {
wv.showDialog("提示:","文件已删除.")
return true;
}
}
}
}
searchFiles = function(folder,keyword,boolSubdir){
//清空listTable
wv.doScript("document.getElementById('resultList').replaceChildren()")
//枚举文件夹中的所有文件
thread.invoke(
function(wv,folder,keyword,boolSubdir){
import fsys;
import fsys.file;
import inet.url;
var i = 0;
fsys.enum( folder, "*.*",
function(dir,filename,fullpath,findData){
if(filename){
if(string.find(filename,"@"++ string.lower(keyword))){
i++;
var file = fsys.file(fullpath);
var size = file.size64().format();
file.close();
var fullpath2 = string.replace(fullpath,'@'++"\","\\");
var nodeHtml = `<tr x-data="{isShow:true}" x-show="isShow"><th class="has-text-centered">`++ i ++ `</th><td class="truncate">`++ filename ++`</td>`
nodeHtml += `<td class="has-text-centered">` ++ size ++ `</td><td class="truncate">`++ fullpath2 ++`</td>`
nodeHtml += `<td><div class="field is-grouped is-grouped-centered">`
nodeHtml += `<p class="control"><button class="button is-small is-responsive is-info" @click="aardio.openFile(\'`++ inet.url.encode(fullpath) ++`\')">打开</button></p>`
nodeHtml += `<p class="control"><button class="button is-small is-responsive is-danger" @click="(async()=>{if(await aardio.deleteFile(\'`++ inet.url.encode(fullpath) ++`\')==true)isShow=false;})()">删除</button></p>`
nodeHtml += `</div></td></tr>`
//直接操作html节点,插入到指定id的tbody元素最后边
wv.doScript("document.getElementById('resultList').insertAdjacentHTML('beforeend','"++ nodeHtml ++ "')");
}
}
} ,boolSubdir/*是否包括子目录*/
);
wv.doScript("updateTooltips()") //tip显示被截断的文本
wv.showDialog("查找结果:","找到 "++i++" 个相符的文件.")
},wv,folder,keyword,boolSubdir
)
} ;
}
wv.showDialog = function(title,msg){
//显示一个提示框
sleep(100)
wv.doScript("document.getElementById('dialogTitle').innerText='"++title++"'")
wv.doScript("document.getElementById('dialogMsg').innerText='"++msg++"'")
wv.doScript("document.getElementById('showDialog').click()")
}
wv.html = /**
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/bulma/1.0.3/css/bulma.css">
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<script defer src="https://cdn.bootcdn.net/ajax/libs/alpinejs/3.14.9/cdn.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/colresizable/1.6.0/colResizable-1.6.min.js"></script>
<style type="text/css">
.table {
table-layout: fixed;
width: 100%;
}
th:nth-child(1){width:4.5rem;}
th:nth-child(2){width:18%;}
th:nth-child(3){width:6.5rem;}
th:nth-child(4){width:auto;}
th:nth-child(5){width:7rem;}
.truncate { /* 截断长文本并显示 "..." */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
</head>
<body class="mt-2 p-5 is-unselectable">
<div class="container">
<section x-data="{dir:'', word:'', bool:false,isSearching:false}" class="mb-4">
<template x-on:icon.document="isSearching = $event.detail.msg;"></template>
<div class="field is-horizontal is-align-items-center">
<div class="field-label is-narrow mx-0 has-text-left-tablet">
<label class="label is-small has-text-weight-normal">选择文件夹:</label>
</div>
<div class="field-body">
<div class="field has-addons">
<div class="control has-icons-left is-expanded">
<input class="input" type="text" id="inputDir" x-model="dir" placeholder="c:\">
<span class="icon is-small is-left">
<i class="fa-solid fa-folder-open"></i>
</span>
</div>
<div class="control">
<button class="button is-warning" @click="(async()=>{dir=await aardio.openDialog()})();">...</button>
</div>
</div>
</div>
</div>
<div class="field is-horizontal is-align-items-center">
<div class="field-label mx-0 has-text-left-tablet">
<label class="label is-small has-text-weight-normal">搜索关键字:</label>
</div>
<div class="field-body">
<div class="field">
<p class="control has-icons-left is-expanded">
<input class="input" type="text" id="inputKeyword"placeholder="输入要搜索的文件名,不支持模式匹配" x-model="word">
<span class="icon is-small is-left">
<i class="fa-solid fa-pen-to-square"></i>
</span>
</p>
</div>
<div class="field is-grouped">
<div class="field is-narrow">
<div class="control">
<button class="button is-info px-5"
@click.debounce="if(!dir){document.getElementById('inputDir').focus();return;};
if(!word){document.getElementById('inputKeyword').focus();return;};
(async()=>{isTrueDir=await aardio.isDir(dir);if(!isTrueDir){document.getElementById('inputDir').focus();return;};})();
isSearching=true;aardio.searchFiles(dir,word,bool)">
<span class="icon is-small">
<i :class="isSearching?'fas fa-spinner fa-pulse':'fa-solid fa-magnifying-glass'"></i>
</span>
<span>查找文件名</span>
</button>
</div>
</div>
<div class="field is-narrow is-flex is-align-items-center">
<p class="control">
<label class="checkbox"><input type="checkbox" x-model="bool"/> 包含子文件夹</label>
</p>
</div>
</div>
</div>
</div>
</section>
<!-- 下面是 显示搜索结果的表格 -->
<div class="table-container">
<table class="table is-striped is-hoverable is-bordered">
<thead>
<tr class="has-background-success">
<th class="has-text-centered">序号</th>
<th class="has-text-centered">文件名</th>
<th class="has-text-centered">文件大小</th>
<th class="has-text-centered">文件路径</th>
<th class="is-size-6 has-text-centered">操作</th>
</tr>
</thead>
<tbody id="resultList"><!-- 从aardio往这里写数据 --></tbody>
</table>
</div>
<!-- 下面是隐藏的模式对话框 -->
<div x-data="{isOpen:false}">
<div class="modal" :class="isOpen?'is-active':''" @keydown.escape.window="isOpen=false;$dispatch('icon', { msg: false})">
<div class="modal-content">
<div class="box">
<article class="message is-info">
<div class="message-header">
<p id="dialogTitle">title</p>
<button class="delete" aria-label="delete" @click="isOpen=false;$dispatch('icon', { msg: false})"></button>
</div>
<div class="message-body" id="dialogMsg">
content here!
</div>
</article>
<div class="field is-grouped is-grouped-centered">
<button class="button is-primary px-5" @click="isOpen=false;$dispatch('icon', { msg: false})" @keyup.enter="isOpen=false;$dispatch('icon', { msg: false})">确 定</button>
</div>
</div>
</div>
</div>
<button class="button is-hidden" id="showDialog" @click="isOpen=true"></button>
</div>
</div>
<script>
$(function(){
$("table").colResizable(); //让表格中的列可调整
});
const updateTooltips = () => {
document.querySelectorAll('td').forEach(td => {
const isOverflowing = td.scrollWidth > td.clientWidth;
td.title = isOverflowing ? td.textContent : '';
});
};
window.addEventListener('resize', updateTooltips);
</script>
</body>
</html>
**/
wv.waitDoc()
winform.show();
win.loopMessage();