This direcitve creates a tooltip that dynamcially adjusts its appearance based on the system's color scheme.
First, detect the system's color preference:
let systemMode = 'light'; // Default to light mode
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
systemMode = 'dark';
}
Next, implement the custom directive. A critical detail is using position: fixed for the tooltip element. Using position: absolute can lead to incorrect positioning when the page has scrollbars.
A timer is included for delayed display; this can be omitted if not required.
// tooltip.js
let tooltipTimer = null;
const tooltipDirective = {
bind(element, binding) {
element.addEventListener('mouseenter', (event) => {
tooltipTimer = setTimeout(() => {
const tooltipElement = document.createElement('div');
const isDarkMode = element.getAttribute('effect') === 'dark';
tooltipElement.style.cssText = `
overflow: auto;
position: fixed;
background: ${isDarkMode ? '#333' : '#fff'};
color: ${isDarkMode ? '#fff' : '#333'};
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
border-radius: 4px;
padding: 8px 12px;
font-size: 14px;
z-index: 1000;
top: ${event.clientY + 15}px;
left: ${event.clientX + 10}px;
`;
tooltipElement.id = 'vue-tooltip';
tooltipElement.textContent = element.getAttribute('tip');
document.body.appendChild(tooltipElement);
}, 800);
});
element.addEventListener('mouseleave', () => {
const existingTooltip = document.getElementById('vue-tooltip');
if (existingTooltip) {
document.body.removeChild(existingTooltip);
}
clearTimeout(tooltipTimer);
tooltipTimer = null;
});
// Optional: Update position on mouse move
// element.addEventListener('mousemove', (event) => {
// const existingTooltip = document.getElementById('vue-tooltip');
// if (existingTooltip) {
// existingTooltip.style.top = `${event.clientY + 15}px`;
// existingTooltip.style.left = `${event.clientX + 10}px`;
// }
// });
},
unbind(element) {
// Clean up event listeners if necessary, though the mouseleave handler should suffice.
element.removeEventListener('mouseenter', () => {});
element.removeEventListener('mouseleave', () => {});
}
};
export default {
install(Vue) {
Vue.directive('tooltip', tooltipDirective);
}
};
Register the directive globlaly:
import Vue from 'vue';
import TooltipDirective from './tooltip.js';
Vue.use(TooltipDirective);
Use the directive in your templates:
<template>
<span v-tooltip :tip='item.title' :effect='systemMode'>
{{ item.title }}
</span>
</template>
<script>
export default {
data() {
return {
systemMode: 'light', // Initialize with default
// ... other data properties
};
},
mounted() {
// Update systemMode when the component mounts
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
this.systemMode = 'dark';
} else {
this.systemMode = 'light';
}
}
};
</script>