✨ Add v-highlight directive for lazy-loaded syntax highlighting using highlight.js
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* v-highlight directive
|
||||
* Lazy loads syntax highlighting for code blocks using highlight.js
|
||||
* Only highlights when element enters viewport (IntersectionObserver)
|
||||
*/
|
||||
|
||||
import hljs from 'highlight.js/lib/core';
|
||||
import json from 'highlight.js/lib/languages/json';
|
||||
|
||||
// Register JSON language
|
||||
hljs.registerLanguage('json', json);
|
||||
|
||||
/**
|
||||
* Apply syntax highlighting to a code element
|
||||
* @param {HTMLElement} el - The code element to highlight
|
||||
* @param {string} theme - Theme name ('github' or 'github-dark')
|
||||
*/
|
||||
function applyHighlight(el, theme = 'github-dark') {
|
||||
if (el.classList.contains('hljs')) {
|
||||
// Already highlighted
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
hljs.highlightElement(el);
|
||||
el.classList.add(`hljs-theme-${theme}`);
|
||||
} catch (error) {
|
||||
console.error('Highlight.js error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create IntersectionObserver for lazy highlighting
|
||||
* @param {HTMLElement} el - Element to observe
|
||||
* @param {string} theme - Theme to apply
|
||||
* @returns {IntersectionObserver}
|
||||
*/
|
||||
function createHighlightObserver(el, theme) {
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
applyHighlight(entry.target, theme);
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
},
|
||||
{
|
||||
rootMargin: '50px', // Start highlighting slightly before entering viewport
|
||||
threshold: 0.01
|
||||
}
|
||||
);
|
||||
|
||||
observer.observe(el);
|
||||
return observer;
|
||||
}
|
||||
|
||||
/**
|
||||
* v-highlight directive
|
||||
* Usage: <code class="language-json" v-highlight="theme">...</code>
|
||||
*/
|
||||
export const vHighlight = {
|
||||
mounted(el, binding) {
|
||||
const theme = binding.value || 'github-dark';
|
||||
|
||||
// Store observer on element for cleanup
|
||||
el._highlightObserver = createHighlightObserver(el, theme);
|
||||
},
|
||||
|
||||
updated(el, binding) {
|
||||
const newTheme = binding.value || 'github-dark';
|
||||
const oldTheme = binding.oldValue || 'github-dark';
|
||||
|
||||
// If theme changed, re-highlight
|
||||
if (newTheme !== oldTheme && el.classList.contains('hljs')) {
|
||||
el.classList.remove(`hljs-theme-${oldTheme}`);
|
||||
el.classList.add(`hljs-theme-${newTheme}`);
|
||||
}
|
||||
},
|
||||
|
||||
unmounted(el) {
|
||||
// Cleanup observer
|
||||
if (el._highlightObserver) {
|
||||
el._highlightObserver.disconnect();
|
||||
delete el._highlightObserver;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default vHighlight;
|
||||
|
||||
Reference in New Issue
Block a user