NW.js开发桌面应用,如何自定义边框

利用NW.js开发桌面应用时,NW框架的边框可能无法满足我们对产品的要求,这个时候就需要自定义边框,比如无边框、无边框+有圆角、无边框+有边+有圆角等。现在问题来了,该怎么实现自定义效果呢?笔者以最后一种情况(无边框+有边+有圆角),进行简单的设置说明。

package.json配置

"window": {
    "frame": false,   // 去除框架的边框
    "transparent": true  // 窗口透明
  }

起步

<!-- 在html元素上设置软件整体边框和圆角;在body中的div上同样可以设置 -->
<html style="border:8px solid #eeca00;border-radius:8px">
<!-- 设置透明背景 -->
<body style="background-color:rgba(0,0,0,0);">

看看效果:


自定义透明背景的NW.js应用

上图所示的完整HTML代码是:

<!DOCTYPE html>
<html style="border:8px solid #eeca00;border-radius:8px">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>demo</title>
</head>
<body style="background-color:rgba(0,0,0,0);">
  <div style="height:500px;font-size:40px">
    Hello World
  </div>
</body>
</html>

可拖拽

现在,这个软件不能拖动,也没有关闭、最小化、最大化窗口功能,现在我们来给这个软件添加这些功能。

添加拖拽层

想要实现拖拽,关键是使用-webkit-app-region: drag;CSS属性。上图中,蓝色横条上添加了这个属性,现在就能点它进行拖拽了。此外,在可拖拽的元素上双击,可以最大化窗口,再次双击则恢复窗口大小。

完整HTML代码如下:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport"content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible"content="ie=edge">
  <title>demo</title>
  <style>
    *{padding:0;margin:0;}
    html{border:8px solid #eeca00;border-radius:8px;}
    body{background-color:rgba(0,0,0,0);overflow:hidden;}
    .app{height:500px;font-size:40px;background:#fff;}
    .drag{height:36px;line-height:36px;font-size:14px;color:#fff;text-align:center;background:#008cee;-webkit-app-region:drag;}
    .main{height:calc(100% - 36px);display:flex;align-items:center;justify-content:center;}
  </style>
</head>

<body>
  <div class="app">
    <div class="drag">拖拽我吧</div>
    <div class="main">Hello World</div>
  </div>
</body>
</html>

窗口控制(最小化、最大化、关闭)

我们在拖拽层的右上角添加几个按钮,然后给它们注册点击事件。需要注意,因为拖拽层上设置了-webkit-app-region: drag;CSS属性,这个属性会吃掉所有的鼠标事件,比如鼠标悬浮、点击等。为了确保图中的三个按钮可以点击,我们要在被点击的元素上设置-webkit-app-region: no-drag;CSS属性,去掉drag功能,就能点击了。

窗口控制

窗口的最大化等操作,需要用到nw的API,下面是实现代码:

  let min, max, close, win
  min = document.getElementById('min')  // 最小化按钮
  max = document.getElementById('max')  // 最大化按钮
  close = document.getElementById('close')  // 关闭按钮
  win = nw.Window.get()  // 获取当前窗口实例
  min.onclick = () => {
    win.minimize()  // 窗口最小化
  }
  max.onclick = () => {
    win.maximize()  // 窗口最大化
  }
  close.onclick = () => {
    nw.App.quit()  // 关闭软件
  }

最大化窗口,是指最大化到我们设置的窗口最大尺寸。如果我们没有在package.json中设置最大尺寸,而把主页面的html元素的宽高设置为100%, 100%, 最大化时就会撑满电脑桌面的可用区域(windows平台中会排除任务栏)。此外,还有win.enterFullscreen接口可以考虑使用,这个接口使得窗口全屏显示,windows中会覆盖掉任务栏。

窗口恢复操作

之前提到拖拽条双击可以放大、再点击可以恢复,我们希望当点击“最大化”按钮后,再次点击可以恢复窗口大小。(之前的代码只实现了最大化功能)这里需要用到win.restore接口。接下来的问题是,我们该如何确定窗口当前是最大化。
如果使用 win.enterFullscreen全屏显示,那么可以通过win.isFullscreen来判断当前窗口是否全屏。
如果使用win.maximize最大化窗口,是不会触发win.isFullscreen的改变的,但是我们可以监听到窗口实例的maximize事件,而当调用win.restore触发窗口实例的restore事件。结合这两个事件就可以判断当前窗口是否最大化。
现在把窗口控制部分的js代码补充完整,如下所示:

  let min, max, close, win
  let flag = false  // 标识当前的窗口是否最大化
  min = document.getElementById('min')
  max = document.getElementById('max')
  close = document.getElementById('close')
  win = nw.Window.get()
  min.onclick = () => {
    win.minimize()
  }
  max.onclick = () => {
    if (flag) {
      win.restore()  // 如果是最大化,则恢复窗口
    } else {
      win.maximize()  // 否则,最大化窗口
    }
  }
  close.onclick = () => {
    nw.App.quit()
  }
  // 监听窗口最大化事件
  win.on('maximize', () => {
    flag = true
  })
  // 监听窗口恢复事件
  win.on('restore', () => {
    flag = false
  })

拖拽条双击放大触发的是maximize事件,双击恢复触发的是restore事件。和我们上面实现的点击按钮的功能完全兼容,可以随意的操作窗口了。但是如果使用win.isFullscreen,它和拖拽条的双击功能并不兼容。

动态设置窗口最大尺寸

前面提到

如果我们没有在package.json中设置最大尺寸,而把主页面的html元素的宽高设置为100%, 100%, 最大化时就会撑满电脑桌面的可用区域(windows平台中会排除任务栏)。

我们可以使用win.setMaximumSize接口动态设置窗口的最大尺寸,调用的时候把最大宽和最大高的数值传递进去,比如:

let { availHeight, availWidth } = win.window.screen  // 获取电脑桌面的可用高度和可用宽度(排除任务栏)
win.setMaximumSize(availWidth, availHeight)   // 设置窗口的最大尺寸
win.maximize()  // 进行最大化操作

结束。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容

  • 原文:https://github.com/electron/electron/blob/master/docs/...
    Shmily落墨阅读 18,999评论 1 5
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,880评论 25 707
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,744评论 1 92
  • 多利用下列的成交用具来达成销售,要表现出肯定、坚定、有信心。 1、 您就奖赏一下自己吧!把它作为永久收藏 2、 您...
    思念的诗阅读 1,371评论 0 0
  • 前几天把Android Studio升级到了2.3版本,今天在打包签名apk时,在最后一步,遇到了一点小麻烦,点了...
    Android_大船阅读 3,307评论 0 3