最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue3實現(xiàn)markdown預(yù)覽和編輯詳解

 更新時間:2025年10月25日 10:13:23   作者:Z編程  
本文介紹了如何在Vue3項目中集成Vditor Markdown編輯器,包括Vditor的簡介、安裝、預(yù)覽、編輯以及一些高級功能和常見問題解決,Vditor支持多種編輯模式、圖表、公式等,且高度可定制化

Markdown作為一種輕量級標記語言,已經(jīng)成為開發(fā)者編寫文檔的首選工具之一。

在Vue3項目中集成Markdown編輯和預(yù)覽功能可以極大地提升內(nèi)容管理體驗。

本文將介紹如何使用Vditor這一強大的開源Markdown編輯器在Vue3項目中實現(xiàn)這一功能。

一、Vditor簡介

Vditor是一款瀏覽器端的Markdown編輯器,支持所見即所得(WYSIWYG)、即時渲染(IR)和分屏預(yù)覽模式。

它具有以下特點:

二、安裝Vditor

在項目中安裝Vditor:

npm install vditor --save

三、實現(xiàn)預(yù)覽

Vdior中提供了專門的預(yù)覽方法來針對不需要編輯僅需要展示markdown文檔的場景

下面是我封裝的一個預(yù)覽組件

<script setup lang="ts">
import { ref, onMounted, watch } from "vue";
import VditorPreview from "vditor/dist/method.min";

/**
 * Markdown預(yù)覽組件
 * @component
 */
const props = defineProps({
  /**
   * Markdown內(nèi)容
   */
  content: {
    type: String,
    required: true
  },
  /**
   * 預(yù)覽選項
   */
  options: {
    type: Object,
    default: () => ({})
  }
});

/**
 * 預(yù)覽容器引用
 */
const previewRef = ref<HTMLDivElement | null>(null);

/**
 * 默認預(yù)覽配置
 */
const defaultOptions = {
  cdn: "https://ld246.com/js/lib/vditor",
  mode: "dark",
  anchor: 1,
  hljs: {
    lineNumber: true,
    style: "github"
  },
  math: {
    inlineDigit: true,
    macros: {}
  },
  theme: {
    current: "dark"
  },
  lazyLoadImage: "http://unpkg.com/vditor/dist/images/img-loading.svg"
};

/**
 * 合并配置項
 */
const mergedOptions = {
  ...defaultOptions,
  ...props.options
};

/**
 * 渲染Markdown內(nèi)容
 */
const renderMarkdown = () => {
  if (previewRef.value) {
    VditorPreview.preview(previewRef.value, props.content, mergedOptions);
  }
};

/**
 * 組件掛載完成后渲染Markdown
 */
onMounted(() => {
  renderMarkdown();

  // 渲染其他特殊語法
  VditorPreview.mermaidRender(document);
  VditorPreview.codeRender(document);
  VditorPreview.mathRender(document);
  VditorPreview.abcRender(document);
  VditorPreview.chartRender(document);
  VditorPreview.mindmapRender(document);
  VditorPreview.graphvizRender(document);
});

/**
 * 監(jiān)聽內(nèi)容變化重新渲染
 */
watch(
  () => props.content,
  () => {
    renderMarkdown();
  }
);
</script>

<template>
  <div class="vditor-preview-container">
    <div ref="previewRef" class="vditor-preview" />
  </div>
</template>

<style scoped>
.vditor-preview-container {
  width: 100%;
}

.vditor-preview {
  box-sizing: border-box;
  padding: 16px;
  color: #ccc;
  background-color: #1a1a1a;
  border-radius: 8px;
}

:deep(.vditor-reset) {
  background: #1a1a1a;
}

:deep(.vditor-reset h1),
:deep(.vditor-reset h2),
:deep(.vditor-reset h3),
:deep(.vditor-reset h4),
:deep(.vditor-reset h5),
:deep(.vditor-reset h6) {
  /* color: #06ad7e; */
  margin-top: 1.5em;
  margin-bottom: 0.5em;
  font-weight: 600;
  border-bottom: none;
}

:deep(.vditor-reset h3) {
  padding-bottom: 0.3em;
  font-size: 1.3em;
}

:deep(.vditor-reset strong) {
  font-weight: 600;
  color: #fff;
}
</style>

 使用:

<script setup lang="ts">
import { ref } from "vue";
import VditorPreview from "@/components/markdown/VditorPreview.vue";
const chiefComplaint = ref("");
</script>
<template>
            <VditorPreview
              :content="chiefComplaint"
              :options="{
                mode: 'dark',
                theme: {
                  current: 'dark'
                }
              }"
            />
</template>

