各位观众老爷,早上好!今天咱们来聊聊一个听起来很酷炫,但实际上操作起来也能让你觉得自己很酷炫的技术组合:CSS Custom Properties
结合 Web Bluetooth API,打造一个用蓝牙设备状态来驱动的 UI。
开场白:蓝牙与 CSS 的邂逅
想象一下,你的智能灯泡颜色能根据你的心率变化而变化,或者你的智能水杯能根据你的饮水进度在网页上实时显示剩余水量。是不是感觉有点赛博朋克?这背后的功臣之一就是我们今天要讲的 Web Bluetooth API 和 CSS Custom Properties。
Web Bluetooth API 让我们能在网页上直接和蓝牙设备“勾搭”上,而 CSS Custom Properties(也叫 CSS 变量)则允许我们定义一些可以在 CSS 中复用的值。把它们俩凑一块儿,就能实现一个真正意义上的“动态” UI,让 UI 的外观和行为随着蓝牙设备的状态而改变。
第一幕:Web Bluetooth API – 蓝牙设备的大门
Web Bluetooth API 允许网页脚本连接到附近的蓝牙低功耗(BLE)设备。它提供了一系列方法来扫描设备、连接设备、读取和写入设备上的数据。
1.1 扫描设备
首先,我们需要告诉浏览器我们要找什么样的蓝牙设备。这通常通过一个filters
数组来实现,里面可以指定设备的名字、UUID (Universally Unique Identifier) 等信息。
async function requestBluetoothDevice() {
try {
const device = await navigator.bluetooth.requestDevice({
filters: [
{ services: ['battery_service'] }, // 比如只找提供电池服务的设备
{ namePrefix: 'MyAwesomeDevice' } // 或者只找名字以 "MyAwesomeDevice" 开头的设备
],
optionalServices: ['heart_rate'] // 也可额外请求心率服务
});
console.log('已选择设备:' + device.name);
return device;
} catch (error) {
console.log('发生错误:' + error);
}
}
这里requestDevice
会弹出一个对话框,让用户选择要连接的蓝牙设备。filters
参数定义了我们要查找的设备类型。optionalServices
允许你在设备连接后,立即请求额外的服务。
1.2 连接设备和获取服务
一旦用户选择了设备,我们就可以连接它,并获取我们感兴趣的服务。
async function connectToDevice(device) {
try {
const server = await device.gatt.connect();
console.log('已连接到 GATT 服务器');
const batteryService = await server.getPrimaryService('battery_service');
console.log('已获取电池服务');
const batteryLevelCharacteristic = await batteryService.getCharacteristic('battery_level');
console.log('已获取电池电量特征');
return batteryLevelCharacteristic;
} catch (error) {
console.log('连接或获取服务时发生错误:' + error);
}
}
这段代码首先连接到设备的 GATT (Generic Attribute Profile) 服务器,然后获取电池服务。GATT 是一种蓝牙协议,用于描述设备提供的服务和特征。getPrimaryService
方法用于获取指定 UUID 的服务。
1.3 读取特征值
最后,我们可以读取特征值,例如电池电量。
async function readBatteryLevel(batteryLevelCharacteristic) {
try {
const batteryLevelBuffer = await batteryLevelCharacteristic.readValue();
const batteryLevel = batteryLevelBuffer.getUint8(0); // 电池电量通常是一个 8 位无符号整数
console.log('电池电量:' + batteryLevel + '%');
return batteryLevel;
} catch (error) {
console.log('读取电池电量时发生错误:' + error);
}
}
readValue
方法用于读取特征值。返回值是一个 DataView
对象,我们可以使用 getUint8
、getUint16
等方法来提取不同类型的数据。
1.4 监听特征值变化
除了手动读取特征值,我们还可以监听特征值的变化,这样就能实时更新 UI。
async function startNotifications(batteryLevelCharacteristic) {
try {
await batteryLevelCharacteristic.startNotifications();
console.log('已开始监听电池电量变化');
batteryLevelCharacteristic.addEventListener('characteristicvaluechanged',
handleBatteryLevelChanged);
} catch (error) {
console.log('启动通知时发生错误:' + error);
}
}
function handleBatteryLevelChanged(event) {
const batteryLevelBuffer = event.target.value;
const batteryLevel = batteryLevelBuffer.getUint8(0);
console.log('电池电量变化:' + batteryLevel + '%');
// 在这里更新 CSS 变量
document.documentElement.style.setProperty('--battery-level', batteryLevel + '%');
}
startNotifications
方法用于启动通知。当特征值发生变化时,会触发 characteristicvaluechanged
事件。在事件处理函数中,我们可以提取新的特征值,并更新 CSS 变量。
第二幕:CSS Custom Properties – UI 的调色板
CSS Custom Properties 允许我们在 CSS 中定义变量,并在样式规则中使用这些变量。这使得我们可以轻松地修改 UI 的外观,而无需修改大量的 CSS 代码。
2.1 定义 CSS 变量
CSS 变量以 --
开头。我们可以在 :root
伪类中定义全局变量,也可以在特定的元素中定义局部变量。
:root {
--primary-color: #007bff;
--secondary-color: #6c757d;
--battery-level: 50%; /* 初始电池电量 */
}
2.2 使用 CSS 变量
我们可以使用 var()
函数来引用 CSS 变量。
.button {
background-color: var(--primary-color);
color: white;
}
.battery-indicator {
width: var(--battery-level); /* 宽度随电量变化 */
height: 20px;
background-color: green;
}
2.3 通过 JavaScript 修改 CSS 变量
我们可以通过 JavaScript 来修改 CSS 变量的值。
// 在 handleBatteryLevelChanged 函数中:
document.documentElement.style.setProperty('--battery-level', batteryLevel + '%');
第三幕:蓝牙驱动的 UI – 动起来!
现在,让我们把 Web Bluetooth API 和 CSS Custom Properties 结合起来,创建一个由蓝牙设备状态驱动的 UI。
3.1 HTML 结构
首先,我们需要一个 HTML 结构来展示电池电量。
<!DOCTYPE html>
<html>
<head>
<title>Battery Level Indicator</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<button id="connectButton">连接蓝牙设备</button>
<div class="battery-container">
<div class="battery-level"></div>
</div>
<p>电池电量:<span id="batteryPercentage"></span></p>
<script src="script.js"></script>
</body>
</html>
3.2 CSS 样式
然后,我们需要一些 CSS 样式来定义电池指示器的外观。
:root {
--battery-level: 0%; /* 初始电量 */
--battery-color: green;
}
.battery-container {
width: 200px;
height: 20px;
border: 1px solid black;
margin-bottom: 10px;
}
.battery-level {
width: var(--battery-level); /* 宽度由电量决定 */
height: 100%;
background-color: var(--battery-color);
transition: width 0.3s ease-in-out; /* 平滑过渡 */
}
/* 根据电量改变颜色 */
@keyframes low-battery-blink {
0%, 100% { background-color: red; }
50% { background-color: darkred; }
}
/* 低电量警告 */
.battery-level[data-battery-level="low"] {
animation: low-battery-blink 1s linear infinite;
}
/* 满电状态 */
.battery-level[data-battery-level="full"] {
background-color: green;
}
这里我们使用 CSS 变量 --battery-level
来控制电池指示器的宽度。我们还添加了一个过渡效果,让电池电量的变化更加平滑。另外,我们使用 CSS 动画来创建一个低电量警告效果。
3.3 JavaScript 代码
最后,我们需要一些 JavaScript 代码来连接蓝牙设备、读取电池电量,并更新 CSS 变量。
const connectButton = document.getElementById('connectButton');
const batteryLevelElement = document.querySelector('.battery-level');
const batteryPercentageElement = document.getElementById('batteryPercentage');
let batteryLevelCharacteristic; // 保存电池电量特征
connectButton.addEventListener('click', async () => {
try {
const device = await requestBluetoothDevice();
batteryLevelCharacteristic = await connectToDevice(device);
// 读取初始电量
const initialBatteryLevel = await readBatteryLevel(batteryLevelCharacteristic);
updateBatteryUI(initialBatteryLevel);
// 开始监听电量变化
await startNotifications(batteryLevelCharacteristic);
} catch (error) {
console.log('发生错误:' + error);
}
});
async function requestBluetoothDevice() {
try {
const device = await navigator.bluetooth.requestDevice({
filters: [{ services: ['battery_service'] }],
optionalServices: ['battery_service']
});
console.log('已选择设备:' + device.name);
return device;
} catch (error) {
console.log('请求蓝牙设备时发生错误:' + error);
}
}
async function connectToDevice(device) {
try {
const server = await device.gatt.connect();
console.log('已连接到 GATT 服务器');
const batteryService = await server.getPrimaryService('battery_service');
console.log('已获取电池服务');
const characteristic = await batteryService.getCharacteristic('battery_level');
console.log('已获取电池电量特征');
return characteristic;
} catch (error) {
console.log('连接设备或获取服务时发生错误:' + error);
}
}
async function readBatteryLevel(characteristic) {
try {
const batteryLevelBuffer = await characteristic.readValue();
const batteryLevel = batteryLevelBuffer.getUint8(0);
console.log('电池电量:' + batteryLevel + '%');
return batteryLevel;
} catch (error) {
console.log('读取电池电量时发生错误:' + error);
return 0;
}
}
async function startNotifications(characteristic) {
try {
await characteristic.startNotifications();
console.log('已开始监听电池电量变化');
characteristic.addEventListener('characteristicvaluechanged',
handleBatteryLevelChanged);
} catch (error) {
console.log('启动通知时发生错误:' + error);
}
}
function handleBatteryLevelChanged(event) {
const batteryLevelBuffer = event.target.value;
const batteryLevel = batteryLevelBuffer.getUint8(0);
console.log('电池电量变化:' + batteryLevel + '%');
updateBatteryUI(batteryLevel);
}
function updateBatteryUI(batteryLevel) {
const batteryPercentage = batteryLevel + '%';
document.documentElement.style.setProperty('--battery-level', batteryPercentage);
batteryPercentageElement.textContent = batteryPercentage;
// 设置 data 属性,用于 CSS 控制低电量动画
if (batteryLevel < 20) {
batteryLevelElement.setAttribute('data-battery-level', 'low');
} else if (batteryLevel === 100) {
batteryLevelElement.setAttribute('data-battery-level', 'full');
} else {
batteryLevelElement.removeAttribute('data-battery-level'); // 移除属性,恢复默认样式
}
}
这段代码实现了以下功能:
- 点击按钮后,连接到蓝牙设备。
- 读取电池电量,并更新电池指示器的宽度。
- 监听电池电量变化,并实时更新 UI。
- 当电池电量低于 20% 时,显示低电量警告。
3.4 完整代码示例
把上面的 HTML、CSS 和 JavaScript 代码放在一起,就是一个完整的蓝牙驱动的电池电量指示器。你可以用它来监控你的智能设备的电池电量,或者把它集成到你的智能家居系统中。
第四幕:进阶技巧与注意事项
4.1 错误处理
Web Bluetooth API 的错误处理非常重要。你需要捕获各种可能发生的错误,例如设备未找到、连接失败、读取特征值失败等。
4.2 安全性
Web Bluetooth API 只能在 HTTPS 页面中使用。这是为了防止恶意网站未经用户许可访问蓝牙设备。
4.3 兼容性
Web Bluetooth API 的兼容性还在不断完善中。目前,Chrome、Edge 和 Opera 等浏览器支持 Web Bluetooth API。
4.4 性能优化
频繁地读取特征值可能会影响性能。你可以使用 requestAnimationFrame
来优化 UI 的更新频率。
4.5 更复杂的数据处理
如果蓝牙设备返回的数据比较复杂,你需要编写更复杂的代码来解析数据。例如,你可以使用 DataView
对象来读取不同类型的数据,或者使用 TextDecoder
对象来解码字符串。
5. 总结
今天我们一起探索了如何使用 CSS Custom Properties 结合 Web Bluetooth API,打造一个由蓝牙设备状态驱动的 UI。通过这个简单的例子,我们可以看到 Web Bluetooth API 和 CSS Custom Properties 的强大之处。它们可以让我们创建出更加动态、更加智能的 Web 应用。希望今天的分享能够激发你的灵感,让你在未来的项目中创造出更加精彩的作品!
最后的彩蛋:一些脑洞大开的想法
- 智能家居控制面板: 根据环境光传感器的数据自动调整 UI 的亮度。
- 健身追踪器仪表盘: 实时显示心率、步数等数据,并根据运动状态改变 UI 的颜色。
- 智能水杯状态显示: 根据水杯的倾斜角度和饮水速度,动态显示剩余水量。
- 智能灯泡控制: 通过颜色选择器控制灯泡的颜色,并实时显示灯泡的亮度。
希望这些想法能给你带来一些启发。记住,想象力是无限的,技术只是实现你的想法的工具。祝你编程愉快!