← Назад к вопросам
Как сделать компонент Vue.js который рендерит исходный код?
1.7 Middle🔥 141 комментариев
#Vue.js
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как сделать компонент Vue.js который рендерит исходный код
Этот вопрос может быть интерпретирован как "отображение исходного кода HTML/JavaScript на странице". Это частая задача для документации, примеров кода, блогов. Рассмотрим несколько подходов.
1. Простой способ - использование vue-highlight-code
npm install highlight.js vue-highlightjs
<template>
<div>
<pre><code v-html="highlightedCode"></code></pre>
</div>
</template>
<script>
import hljs from 'highlight.js';
import 'highlight.js/styles/atom-one-dark.css';
export default {
props: {
code: String,
language: {
type: String,
default: 'javascript'
}
},
computed: {
highlightedCode() {
return hljs.highlight(this.code, { language: this.language }).value;
}
}
};
</script>
<style scoped>
pre {
background-color: #282c34;
color: #abb2bf;
padding: 16px;
border-radius: 8px;
overflow-x: auto;
font-family: 'Courier New', monospace;
font-size: 14px;
line-height: 1.5;
}
</style>
2. С использованием Prism.js для лучшей подсветки синтаксиса
npm install prismjs
<template>
<pre :class="`language-${language}`"><code>{{ code }}</code></pre>
</template>
<script>
import Prism from 'prismjs';
import 'prismjs/themes/prism-tomorrow.css';
import 'prismjs/components/prism-javascript';
import 'prismjs/components/prism-jsx';
import 'prismjs/components/prism-typescript';
import 'prismjs/components/prism-css';
import 'prismjs/components/prism-html';
export default {
props: {
code: String,
language: {
type: String,
default: 'javascript'
}
},
mounted() {
Prism.highlightAllUnder(this.$el);
},
watch: {
code() {
this.$nextTick(() => {
Prism.highlightAllUnder(this.$el);
});
}
}
};
</script>
<style scoped>
pre {
background-color: #2d2d2d;
padding: 16px;
border-radius: 8px;
overflow-x: auto;
}
code {
font-family: 'Courier New', monospace;
font-size: 14px;
line-height: 1.6;
}
</style>
3. Отображение исходного кода Vue компонента
<template>
<div class="component-viewer">
<!-- Отображение самого компонента -->
<div class="component-preview">
<slot></slot>
</div>
<!-- Кнопка показать/скрыть код -->
<button @click="showCode = !showCode" class="toggle-btn">
{{ showCode ? 'Скрыть код' : 'Показать код' }}
</button>
<!-- Отображение исходного кода -->
<div v-if="showCode" class="code-section">
<pre><code v-html="highlightedSourceCode"></code></pre>
</div>
</div>
</template>
<script>
import hljs from 'highlight.js';
import 'highlight.js/styles/atom-one-dark.css';
export default {
props: {
sourceCode: {
type: String,
required: true
}
},
data() {
return {
showCode: false
};
},
computed: {
highlightedSourceCode() {
return hljs.highlight(this.sourceCode, { language: 'vue' }).value;
}
}
};
</script>
<style scoped>
.component-viewer {
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
}
.component-preview {
padding: 20px;
background-color: white;
border-bottom: 1px solid #ddd;
}
.toggle-btn {
width: 100%;
padding: 10px;
background-color: #f5f5f5;
border: none;
cursor: pointer;
font-weight: bold;
transition: background-color 0.2s;
}
.toggle-btn:hover {
background-color: #e0e0e0;
}
.code-section {
background-color: #282c34;
padding: 16px;
}
pre {
margin: 0;
color: #abb2bf;
font-family: 'Courier New', monospace;
font-size: 14px;
line-height: 1.5;
overflow-x: auto;
}
</style>
Использование:
<ComponentViewer
sourceCode="
<template>
<button @click="count++">Count: {{ count }}</button>
</template>
<script>
export default {
data() {
return { count: 0 }
}
}
</script>
"
>
<button @click="count++">Count: {{ count }}</button>
</ComponentViewer>
4. Загрузка кода из файла
<template>
<div>
<pre><code v-html="highlightedCode"></code></pre>
</div>
</template>
<script>
import hljs from 'highlight.js';
export default {
props: {
filePath: String
},
data() {
return {
code: ''
};
},
computed: {
highlightedCode() {
return hljs.highlight(this.code, { language: 'javascript' }).value;
}
},
async mounted() {
try {
// Загружаем файл
const response = await fetch(this.filePath);
this.code = await response.text();
} catch (error) {
console.error('Error loading file:', error);
this.code = 'Error loading code';
}
}
};
</script>
5. Компонент с копированием кода
<template>
<div class="code-block">
<div class="code-header">
<span class="language">{{ language }}</span>
<button @click="copyCode" class="copy-btn">
{{ copied ? 'Скопировано!' : 'Копировать' }}
</button>
</div>
<pre><code v-html="highlightedCode"></code></pre>
</div>
</template>
<script>
import hljs from 'highlight.js';
export default {
props: {
code: String,
language: {
type: String,
default: 'javascript'
}
},
data() {
return {
copied: false
};
},
computed: {
highlightedCode() {
return hljs.highlight(this.code, { language: this.language }).value;
}
},
methods: {
async copyCode() {
try {
// Копируем в буфер обмена
await navigator.clipboard.writeText(this.code);
this.copied = true;
// Убираем сообщение через 2 секунды
setTimeout(() => {
this.copied = false;
}, 2000);
} catch (error) {
console.error('Failed to copy:', error);
}
}
}
};
</script>
<style scoped>
.code-block {
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
background-color: #282c34;
}
.code-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
background-color: #21252b;
border-bottom: 1px solid #ddd;
color: #abb2bf;
}
.language {
font-weight: bold;
font-size: 12px;
text-transform: uppercase;
}
.copy-btn {
background-color: #667eea;
color: white;
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
transition: background-color 0.2s;
}
.copy-btn:hover {
background-color: #764ba2;
}
pre {
margin: 0;
padding: 16px;
color: #abb2bf;
font-family: 'Courier New', monospace;
font-size: 14px;
line-height: 1.5;
overflow-x: auto;
}
</style>
6. Компонент для рендеринга template как строки
<template>
<div>
<div class="template-preview">
<!-- Рендерим реальный шаблон -->
<component :is="{ template: templateString }"></component>
</div>
<div class="template-code">
<pre><code>{{ templateString }}</code></pre>
</div>
</div>
</template>
<script>
export default {
props: {
templateString: String
}
};
</script>
7. Маркдаун компонент с встраиванием кода
<template>
<div class="markdown-content" v-html="renderedMarkdown"></div>
</template>
<script>
import marked from 'marked';
import hljs from 'highlight.js';
// Конфигурируем renderer маркдауна
marked.setOptions({
highlight: function(code, language) {
if (language && hljs.getLanguage(language)) {
try {
return hljs.highlight(code, { language }).value;
} catch (err) {
console.error(err);
}
}
return code;
}
});
export default {
props: {
markdown: String
},
computed: {
renderedMarkdown() {
return marked.parse(this.markdown);
}
}
};
</script>
<style scoped>
.markdown-content {
font-size: 16px;
line-height: 1.6;
}
.markdown-content pre {
background-color: #282c34;
padding: 16px;
border-radius: 8px;
overflow-x: auto;
}
.markdown-content code {
font-family: 'Courier New', monospace;
color: #abb2bf;
}
</style>
Итоговые рекомендации
- Для подсветки синтаксиса используй highlight.js или Prism.js
- Для компонента с кодом создай обёртку, которая показывает разметку и исходный код
- Для копирования используй navigator.clipboard API
- Для загрузки кода используй fetch API или import.meta.glob в Vite
- Для маркдауна с кодом используй marked с highlight.js
- Помни о безопасности - санитизируй код если он приходит от пользователя
- Для лучшей UX добавь кнопку копирования и показать/скрыть код
Выбор подхода зависит от задачи: для простого отображения кода подойдёт highlight.js, для полноценного компонента с примерами - комбинированный подход с ComponentViewer.