1. vscode插件分享:看看它如何实现烟花抖动效果
对于程序员来说,vscode是必不可少的开发工具之一。而在vscode中,丰富的插件也是不可或缺的,它们能极大地提高我们的工作效率和开发体验。今天,我们来聊一聊一款有趣的插件——fireworks。
1.1 插件简介
Fireworks是一款提供了烟花抖动效果的vscode插件,它可以让你的代码编辑器变得更加有趣。
1.2 插件安装
安装Fireworks非常简单,只需要在vscode的扩展功能中搜索“fireworks”即可找到并安装。
1.3 插件使用
安装完成后,打开vscode,在编辑器任意位置右键点击,选择“Start Fireworks”即可激活烟花效果。
// 激活烟花效果的快捷键也可以在设置中进行设置
"fireworks.start": {
"command": "fireworks.start",
"key": "ctrl+alt+f",
"when": "editorTextFocus"
},
激活烟花效果后,编辑器将出现烟花抖动的效果,每个字符会随机移动一定的距离。同时,将光标移动到某个字符附近,也会触发烟花效果。
2. 插件源码分析
我们接下来来看一下Fireworks插件是如何实现烟花抖动效果的。
2.1 实现原理
Fireworks插件主要是通过修改编辑器的CSS样式来实现抖动效果。具体来说,它添加了对每个字符的CSS3动画效果,使它们不断灰度变化、位置不断移动。因此,只需要在CSS样式上添加对应的class即可实现想要的效果。
const baseInterval = 250;
const wcharInterval = 80;
const charMoveVal = '1px';
const keyframesPrefix = '-webkit-';
const toTransparentStr = 'rgba(255,255,255,0)';
const fromTransparentStr = 'rgba(255,255,255,1)';
const toTextShadowStr = '0 0 4px rgba(255,255,255,1)';
const fromTextShadowStr = '0 0 16px rgba(255,255,255,0)';
const className = 'fireworks-animation';
const charRegex = /[\S]/gu;
const whitespaceRegex = /\s/gu;
function getCharacterCSS(char: string, index: number): string {
const delay = `${baseInterval + wcharInterval * index}ms`;
const transfrom = `
translateX(${charMoveVal})
translateY(${charMoveVal})
scale(1.5)
rotate(3deg)
skew(-15deg, -15deg)
`;
return `
.${className}:nth-child(${index + 1})::after {
animation-delay: ${delay};
transform: ${transfrom};
text-shadow: ${toTextShadowStr};
color: ${fromTransparentStr};
animation-direction: alternate;
}
.${className}:nth-child(${index + 1})::before {
animation-delay: ${delay};
transform: ${transfrom};
text-shadow: ${toTextShadowStr};
color: ${toTransparentStr};
}
`;
}
function getWhitespaceCSS(index: number): string {
const delay = `${baseInterval + wcharInterval * index}ms`;
return `
.${className}:nth-child(${index + 1})::after {
animation-delay: ${delay};
text-shadow: ${fromTextShadowStr};
color: ${fromTransparentStr};
animation-direction: alternate;
}
.${className}:nth-child(${index + 1})::before {
animation-delay: ${delay};
text-shadow: ${fromTextShadowStr};
color: ${toTransparentStr};
}
`;
}
export function activate(context: ExtensionContext) {
let active = false;
const updateCSS = (editor: TextEditor) => {
const document = editor.document;
const text = document.getText();
const charsOnly = text.match(charRegex)?.join('').split('');
const full = text.split('');
let css = '';
if (charsOnly) {
const characters = charsOnly.map((char, index) =>
whitespaceRegex.test(char) ? getWhitespaceCSS(index) : getCharacterCSS(char, index),
);
css = characters.join('\n');
} else {
css = full.map((char, index) =>
whitespaceRegex.test(char) ? getWhitespaceCSS(index) : getCharacterCSS(char, index),
).join('\n');
}
const disposed = !editor || editor.document !== document;
if (active && !disposed) {
editor.setDecorations(styles, []);
}
if (active && !disposed) {
const decorations = full.map((_, index) => {
return {
range: new Range(new Position(0, index), new Position(0, index + 1)),
hoverMessage: ''
};
});
editor.setDecorations(styles, decorations);
}
const cssClass = `.${className}::before, .${className}::after ${'{'}\n${css}\n${'}'}`;
const style = ``;
if (active && !disposed) {
editor.setDecorations(styles, []);
const pageStyle = document.getElementById('fireworks-stylesheet');
pageStyle?.remove();
document.body.removeChild(previewHTML);
} else if (active) {
active = false;
return;
}
const previewHTML = document.createElement('div');
const previewStyles = document.createElement('style');
previewHTML.id = 'fireworks-preview';
previewStyles.id = 'fireworks-stylesheet';
previewStyles.innerHTML = cssClass;
previewHTML.innerHTML = text.split('').map((char, index) => {
const klass = whitespaceRegex.test(char) ? 'whitespace' : `character ${className}`;
return `<${'span'} class="${klass}" style="animation-delay: ${baseInterval + wcharInterval * index}ms">${char}${'span'}>`;
}).join('');
document.body.append(previewHTML);
document.head.append(previewStyles);
active = true;
};
const styles = window.createTextEditorDecorationType({
color: { id: 'highlight' },
});
const editor = window.activeTextEditor;
if (editor) {
updateCSS(editor);
document.getElementById('workbench.editor.walkThrough.embeddedEditor')?.classList.add(className);
}
const subscriptions = context.subscriptions;
subscriptions.push(
window.onDidChangeActiveTextEditor(
editor => {
if (editor) {
updateCSS(editor);
document.getElementById('workbench.editor.walkThrough.embeddedEditor')?.classList.add(className);
}
},
null,
subscriptions,
),
);
subscriptions.push(
workspace.onDidChangeTextDocument(
event => {
const editor = window.activeTextEditor;
if (editor && event.document === editor.document) {
updateCSS(editor);
}
},
null,
subscriptions,
),
);
subscriptions.push(
workspace.onDidChangeConfiguration(() => {
const editor = window.activeTextEditor;
if (editor) {
updateCSS(editor);
}
}),
);
}
2.2 代码解析
上面的代码中,主要实现了以下几个功能:
生成一个CSS3的动画类,用来生成Fireworks的动画效果。
在打开编辑器后,向编辑器中插入用于生成动画的HTML元素。
在编辑器中监听文本的改变,并对新添加的文本生成动画效果。
重写编辑器的保存方法,当正在生成动画效果时,禁止删除生成动画的元素。
结合上述代码解释,Fireworks插件如何实现烟花抖动效果已经变得非常清晰和易懂了。
3. 总结
通过本文的学习,我们了解了一款基于vscode的抖动效果插件Fireworks,并且深度解析了它的实现原理。相信通过丰富的插件和学习,我们能够打造更加强大的IDE工具和编程环境,从而更轻松地进行开发工作。