四、實現(xiàn)編輯

編輯組件按照Vditor文檔來使用Vditor編輯器即可

<script setup lang="ts">
import "vditor/dist/index.css";
import Vditor from "vditor";
import { useIntervalFn } from "@vueuse/core";
import { onMounted, ref, watch, toRaw, onUnmounted } from "vue";

const emit = defineEmits([
  "update:modelValue",
  "after",
  "focus",
  "blur",
  "esc",
  "ctrlEnter",
  "select"
]);

const props = defineProps({
  options: {
    type: Object,
    default() {
      return {};
    }
  },
  modelValue: {
    type: String,
    default: ""
  },
  isDark:{
    type: Boolean,
    default: true
  },
});

const editor = ref<Vditor | null>(null);
const markdownRef = ref<HTMLElement | null>(null);

onMounted(() => {
  editor.value = new Vditor(markdownRef.value as HTMLElement, {
    ...props.options,
    value: props.modelValue,
    cache: {
      enable: false
    },
    fullscreen: {
      index: 10000
    },
    toolbar: [
      "headings",
      "bold",
      "italic",
      "strike",
      "|",
      "line",
      "quote",
      "list",
      "ordered-list",
      "|",
      "check",
      "insert-after",
      "|",
      "insert-before",
      "undo",
      "redo",
      "link",
      "|",
      "table",
      "br",
      "fullscreen"
    ],
    cdn: "https://ld246.com/js/lib/vditor",
    after() {
      emit("after", toRaw(editor.value));
    },
    input(value: string) {
      emit("update:modelValue", value);
    },
    focus(value: string) {
      emit("focus", value);
    },
    blur(value: string) {
      emit("blur", value);
    },
    esc(value: string) {
      emit("esc", value);
    },
    ctrlEnter(value: string) {
      emit("ctrlEnter", value);
    },
    select(value: string) {
      emit("select", value);
    }
  });
});

watch(
  () => props.modelValue,
  newVal => {
    if (newVal !== editor.value?.getValue()) {
      editor.value?.setValue(newVal);
    }
  }
);

watch(
  () => props.isDark,
  newVal => {
    const { pause } = useIntervalFn(() => {
      if (editor.value.vditor) {
        newVal
          ? editor.value.setTheme("dark", "dark", "rose-pine")
          : editor.value.setTheme("classic", "light", "github");
        pause();
      }
    }, 20);
  }
);

onUnmounted(() => {
  const editorInstance = editor.value;
  if (!editorInstance) return;
  try {
    editorInstance?.destroy?.();
  } catch (error) {
    console.log(error);
  }
});
</script>

<template>
  <div ref="markdownRef" />
</template>

使用

 <Vditor
            v-model="chiefComplaintContent"
            :options="{
              mode: 'ir',
              outline: { enable: false, position: 'right' },
              toolbarConfig: {
                pin: true
              }
            }"
          />

五、高級功能實現(xiàn)

這些都是options中的配置項,如果需要使用,直接將其加入options對象中即可

1. 自定義工具欄

Vditor允許完全自定義工具欄配置。以下是一個精簡版的工具欄配置:

toolbar: [
  'headings',
  'bold',
  'italic',
  'strike',
  '|',
  'list',
  'ordered-list',
  'check',
  '|',
  'quote',
  'code',
  'inline-code',
  '|',
  'upload',
  '|',
  'undo',
  'redo',
  '|',
  'fullscreen',
],

2. 圖片上傳處理

upload: {
  accept: 'image/*',
  handler(files) {
    // 這里實現(xiàn)上傳邏輯
    const file = files[0];
    const formData = new FormData();
    formData.append('file', file);
    
    // 示例:使用axios上傳
    axios.post('/api/upload', formData)
      .then(response => {
        const url = response.data.url;
        editor.value.insertValue(`![圖片描述](${url})`);
      })
      .catch(error => {
        console.error('上傳失敗:', error);
      });
    
    return false; // 阻止默認上傳行為
  },
},

六、常見問題解決

1. 自定義樣式

我采用的方式是給父容器加一個樣式,然后不使用scope寫css解決

<style lang="scss">
/* 自定義抽屜樣式 */
.report-drawer .el-drawer__header {
  padding: 8px 20px !important;
  margin-bottom: 0 !important;
  font-size: 16px !important;
  color: #fff !important;
  border-bottom: 1px solid #383838 !important;
}

.report-drawer .vditor-ir {
  overflow-x: hidden !important;
}

.report-drawer .vditorv .ditor-toolbar {
  overflow-x: auto;
}

.report-drawer .vditor--dark .vditor--fullscreen .ditor-toolbar {
  overflow-y: auto;
}

