外观
专注主题代码构成 预览版本
更新时间:2025年3月30日
在上一章中,我们加载了一个示例专注主题项目。不难发现,其中有如下几个文件与文件夹:
- info.json 信息文件
- main.html 布局文件
- preview.webp 预览图
- setting 用户默认配置文件夹
JSON配置
JSON是一种数据格式,并不是编程语言。在专注主题中,info.json存储了关于该专注主题的唯一ID、版本、名称等信息。
以下是示例专注主题项目的info.json:
json
{
"id": "yyy66d35-8048-46c8-8627-ac8d89a80ce9",
"sceneRenderVersion":2,
"version":20250310,
"name": "标准 V2",
"color": "#FF9800",
"feature":[
"followActionColor",
"darkMode"
],
"setting": [
{
"type": "SettingItemGroup",
"items": [
{
"type": "SettingItem",
"contentType": "image",
"title": "专注背景图片",
"preferenceName": "background.png",
"icon": "0xf029f"
},
{
"type": "SettingItem",
"contentType": "seekbar",
"data": {
"max": "10",
"min": "0"
},
"title": "背景模糊",
"preferenceName": "backgroundBlur",
"icon": "0xf5c9"
}
],
"description": "如果未设置专注背景图片,则显示专注模式主题色。\n\n背景模糊为0时不生效。"
}
]
}
其中,各个字段的解释如下:
id
:由Doing系统自动分配的唯一ID,用于区分专注主题。如果仅仅是在本地测试开发,则可以填写任意UUID V4内容。sceneRenderVersion
:固定值为2。version
:版本序号。需要为纯数字,可用于比较版本大小。name
:名称。用户将会在专注主题列表页面看到。color
:主题色。可能会被用在展示该专注主题的信息页。feature
:支持特性。列表可以填写的值包括followActionColor
darkMode
。setting
: 用户个性化配置。允许用户修改的配置信息。
TIP
不要忘记,JSON中无法使用注释
HTML文件
main.html
是专注主题的布局文件。在这个文件中,我们可以使用HTML、CSS、JavaScript等技术来构建专注主题的界面。
WARNING
目前版本中,包括HTML、CSS、JavaScript的内容都需在一个文件中。
我们将示例专注主题项目的main.html进行拆分:
1. <head>与<style>
部分
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>番茄钟</title>
<style>
* {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
p,
h1,
h2,
h3,
h4,
h5,
h6,
li,
span,
div {
cursor: default !important;
}
:root {
--main-color: #2196F3;
--background-color: #ffffff;
--text-color: #212121;
}
@media (prefers-color-scheme: dark) {
:root {
--background-color: #121212;
--text-color: #ffffff;
}
}
body {
margin: 0;
height: 100vh;
background: var(--background-color);
color: var(--text-color);
overflow: hidden;
position: relative;
font-family: 'Arial', sans-serif;
}
.timer-container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 2;
width: clamp(200px, 70vw, 400px);
aspect-ratio: 1;
}
...
</style>
</head>
</html>
该部分与网页开发类似。需要注意的是:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
:建议设置,以适配不同设备。<meta name="color-scheme" content="light dark">
:建议设置,以适配不同主题模式。cursor: default !important;
:建议设置,以避免鼠标指针样式被覆盖。
2. <body>
部分
html
<body>
<div class="glow-container" id="glowContainer"></div>
<div class="timer-container">
<div class="progress-ring">
<div style="justify-content: center; align-items: center; display: flex; flex-direction: column;">
<div style="opacity: 0;">专注中</div>
<div id="time"></div>
<div id="mode"></div>
</div>
</div>
</div>
<div id="titlebar">
<button class="exit-btn control-btn" onclick="doing.call('exit')">
<div class="icon-exit"></div>
</button>
<div style="text-align: right; letter-spacing: 2px; opacity: 0.4;">12:34</div>
</div>
<div class="controls" id="controls">
<button class="control-btn" onclick="doing.call('action', 'togglePause')" id="pauseBtn">
<div class="icon-pause" id="pauseIcon"></div>
</button>
<button class="control-btn" onclick="doing.call('action', 'toggleDND')" id="dndBtn">
<div class="icon-dnd" id="dndIcon"></div>
</button>
<button class="control-btn" onclick="doing.call('action', 'toggleKeepScreenOn')" id="screenBtn">
<div class="icon-screen" id="screenIcon"></div>
</button>
</div>
...
</body>
该部分与网页开发类似。需要注意的是:
- 图片等资源均需包含在dft文件中,不能使用外部链接。
3. <script>
部分
html
<script>
document.oncontextmenu = () => false;
document.addEventListener('selectstart', (e) => e.preventDefault());
// 状态更新函数
function updateDoingFocusState() {
document.getElementById('time').textContent = doing.getState().timer.remainTime;
document.getElementById('mode').textContent = doing.getState().timer.mode == "work" ? "专注中" : doing.getState().timer.mode == "rest" ? "休息中" : "已暂停";
// 省略部分状态更新
}
...
</script>
该部分与网页开发类似。需要注意的是:
- 脚本将无法访问网络内容,资源均应包含在dft文件中。
其中,updateDoingFocusState()
方法将会在专注主题状态更新时被调用,以更新专注主题界面。因此,所有界面数据和状态更新需要从这个方法中获得。
例如,如果需要更新时间,可使用:
javascript
document.getElementById('time').textContent = doing.getState().timer.remainTime;
doing.getState()
的结构如下:
javascript
{
"timer": {
"remainTime": "12:34",
"currentPeriodTime": "40000",
"periodTime": "60",
"mode": "rest",
"keepScreenOn": "false",
"dnd": "true"
}
}
WARNING
当前专注主题仍处于早期阶段,doing.getState()的结构可能会有所变动。请注意关注文档更新。
如果需要按钮来对专注计时进行修改,可以通过doing.call()
方法来进行。 例如如果需要切换暂停状态:
javascript
doing.call(["action","togglePause"]);
其中,这些函数有:
javascript
{
"action": [
"exit",
"togglePause",
"toggleKeepScreenOn",
"toggleDND",
"toggleFullscreen",
"rotateScreen",
"minimizeFocus"
},
"function": [
"showWhiteNoiseDialog",
"showEventDialog",
"showInstantRecordDialog",
"showLeftScreen",
"showRightScreen"
]
}
用户配置文件
setting/
文件夹中存储了用户个性化配置。在info.json中,我们定义了用户可以修改的配置项,而这些配置项的默认值将会被存储在这个文件夹中。
例如,我们在info.json中定义了一个名为backgroundBlur
的配置项:
json
{
"type": "SettingItem",
"contentType": "seekbar",
"data": {
"max": "10",
"min": "0"
},
"title": "背景模糊",
"preferenceName": "backgroundBlur",
"icon": "0xf5c9"
}
那么,在setting/settings.json
中,我们可以定义这个配置项的默认值:
json
{
"backgroundBlur": "4.3
}
在专注主题中,我们可以通过doing.getPreference()
方法来获取用户配置项的值:
javascript
const backgroundBlur = doing.getPreference("backgroundBlur");
WARNING
请注意,用户配置项的值是字符串类型。如果需要使用数值,请自行转换。
总结
通过本章节,我们了解了专注主题的代码构成。