最近学习web.view。试了一下用web.view做程序界面,还是非常强大的,可以用很多前端的框架、插件等,灵活性很强,可以做出很炫的界面,这一点是winform界面编程很难比拟的。
下面代码是一个根据关键字查找文件名的小程序,不是很完善,功能也很简单,主要是想分享一下web.view做界面的过程,欢迎大家批评指正!
Code AardioLine:388复制1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251. 252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265. 266. 267. 268. 269. 270. 271. 272. 273. 274. 275. 276. 277. 278. 279. 280. 281. 282. 283. 284. 285. 286. 287. 288. 289. 290. 291. 292. 293. 294. 295. 296. 297. 298. 299. 300. 301. 302. 303. 304. 305. 306. 307. 308. 309. 310. 311. 312. 313. 314. 315. 316. 317. 318. 319. 320. 321. 322. 323. 324. 325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335. 336. 337. 338. 339. 340. 341. 342. 343. 344. 345. 346. 347. 348. 349. 350. 351. 352. 353. 354. 355. 356. 357. 358. 359. 360. 361. 362. 363. 364. 365. 366. 367. 368. 369. 370. 371. 372. 373. 374. 375. 376. 377. 378. 379. 380. 381. 382. 383. 384. 385. 386. 387. 388.
import
win
.ui;/*DSG{{*/
var
winform =win
.form(text="web.view制作界面: 查找文件名的小工具 (by:Mr_Mao)"
;right=1183
;bottom=751
)- winform.add()
/*}}*/
import
fsys;import
fsys.dlg.dir;import
process;import
fsys.info;import
web.view;var
wv = web.view(winform);- wv.enableDefaultContextMenus(
false
)- wv.external = {
- openDialog =
function
(){var
folder = fsys.dlg.dir();return
folder;- };
- isDir =
function
(str){if
(fsys.isDir(string
.trim(str)))return
true
;- };
- openFile =
function
(path){- process.
execute
(path)- };
- deleteFile =
function
(path){if
(win
.msgboxTest("你确定要删除这个文件吗?"
,"请确认:"
,winform.hwnd)){var
bool =io
.remove(path)//物理删除本地文件
if
(bool) {sleep
(300
)- wv.
invoke
("showDialog"
,"提示:"
,"文件已删除."
)return
true
;- }
- }
- }
- getIconBuffer =
function
(path){var
sfi = fsys.info.get(path, 0x100/*_SHGFI_ICON*/
);var
handle = sfi.hIcon;var
buffer = gdip.bitmap(handle,1
).saveToBuffer(".png"
)return
buffer;- };
- 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();//插入到x-data中的数组内
- wv.
invoke
("add2items"
, i, filename, fullpath, size)//add2items(id,name,path,size)
- }
- }
- } ,boolSubdir
/*是否包括子目录*/
- );
- wv.doScript(
"updateTooltips()"
)sleep
(300
)- wv.
invoke
("showDialog"
,"查找结果:"
,"找到 "
++i++" 个相符的文件."
)- },wv,folder,keyword,boolSubdir
- )
- } ;
- }
- 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: 62px;}
th:nth-child(2) { width: 20%;}
th:nth-child(3) { width: 120px;}
th:nth-child(4) { width: auto;}
th:nth-child(5) { width: 120px;}
.truncate {/* 截断长文本并显示 "..." */
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- .pagination-ellipsis {
- pointer-events: none;
- }
- </style>
- </head>
- <body>
- <div
class
="container"
x-data="app"
id="container"
>- <!-- form区域 -->
- <div
class
="section py-5"
>- <div
class
="columns is-vcentered"
>- <div
class
="column is-narrow"
>- <label
class
="label"
>选择文件夹:</label>- </div>
- <div
class
="column"
>- <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
="columns is-vcentered"
>- <div
class
="column is-narrow"
>- <label
class
="label"
>搜索关键字:</label>- </div>
- <div
class
="column"
>- <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>
- <div
class
="column is-narrow"
>- <div
class
="field is-horizontal"
>- <div
class
="field-body"
>- <div
class
="field is-grouped"
>- <div
class
="field is-narrow"
>- <div
class
="control"
>- <button
class
="button is-info px-5"
- @click.debounce=
"findStrInDir();"
>- <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"
><inputtype
="checkbox"
x-model="bool"
class
='mr-1'
/>包含子文件夹</label>- </p>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!--
table
区域 -->- <div
class
="table-container mx-3"
>- <
table
class
="table is-striped is-hoverable is-bordered"
id="filestable"
>- <thead>
- <tr
class
="has-background-success"
>- <th
class
="has-text-centered is-size-7-touch"
style="vertical-align: middle;"
>序号</th>- <th
class
="has-text-centered is-size-7-touch"
style="vertical-align: middle;"
>文件名</th>- <th
class
="has-text-centered is-size-7-touch"
style="vertical-align: middle;"
>文件大小</th>- <th
class
="has-text-centered is-size-7-touch"
style="vertical-align: middle;"
>文件路径</th>- <th
class
="has-text-centered is-size-7-touch"
style="vertical-align: middle;"
>操作</th>- </tr>
- </thead>
- <tbody>
- <!-- aardio往这里写数据 -->
- <template x-
for
="item in pageItems"
>- <tr>
- <th
class
="has-text-centered"
style="vertical-align: middle;"
x-text="item.id"
></th>- <td
class
="truncate"
style="vertical-align: middle;"
>- <figure
class
="image is-32x32 is-pulled-left"
><img :src="showIcon(item.filepath)"
/></figure>- <span
class
="ml-2"
x-text="item.filename"
></span>- </td>
- <td
class
="has-text-centered"
style="vertical-align: middle;"
x-text="item.filesize"
></td>- <td
class
="truncate"
style="vertical-align: middle;"
x-text="item.filepath"
></td>- <td style=
"vertical-align: middle;"
>- <div
class
="buttons are-small is-centered"
>- <button
class
="button is-info px-2 py-1"
@click="openItem(item.filepath)"
>打开</button>- <button
class
="button is-danger px-2 py-1"
@click="(async()=>{if(await aardio.deleteFile(item.filepath)==true)deleteItem(totalItems, item.id); })()"
>删除</button>- </div>
- </td>
- </tr>
- </template>
- </tbody>
- </
table
>- </div>
- <!-- 分页器 -->
- <template x-
if
="totalPages>1"
>- <nav
class
="pagination is-centered"
role="navigation"
aria-label="pagination"
>- <ul
class
="pagination-list"
>- <li><!-- 上一页按钮 -->
- <a
class
="pagination-previous"
- :
class
="{ 'is-disabled': currentPage === 1 }"
- @click=
"changePage(currentPage - 1)"
> 上页 </a>- </li>
- <li>
- <a
class
="pagination-link"
- :
class
="{ 'is-current': 1 === currentPage }"
- @click=
"changePage(1)"
>1
</a>- </li>
- <li x-show=
"currentPage > visiblePages + 1"
><!-- 前省略号 -->- <span
class
="pagination-ellipsis"
>…</span>- </li>
- <template x-
for
="page in visiblePageNumbers"
:key="page"
>- <li x-show=
"page > 1 && page < totalPages"
>- <a
class
="pagination-link"
- :
class
="{ 'is-current': page === currentPage }"
- @click=
"changePage(page)"
- x-text=
"page"
></a>- </li>
- </template>
- <li x-show=
"currentPage < totalPages - visiblePages"
><!-- 后省略号 -->- <span
class
="pagination-ellipsis"
>…</span>- </li>
- <li x-show=
"totalPages > 1"
>- <a
class
="pagination-link"
- :
class
="{ 'is-current': totalPages === currentPage }"
- @click=
"changePage(totalPages)"
- x-text=
"totalPages"
></a>- </li>
- <li><!-- 下一页按钮 -->
- <a
class
="pagination-next"
- :
class
="{ 'is-disabled': currentPage === totalPages }"
- @click=
"changePage(currentPage + 1)"
>下页</a>- </li>
- </ul>
- </nav>
- </template>
- <!-- 模式对话框 -->
- <template x-teleport=
"body"
>- <div
class
="modal"
:class
="isModalOpen?'is-active':''"
>- <div
class
="modal-content"
style="max-width:50%"
>- <article
class
="message is-info"
>- <div
class
="message-header"
>- <p x-text=
"title"
>title</p>- <button
class
="delete"
aria-label="delete"
@click="isModalOpen=false;isSearching=false"
></button>- </div>
- <div
class
="message-body"
>- <div
class
="py-4"
x-text="msg"
>contents</div>- <div
class
="field is-grouped is-grouped-centered mt-5"
>- <button
class
="button is-primary mx-7"
@click="isModalOpen=false;isSearching=false"
- @keyup.escape.window=
"$dispatch($el.click())"
>确 定</button>- </div>
- </div>
- </article>
- </div>
- </div>
- </template>
- </div> <!-- div.container 结束 -->
- <script
type
="text/javascript"
>//alpine初始化
- document.addEventListener(
'alpine:init'
,function
() {- Alpine.data(
'app'
, () => ({- dir:
''
, word:''
, bool:false
,- isSearching:
false
, isModalOpen:false
,- title:
''
, msg:''
,- totalItems:[],
- currentPage:
1
,- itemsPerPage:
10
,- visiblePages:
2
,// 当前页左右各显示多少页码
- get totalPages() {
return
Math
.ceil(this
.totalItems.length /this
.itemsPerPage);- },
- get pageItems() {
- const start = (
this
.currentPage -1
) *this
.itemsPerPage;- const
end
= start +this
.itemsPerPage;return
this
.totalItems.slice(start,end
);- },
- changePage(page) {
if
(page >=1
&& page <=this
.totalPages) {this
.currentPage = page;- }
- },
- get visiblePageNumbers() {
- const start =
Math
.max(2
,this
.currentPage -this
.visiblePages);- const
end
=Math
.min(this
.totalPages -1
,this
.currentPage +this
.visiblePages);- const pages = [];
for
(let i = start; i <=end
; i++) {- pages.push(i);
- }
return
pages;- },
- findStrInDir(){
this
.isSearching=false
;if
(!this
.dir){document.getElementById('inputDir'
).focus();return
;};if
(!this
.word){document.getElementById('inputKeyword'
).focus();return
;};- (async()=>{
- const isTrueDir = await aardio.isDir(
this
.dir);if
(!isTrueDir){document.getElementById('inputDir'
).focus();return
;};this
.isSearching=true
;this
.totalItems.length =0
;this
.currentPage=1
;- aardio.searchFiles(
this
.dir,this
.word,this
.bool);- })();
- },
- }))
- });
//显示一个提示框
function
showDialog(t,m) {// 通过 DOM 元素获取 Alpine 组件实例
- const component = document.querySelector(
'#container'
);- const alpineData = Alpine.$data(component);
- alpineData.title = t;
- alpineData.msg = m;
- alpineData.isModalOpen =
true
;- }
//添加符合条件的文件信息到数组中
function
add2items(num,name,path,size) {- const component = document.querySelector(
'#container'
);- const alpineData = Alpine.$data(component);
- alpineData.totalItems.push({id: num, filename: name, filesize: size, filepath: path})
- }
//打开本地文件
function
openItem(path) {- aardio.openFile(path)
//
- }
//删除本地文件
function
deleteItem(arr, idNum) {- arr.splice(arr.findIndex(el => el.id === idNum),
1
)- }
//显示图标
- async
function
showIcon(path) {var
nativeByteArray = await aardio.getIconBuffer(path);- const uint8Array = new Uint8Array(nativeByteArray);
- const blob = new Blob([uint8Array], {
type
:'image/png'
});- const imageUrl = URL.createObjectURL(blob);
return
imageUrl;- }
- $(
function
() {//让表格中的列可调整
- $(
"#filestable"
).colResizable();- });
//让td单元格鼠标悬停tip显示全名
- 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();