.report-drawer .vditor--dark .vditor--fullscreen .ditor {
  height: 100% !important;
}

/* Vditor的預(yù)覽區(qū)域樣式 */
.report-drawer .vditor-preview {
  overflow-x: hidden !important;

}

.report-drawer .vditor-ir pre.vditor-reset {
  max-height: 100vh !important;
  overflow-y: auto;
  padding: 0 60px !important;
}

/* 按鈕樣式 */
.el-button {
  border-radius: 4px !important;
}
</style>

 需要注意的是預(yù)覽區(qū)域的樣式和選擇的模式有關(guān),如果我設(shè)置的是ir,那么我預(yù)覽區(qū)域的樣式是.vditor-ir pre.vditor-reset

2.中文提示

Vditor的默認提示是英文的,可以設(shè)置中文:

new Vditor(editorContainer.value, {
  lang: 'zh_CN',
  // ...其他配置
});

3.cdn配置

在使用時可能會碰到css文件和js文件無法加載的情況,這是因為Vditor默認的cdn地址失效,需要在options中傳入最新的可用cdn地址,目前可用的是https://ld246.com/js/lib/vditor

    cdn: "https://ld246.com/js/lib/vditor", 

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue封裝axios與api接口管理的完整步驟

    vue封裝axios與api接口管理的完整步驟

    在實際的項目中,和后臺的數(shù)據(jù)交互是少不了的,我通常使用的是 axios 庫,所以下面這篇文章主要給大家介紹了關(guān)于vue封裝axios與api接口管理的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • vue鼠標hover(懸停)改變background-color移入變色問題

    vue鼠標hover(懸停)改變background-color移入變色問題

    這篇文章主要介紹了vue鼠標hover(懸停)改變background-color移入變色問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • vue一直自動換行的問題及解決

    vue一直自動換行的問題及解決

    這篇文章主要介紹了vue一直自動換行的問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • vue幾個常用跨域處理方式介紹

    vue幾個常用跨域處理方式介紹

    本篇文章給大家詳細介紹了vue跨域處理問題的方式以及相關(guān)知識點介紹,對此有興趣的朋友學(xué)習(xí)下。
    2018-02-02
  • vue?watch中如何獲取this.$refs.xxx節(jié)點

    vue?watch中如何獲取this.$refs.xxx節(jié)點

    這篇文章主要介紹了vue?watch中獲取this.$refs.xxx節(jié)點的方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • vue.js Router中嵌套路由的實用示例

    vue.js Router中嵌套路由的實用示例

    這篇文章主要給大家介紹了關(guān)于vue.js Router中嵌套路由的相關(guān)資料,所謂嵌套路由就是路由里面嵌套他的子路由,文章通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-06-06
  • Vue3實現(xiàn)組件二次封裝的小技巧分享

    Vue3實現(xiàn)組件二次封裝的小技巧分享

    組件的二次封裝:保留組件已有的功能,需要重寫組件方法,當組件已有大量功能時候,則需要重寫很多重復(fù)代碼,且組件功能進行修改的時候,封裝的組件也需要對應(yīng)修改,從而造成許多開發(fā)和維護成本,本文給大家分享了Vue3實現(xiàn)組件二次封裝的小技巧,需要的朋友可以參考下
    2024-09-09
  • vue-cropper組件實現(xiàn)圖片切割上傳

    vue-cropper組件實現(xiàn)圖片切割上傳

    這篇文章主要為大家詳細介紹了vue-cropper組件實現(xiàn)圖片切割上傳,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • Vue3使用icon的兩種方式實例

    Vue3使用icon的兩種方式實例

    vue開發(fā)網(wǎng)站的時候,往往圖標是起著很重要的作用,下面這篇文章主要給大家介紹了關(guān)于Vue3使用icon的兩種方式,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-11-11
  • 解決el-menu標題過長顯示不全問題

    解決el-menu標題過長顯示不全問題

    本文主要介紹了如何解決el-menu標題過長顯示不全問題,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,感興趣的朋友們跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-12-12

最新評論

金寨县| 巫溪县| 上栗县| 遂昌县| 馆陶县| 珠海市| 禹州市| 论坛| 江北区| 五常市| 清流县| 迁安市| 台中县| 临城县| 阳信县| 乡城县| 莱阳市| 藁城市| 蒙山县| 靖安县| 尉氏县| 普宁市| 疏附县| 广西| 米脂县| 醴陵市| 运城市| 永平县| 郯城县| 晋州市| 神农架林区| 邢台县| 崇文区| 讷河市| 莫力| 南皮县| 怀集县| 三原县| 苏尼特左旗| 荥阳市| 陵川县|