<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      個人網站建站日記-集成Markdown編輯器

      一次偶然的機會,我體驗的到了markdown的便捷,于是乎,我就著手給我的網站閑蛋博客社區集成了Markdown,現在可以自由的切換Markdown與富文本編輯的使用了。這里我特此分享記錄下安裝使用的過程。

      一、安裝Markdown編輯器

      這里我采用的是md-editor-v3編輯器,目前看來還是很好用的,安裝方便,使用簡單

      二 pnpm安裝 pnpm install md-editor-v3

      注意,直接運行的是安裝的最新版的,最新版本的使用的vue3.5以上,如果你低于3.5的版本,代碼運行的時候可能會報錯,所以安裝的是其它的版本

      pnpm install md-editor-v3@4.21.1

      三、頁面基本使用

      話不多說,直接看代碼

      <template>
          <MdEditor :autoFocus="true" v-model="textContent"  :toolbars="toolbars">
          </MdEditor>
      </template>
      <script lang="ts" setup>
      import { ref, watch } from 'vue';
      import { MdEditor, DropdownToolbar, ToolbarNames, config } from 'md-editor-v3';
      import 'md-editor-v3/lib/style.css';
      const { checkImg } = useUpload();
      const toolbars: ToolbarNames[] = [
          'bold',
          'underline',
          'italic',
          '-',
          'title',
          'strikeThrough',
          'sub',
          'sup',
          'quote',
          'unorderedList',
          'orderedList',
          'task',
          '-',
          'codeRow',
          'code',
          'link',
          'image',
          'table',
          'mermaid',
          'katex',
          '-',
          'revoke',
          'next',
          '=',
          'pageFullscreen',
          'fullscreen',
          'preview',
          'htmlPreview',
          'catalog',
          'github'
      ];
      
      </script>
      

      讓后運行項目如下圖
      image

      這樣就可以了,但是我們看官網,它是可以支持切換主題的,那么怎實現呢。

      四、編輯器切換主題

      實現它就是去使用它的#defToolbars插槽,可以實現

      實現切換預覽主題

      我這里只是默認使用它里面提供的幾個主題,定義預覽主題如下:

      const previewThemeOptions = [
          {
              value: 'default',
              label: 'default'
          },
          {
              value: 'github',
              label: 'github'
          },
          {
              value: 'vuepress',
              label: 'vuepress'
          },
          {
              value: 'mk-cute',
              label: 'mk-cute'
          },
          {
              value: 'smart-blue',
              label: 'smart-blue'
          },
          {
              value: 'cyanosis',
              label: 'cyanosis'
          }
      ];
      

      然后插槽里面的代碼

      <MdEditor :autoFocus="true" v-model="textContent" :previewTheme="previewThemeSelected"
                :toolbars="toolbars">
              <template #defToolbars>
                  <DropdownToolbar title="預覽主題" :visible="showPreviewTheme" :on-change="appendixPreviewThemeChanged">
                      <template #overlay>
                          <el-select v-model="previewThemeSelected" size="small" style="width: 70px"
                              @change="previewThemeChange">
                              <el-option v-for="item in previewThemeOptions" :key="item.value" :label="item.label"
                                  :value="item.value" />
                          </el-select>
                      </template>
                      <template #trigger>
                          <el-icon class="md-editor-icon" :size="18">
                              <Platform />
                          </el-icon>
                      </template>
                  </DropdownToolbar>
              </template>
          </MdEditor>
      

      同時在toolbars里面要加一個對應的索引位置,代表自己的工具欄
      image

      然后運行看下代碼部分截圖

      default主題

      image

      github主題

      image

      smart-blue主題

      image

      以此類推,其它的主題我就不演示了

      圖片上傳

      圖片上傳要實現它的 @on-upload-img="onUploadImg"方法,參考代碼如下,也可以參考官網的寫法,比較簡單

      function onUploadImg(files, callback) {
          files.forEach((s) => {
              let file = s;
              let formData = new FormData();
              formData.append('file', file);
              uploadFileApi(formData).then((res) => {
                  let arr = [];
                  arr.push(res.urlPath);
                  callback(arr);
              });
          });
      }
      

      內容超鏈接target屬性

      如果想實現target屬性需要安裝 markdown-it-link-attributes 插件,讓后代碼加入如下代碼

      import LinkAttr from 'markdown-it-link-attributes';
      config({
          markdownItPlugins(plugins) {
              return [
                  ...plugins,
                  {
                      type: 'linkAttr',
                      plugin: LinkAttr,
                      options: {
                          matcher(href: string) {
                              return !href.startsWith('#');
                          },
                          attrs: {
                              target: '_blank'
                          }
                      }
                  }
              ];
          }
      });
      

      應該沒有什么還有補充了??

      五、頁面如何渲染

      上面搞的差不多后,就要實現文章頁面渲染,我看網上的解決方法都是通過安裝marked插件,然后通過它把markdown語法轉成html,但是我沒有使用。因為我看md-editor-v3已經實現了預覽,并且非常簡單。就是使用MdPreview組件就好了,也不需要額外安裝調樣式。

      import { MdPreview } from 'md-editor-v3';
      import 'md-editor-v3/lib/style.css';
      
        <MdPreview v-else v-model="articleContent" :previewTheme="預覽主題" 
          :codeTheme="代碼主題" />
      

      然后頁面加載渲染就可以了
      image

      真實效果可以點這里 https://www.xiandanplay.com/article/view?id=17143377224138752&articleCategoryId=16078840161206272

      六、代碼示例

      以下代碼僅僅是我的業務代碼,可以參考,具體的可以根據需要自行更改

      <template>
          <MdEditor :autoFocus="true" v-model="textContent" :previewTheme="previewThemeSelected"
              :codeTheme="codeThemeSelected" @on-upload-img="onUploadImg" :toolbars="toolbars">
              <template #defToolbars>
                  <DropdownToolbar title="預覽主題" :visible="showPreviewTheme" :on-change="appendixPreviewThemeChanged">
                      <template #overlay>
                          <el-select v-model="previewThemeSelected" size="small" style="width: 70px"
                              @change="previewThemeChange">
                              <el-option v-for="item in previewThemeOptions" :key="item.value" :label="item.label"
                                  :value="item.value" />
                          </el-select>
                      </template>
                      <template #trigger>
                          <el-icon class="md-editor-icon" :size="18">
                              <Platform />
                          </el-icon>
                      </template>
                  </DropdownToolbar>
                  <DropdownToolbar title="代碼主題" :visible="showCodeTheme" :on-change="appendixCodeThemeChanged">
                      <template #overlay>
                          <el-select v-model="codeThemeSelected" size="small" style="width: 70px" @change="codeThemeChange">
                              <el-option v-for="item in codeThemeOptions" :key="item.value" :label="item.label"
                                  :value="item.value" />
                          </el-select>
                      </template>
                      <template #trigger>
                          <el-icon class="md-editor-icon" :size="18">
                              <Postcard />
                          </el-icon>
                      </template>
                  </DropdownToolbar>
              </template>
          </MdEditor>
      </template>
      <script lang="ts" setup>
      import { ref, watch } from 'vue';
      import { MdEditor, DropdownToolbar, ToolbarNames, config } from 'md-editor-v3';
      import 'md-editor-v3/lib/style.css';
      import { Marked } from 'marked';
      import { useUpload } from '@/hooks/useUpload';
      import { uploadFileApi } from '@/api/uploadFile';
      import { CloudStorageType } from '@/utils/globalDeclare';
      import LinkAttr from 'markdown-it-link-attributes';
      config({
          markdownItPlugins(plugins) {
              return [
                  ...plugins,
                  {
                      type: 'linkAttr',
                      plugin: LinkAttr,
                      options: {
                          matcher(href: string) {
                              return !href.startsWith('#');
                          },
                          attrs: {
                              target: '_blank'
                          }
                      }
                  }
              ];
          }
      });
      const { checkImg } = useUpload();
      const marked = new Marked({ gfm: true });
      const props = defineProps({
          codeTheme: {
              type: String,
              default: 'default'
          },
          previewTheme: {
              type: String,
              default: 'default'
          }
      });
      const toolbars: ToolbarNames[] = [
          'bold',
          'underline',
          'italic',
          '-',
          'title',
          'strikeThrough',
          'sub',
          'sup',
          'quote',
          'unorderedList',
          'orderedList',
          'task',
          '-',
          'codeRow',
          'code',
          'link',
          'image',
          'table',
          'mermaid',
          'katex',
          '-',
          'revoke',
          'next',
          0,
          1,
          '=',
          'pageFullscreen',
          'fullscreen',
          'preview',
          'htmlPreview',
          'catalog',
          'github'
      ];
      const textContent = ref<string>();
      const emit = defineEmits(['changeTheme']);
      const showPreviewTheme = ref(false);
      const showCodeTheme = ref(false);
      const previewThemeOptions = [
          {
              value: 'default',
              label: 'default'
          },
          {
              value: 'github',
              label: 'github'
          },
          {
              value: 'vuepress',
              label: 'vuepress'
          },
          {
              value: 'mk-cute',
              label: 'mk-cute'
          },
          {
              value: 'smart-blue',
              label: 'smart-blue'
          },
          {
              value: 'cyanosis',
              label: 'cyanosis'
          }
      ];
      const codeThemeOptions = [
          {
              value: 'atom',
              label: 'atom'
          },
          {
              value: 'a11y',
              label: 'a11y'
          },
          {
              value: 'github',
              label: 'github'
          },
          {
              value: 'gradient',
              label: 'gradient'
          },
          {
              value: 'kimbie',
              label: 'kimbie'
          },
          {
              value: 'paraiso',
              label: 'paraiso'
          },
          {
              value: 'qtcreator',
              label: 'qtcreator'
          },
          {
              value: 'stackoverflow',
              label: 'stackoverflow'
          }
      ];
      const previewThemeSelected = ref<string>(props.previewTheme);
      const codeThemeSelected = ref<string>(props.codeTheme);
      init();
      function init() {
          let themeStore = localStorage.getItem('mdv3_theme_store');
          if (themeStore) {
              let arr = themeStore.split('|');
              codeThemeSelected.value = arr[0];
              previewThemeSelected.value = arr[1];
              emit('changeTheme', {
                  codeTheme: codeThemeSelected.value,
                  previewTheme: previewThemeSelected.value
              });
          }
      }
      function previewThemeChange(selected) {
          setThemeStore('preview', selected);
      }
      function codeThemeChange(selected) {
          setThemeStore('code', selected);
      }
      function setThemeStore(themeType, themeSelected) {
          let theme: any = {};
          if (themeType == 'code') {
              localStorage.setItem(
                  'mdv3_theme_store',
                  themeSelected + '|' + previewThemeSelected.value
              );
              theme.codeTheme = themeSelected;
              codeThemeSelected.value = themeSelected;
              theme.previewTheme = previewThemeSelected.value;
          } else {
              localStorage.setItem(
                  'mdv3_theme_store',
                  codeThemeSelected.value + '|' + themeSelected
              );
              theme.codeTheme = codeThemeSelected.value;
              theme.previewTheme = themeSelected;
              previewThemeSelected.value = themeSelected;
          }
          emit('changeTheme', theme);
      }
      
      function appendixPreviewThemeChanged() {
          if (showPreviewTheme.value) {
              showPreviewTheme.value = false;
          } else {
              showPreviewTheme.value = true;
          }
      }
      function appendixCodeThemeChanged() {
          if (showCodeTheme.value) {
              showCodeTheme.value = false;
          } else {
              showCodeTheme.value = true;
          }
      }
      function onUploadImg(files, callback) {
          files.forEach((s) => {
              let file = s;
              let result: boolean = checkImg(file, 2);
              if (result == false) {
                  return;
              }
              let formData = new FormData();
              formData.append('file', file);
              formData.append('cloudStorageType', CloudStorageType.Qiniu);
              uploadFileApi(formData).then((res) => {
                  let arr = [];
                  arr.push(res.urlPath);
                  callback(arr);
              });
          });
      }
      function setContent(content) {
          textContent.value = content;
      }
      function getTheme() {
          let theme = {
              codeTheme: codeThemeSelected.value,
              previewTheme: previewThemeSelected.value
          };
          return theme;
      }
      function getText() {
          const plainText = marked
              .parse(textContent.value)
              .replace(/<\/?[^>]+(>|$)/g, '')
              .trim();
          return plainText;
      }
      const getContent = () => {
          return textContent.value
      };
      defineExpose({ getText, getTheme, setContent, getContent });
      </script>
      
      

      作者:程序員奶牛
      個人開源網站:https://www.xiandanplay.com
      源碼地址:https://gitee.com/MrHanchichi/xian-dan

      posted @ 2024-12-15 13:39  灬丶  閱讀(630)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 男女性高爱潮免费网站| 亚洲综合在线日韩av| 成人亚洲国产精品一区不卡| 欧美人妻在线一区二区| 欧美成人精品三级在线观看| 99国精品午夜福利视频不卡99| 免费无码成人AV片在线| 日韩精品亚洲aⅴ在线影院| 97人妻免费碰视频碰免| 性动态图无遮挡试看30秒| 人妻人人澡人人添人人爽人人玩| 韩国美女福利视频在线观看| 东丽区| 亚洲人妻中文字幕一区| 中文日产幕无线码一区中文| 日韩精品一区二区三区影院| 蜜臀精品视频一区二区三区| 亚洲中文一区二区av| 亚洲码欧洲码一二三四五| 尼木县| 美女爽到高潮嗷嗷嗷叫免费网站| 91精品国产免费人成网站| 亚洲VA中文字幕无码久久| 亚洲激情国产一区二区三区| 国产精品毛片一区二区| 国产乱精品一区二区三区| 亚洲国产精品久久久天堂麻豆宅男| 亚洲国产成人精品女久久| 亚洲中文精品一区二区| 日韩精品一区二区三区影院| 欧美精品黑人粗大破除| 国产极品美女高潮无套| 亚洲天堂男人天堂女人天堂| 草草浮力影院| 国产在线高清视频无码| 国产精品美腿一区在线看| 精品 日韩 国产 欧美 视频| 日韩亚洲国产激情一区二区| 日本道精品一区二区三区| 亚洲中文字幕无码一区无广告| 国产日韩乱码精品一区二区|