跳转到内容

代码编辑器

刀刀

12/31/2024

0 字

0 分钟

在页面中想要效仿 MDN 网站 CSS 模块的效果,用户输入后右侧效果动态修改,渲染最新的效果。

组件封装

询问 ChatGPT,得到的回复是可以使用 NPM 下载的第三方组件 CodeMirror 。由于没有具体的官方文档介绍 Vue 项目如何使用,下面是询问 GPT 后得到的步骤:

  1. 下载相关依赖

    shell
    pnpm i codemirror
    pnpm i vue-codemirror
    pnpm i @codemirror/lang-css
    pnpm i @codemirror/lang-javascript
    pnpm i @codemirror/theme-one-dark

    前两个依赖主要是下载第三方组件和 Vue 适配的组件;中间两个是该组件语法高亮的语言;最后一个是皮肤,暗黑模式。

  2. 新建一个子组件,导入依赖并声明使用组件

    vue
    <script setup>
    import { Codemirror } from 'vue-codemirror';
      
    const code = defineModel();
      
    const emit = defineEmits(['change']);
    
    const handleChange = e => {
        emit('change', e);
    }
    </script>
    
    <template>
        <Codemirror
            v-model="code"
            placeholder="暂无数据..."
            :autofocus="false"
            :tabSize="2"
            @change="handleChange">
        </Codemirror>
    </template>

    其中,tabSize 为每行前面缩进几个字符,autofocus 表示是否自动聚焦,code 是父传子双向绑定的数据,修改内容会触发 change 事件。

  3. 设置编辑器的语言和皮肤模式

    通过父子传参的形式,动态设置编辑器的高亮语言语法,再和皮肤作为一个数组传递给组件的 extensions 变量。最后设置一下样式即可。

    vue
    <script setup>
    import { Codemirror } from 'vue-codemirror';
    import { javascript } from '@codemirror/lang-javascript'; 
    import { css } from '@codemirror/lang-css'; 
    import { vue } from '@codemirror/lang-vue'; 
    import { oneDark } from '@codemirror/theme-one-dark'; 
    import { screenWidth } from "@/store/index.js"; 
    
    const props = defineProps({ 
        language: { 
            type: String, 
            default: 'css'
        }, 
        disabled: { 
            type: [String, Boolean], 
            default: false
        }, 
        style: { 
            type: [Object], 
            default: () => ({}) 
        } 
    }); 
    const emit = defineEmits(['change']);
    
    const { language, disabled, style } = toRefs(props); 
    
    const lang = ref(null); 
    const extensions = ref(null); 
    watch(() => language.value, (newVal) => { 
        lang.value = { javascript, css, vue }[language.value]; 
        extensions.value = [lang.value(), oneDark]; 
    }, { immediate: true }); 
    const code = defineModel();
    const comStyle = computed(() => ({ ...style.value, ...{ height: screenWidth.value > 768 ? '300px' : '18.75rem' } })); 
    
    const handleChange = e => {
        emit('change', e);
    }
    </script>
    
    <template>
        <Codemirror :disabled="disabled"
            v-model="code"
            placeholder="暂无数据..."
            :style="comStyle"
            :autofocus="false"
            :indent-with-tab="true"
            :tabSize="2"
            :fullScreen="true"
            :extensions="extensions"
            @change="handleChange">
        </Codemirror>
    </template>

组件使用

现在封装好了一个 code 组件可以使用了,父组件只需要 v-model 双向绑定代码文本,通过 language 指定代码语言风格即可。示例代码如下:

vue
<script setup>
import Code from './code.vue';

const code = ref('clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)');
</script>

<template>
	<Code
	    class="code"
	    language="css"
	    v-model="code">
	</Code>
</template>

再搭配一个 DOM 节点,可用于查看设置的样式。效果如下所示:

样式修改