JAVASCRIPT
Implementing Reusable Logic with a Custom Vue 3 Composable (useBatteryStatus)
Create a custom Vue 3 Composition API composable (`useBatteryStatus`) to encapsulate and reuse reactive logic for monitoring the device's battery status across components.
<!-- App.vue (Consuming the composable) -->
<template>
<div>
<h1>Device Battery Status</h1>
<div v-if="isSupported">
<p>Charging: {{ isCharging ? 'Yes' : 'No' }}</p>
<p>Level: {{ Math.round(level * 100) }}%</p>
<p>Charging Time: {{ chargingTime === Infinity ? 'N/A' : chargingTime + ' seconds' }}</p>
<p>Discharging Time: {{ dischargingTime === Infinity ? 'N/A' : dischargingTime + ' seconds' }}</p>
</div>
<p v-else>Battery Status API not supported in this browser.</p>
</div>
</template>
<script setup>
import { useBatteryStatus } from './composables/useBatteryStatus';
const { isSupported, isCharging, level, chargingTime, dischargingTime } = useBatteryStatus();
</script>
<!-- composables/useBatteryStatus.js (The custom composable) -->
import { ref, onMounted, onUnmounted } from 'vue';
export function useBatteryStatus() {
const isSupported = ref('getBattery' in navigator);
const isCharging = ref(false);
const level = ref(1);
const chargingTime = ref(0);
const dischargingTime = ref(Infinity);
let battery = null;
const updateBatteryStatus = () => {
if (!battery) return;
isCharging.value = battery.charging;
level.value = battery.level;
chargingTime.value = battery.chargingTime;
dischargingTime.value = battery.dischargingTime;
};
const initBattery = async () => {
if (isSupported.value) {
battery = await navigator.getBattery();
updateBatteryStatus();
battery.addEventListener('chargingchange', updateBatteryStatus);
battery.addEventListener('levelchange', updateBatteryStatus);
battery.addEventListener('chargingtimechange', updateBatteryStatus);
battery.addEventListener('dischargingtimechange', updateBatteryStatus);
}
};
onMounted(initBattery);
onUnmounted(() => {
if (battery) {
battery.removeEventListener('chargingchange', updateBatteryStatus);
battery.removeEventListener('levelchange', updateBatteryStatus);
battery.removeEventListener('chargingtimechange', updateBatteryStatus);
battery.removeEventListener('dischargingtimechange', updateBatteryStatus);
}
});
return {
isSupported,
isCharging,
level,
chargingTime,
dischargingTime,
};
}
How it works: This snippet demonstrates creating and using a custom Vue 3 composable, `useBatteryStatus`, to encapsulate and reuse reactive logic for interacting with the Battery Status API. This composable exports reactive references (`ref`) for properties like `isCharging`, `level`, and `chargingTime`, allowing any component to easily monitor the device's battery status. It correctly handles mounting and unmounting to add and remove event listeners, preventing memory leaks and ensuring efficient resource management, a hallmark of well-designed composables.