vue2集成markdown编辑器及前台渲染

news2024/12/24 22:12:29

效果展示

后台编辑器
image-20240721164815250

前台渲染
image-20240721164519145

后台编辑器步骤

安装包

npm i @kangc/v-md-editor -S

main.js里全局注册

编辑器VueMarkdownEditor组件

import Vue from 'vue';
import VueMarkdownEditor from '@kangc/v-md-editor';
import '@kangc/v-md-editor/lib/style/base-editor.css';
import vuepressTheme from '@kangc/v-md-editor/lib/theme/vuepress.js';
import '@kangc/v-md-editor/lib/theme/style/vuepress.css';
import Prism from 'prismjs';
VueMarkdownEditor.use(vuepressTheme, {
  Prism,
});
Vue.use(VueMarkdownEditor);

VMDEditor.vue文件

自己内部

<template>
  <div>
    <v-md-editor
      v-model="editorValue"
      :disabled-menus="[]"
      height="calc(100vh - 150px)"
      @upload-image="handleUploadImage"
    />
  </div>
</template>

<script>
export default {
  name: 'MdEditor',
  props: {
    // 接收值父组件传递值
    content: String
  },
  data() {
    return {
      editorValue: this.content != null ? this.content : '',
    }
  },
  watch: {
    editorValue: function(newNum, oldNum) {
      // 修改调用者传入的值
      this.$emit('update:content', newNum)
    }
  },
  methods: {
    // v-md-editor 文件上传
    handleUploadImage(event, insertImage, files) {
      // console.log(files);
      // 上传
      for (let i = 0; i < files.length; i++) {
        this.crud.upload(files[i], 'image/vMdEditor/').then(res => {
          // 获取返回数据
          const data = res.data.data
          // 添加图片到内容
          insertImage({
            url: data.url,
            desc: data.name
          })
        })
      }
    }
  }
}
</script>

<style>
</style>

在需要用到的页面里引入注册并使用

image-20240721165543626

监听输入框并给页面传值

使用到了父子组件emit on传值方法

子组件

image-20240721165801321

父组件

image-20240721165848662

编辑时回显数组

如果是发布新增,路径参数为0,如果是修改,参数为文章id,以此区分编辑还是发布

编辑时记录当前文章的所有信息在vuex里

image-20240721170143357

操作文章的组件里挂载时判断是编辑还是新增,编辑则获取vuex数据到form表单对象

image-20240721170306908

然后表单数据给md编辑器组件传值,md接收绑定即可
image-20240721170407049

image-20240721170439520

前台渲染md格式数据步骤

main.js 引入

github主题

image-20240721171010102
import VMdPreview from '@kangc/v-md-editor/lib/preview';
import '@kangc/v-md-editor/lib/style/base-editor.css';
import '@kangc/v-md-editor/lib/style/preview.css';
// github主题
import githubTheme from '@kangc/v-md-editor/lib/theme/github.js'
import '@kangc/v-md-editor/lib/theme/style/github.css'
import hljs from 'highlight.js'
VMdPreview.use(githubTheme,{
    Hljs: hljs
})
Vue.use(VMdPreview)

vuepress主题

image-20240721171351156

main.js

import VMdPreview from '@kangc/v-md-editor/lib/preview';
import '@kangc/v-md-editor/lib/style/base-editor.css';
import '@kangc/v-md-editor/lib/style/preview.css';
// vuepressTheme主题
import vuepressTheme from '@kangc/v-md-editor/lib/theme/vuepress.js';
import '@kangc/v-md-editor/lib/theme/style/vuepress.css';
import Prism from 'prismjs';
VMdPreview.use(vuepressTheme,{
    Prism
})
Vue.use(VMdPreview)

还需要安装一个包和修改配置文件

npm install babel-plugin-prismjs

在babel.config.js里 按需引入对应语言

// babel.config.js
module.exports = {
  plugins: [
    [
      'prismjs',
      {
        languages: ['json'],
      },
    ],
  ],
};

引入所有语言

const components = require('prismjs/components');
const allLanguages = Object.keys(components.languages).filter((item) => item !== 'meta');
module.exports = {
  plugins: [
    [
      'prismjs',
      {
        languages: allLanguages
      },
    ],
  ],
}

渲染组件的使用

image-20240721171916909

点击按钮复制代码块内容

image-20240721172255084

image-20240721172324210

// main.js
import createCopyCodePlugin from '@kangc/v-md-editor/lib/plugins/copy-code/index';
import '@kangc/v-md-editor/lib/plugins/copy-code/copy-code.css';
VMdPreview.use(createCopyCodePlugin());

如果想要点击后弹框则在组件上设置监听事件对应的回调即可

image-20240721172504850

文章目录的展示

method

思路

获取所有h1-h6标签的的document文档设置id

过滤标题标签内容不为空的

使用set集合的不重复特性,获取所有h标签,后续根据标签名,确定缩进值大小,h1-> 缩进级别为1,根据级别*padding-left的固定值实现分层

(也可以使用获取nodeName的第二个值也就是h1=> 1 获取层次等级)

加工titles数组,所有对象有id,level(indent)层级

结尾设置监听器,等待文章目录的a标签映射上去之后监听,点击后调用高亮方法.将自身作用参数传递过去,增加类样式

getTitles() {
    // 文章目录操作
    const anchors = this.$refs.articleContent.$el.querySelectorAll('h1,h2,h3,h4,h5,h6');
    // 给h1,2,3标签设置id
    anchors.forEach((item, index) => {
        item.setAttribute('id', 'header-' + index)
    })
    // 存数组,后续监听该标题的变化位置来高亮标题
    this.titlesDoms = anchors

    // 判断标题里是否为空
    const titles = Array.from(anchors).filter((title) => title.innerText.trim() !== null);
    if (!titles.length) {
        this.titles = [];
        return;
    }

    const hTags = Array.from(new Set(titles.map((title) => title.tagName))).sort();
    this.titles = titles.map((el, index) => ({
        id: 'header-' + index,
        title: el.innerText,
        // lineIndex: el.getAttribute('data-v-md-line'),
        level: Number(el.nodeName.substring(1, 2)),
        indent: hTags.indexOf(el.tagName),
    }));
    setTimeout(() => {
        this.setClickListen()
        // 初始化高亮
    }, 50)
},
    setClickListen() {
        const headers = document.querySelectorAll('a');
        headers.forEach(header => {
            // 如果是id为header开始的a标签,则设置监听
            if (header.id.startsWith('header')) {
                //监听自己,如果被点击了,就触发函数,将自己丢过去
                header.addEventListener('click', () => {
                    this.highlight(header)
                })
            }
        })
    },
        highlight(header) {
            // 清空所有a标签的高亮,进行初始化
            document.querySelectorAll('a.highlight')
                .forEach(a => a.classList.remove('highlight'));
            //将此次点击的header目录进行添加高亮
            if (document.querySelector(`a#${header.id}`) === null) {
                console.log('空')
                return
            }
            document.querySelector(`a#${header.id}`).classList.add('highlight')
        }

监听滚动视窗原理 在以往的文章有提及,可自行查找,这里不过多赘述了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1939427.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker核心技术:应用架构演进

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Docker核心技术 系列文章&#xff1a;应用架构演进&#xff0c;其他文章快捷链接如下&#xff1a; 应用架构演进&#xff08;本文&#xff09;容器技术要解决哪些问题Docker的基本使用Docker是如何实现的 1.1.架…

matlab simulink气隙局部放电仿真技术研究

1、内容简介 略 87-可以交流、咨询、答疑 2、内容说明 略 为了解决目前国内外局部放电仿真方法难以计算气隙局部放电暂态过程的问题 , 利用 MATLAB (SIMULINK ) 的公共模块库和电力系统专业模块库 , 根据单气隙局部放电仿真物理模型 , 构造了气隙局部放 电仿真计算的电…

进程间通信——共享内存,信号量,信号

进程 VS 线程通信 进程&#xff1a;共享内存&#xff0c;消息队列&#xff0c;管道&#xff0c;信号&#xff08;条件变量&#xff0c;锁&#xff0c;信号量需要搭配共享内存使用&#xff09;&#xff1b; 线程&#xff1a;信号&#xff0c;条件变量&#xff0c;锁&#xff0c…

C语言·分支和循环语句(超详细系列·全面总结)

前言&#xff1a;Hello大家好&#x1f618;&#xff0c;我是心跳sy&#xff0c;为了更好地形成一个学习c语言的体系&#xff0c;最近将会更新关于c语言语法基础的知识&#xff0c;今天更新一下分支循环语句的知识点&#xff0c;我们一起来看看吧~ 目录 一、什么是语句&#xf…

C语言航空售票系统

以下是系统部分页面 以下是部分源码&#xff0c;需要源码的私信 #include<stdio.h> #include<stdlib.h> #include<string.h> #define max_user 100 typedef struct ft {char name[50];//名字char start_place[50];//出发地char end_place[50];//目的地char …

【专项刷题】— 归并

1、排序数组 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 先找一个中间值&#xff0c;然后递归左边部分和递归右半部分直到左边和右边只剩一个数了就返回&#xff0c;然后再合并左右两个部分代码&#xff1a; class Solution {int[] tmp;public int[] sortArray(…

canvas:矢量点转栅格

案例描述 ArcGIS提供了“点转栅格”的工具,可以将矢量点转换为栅格数据,以下尝试基于canvas绘图技术,实现经纬度矢量点转换为canvas栅格数据,并在Cesium.js三维地图中进行渲染。 原始数据 转出栅格 案例分析 实现的关键点在于:如何将经纬度坐标与canvas画布坐标进…

Java代码基础算法练习-三角形判断-2024.07.21

任务描述&#xff1a; 解决思路&#xff1a; 一个函数&#xff0c;带入输入的三个边长参数&#xff0c;条件满足计算其周长、面积&#xff0c;否则不计算 代码示例&#xff1a; package a4_2024_07;import java.util.Scanner;public class j240721_2 {public static void mai…

Pytorch学习笔记【B站:小土堆】

文章目录 1 基础环境配置&#xff08;CPU版&#xff09;2 PyTorch学习2.1 Dataset和DataLoader2.1.1 Dataset2.1.2 DataLoader 2.2 Tensorboardadd_scalaradd_imageadd_graph 2.3 Transforms2.3.1 ToTensor2.3.2 Normalize2.3.3 Resize2.3.4 Compose 2.4 torchvision中的数据集…

MQTTX连接华为云IoTDA

目录 华为IoTDA平台 MQTTX连接参数的设置 物模型的构建 属性上报 基本数据格式 时戳 我以前上课都是用巴法云服务器来演示MQTT的&#xff0c;前几天因为测试工业互联网关使用了华为的IoTDA&#xff0c;觉得也不算太复杂&#xff0c;今天尝试用MQTTX连接华为云&#xff0c…

NLP: 词袋模型和TFIDF模型

文章目录 词袋模型TF-IDF模型词汇表模型 词袋模型 文本特征提取有两个非常重要的模型&#xff1a; 词集模型&#xff1a;单词构成的集合&#xff0c;集合自然每个元素都只有一个&#xff0c;也即词集中的每个单词都只有一个。 词袋模型&#xff1a;在词集的基础上如果一个单词…

DDPM扩散模型(模型结构图与公式推导)

DDPM扩散模型 一、前置知识 1. 条件概率知识 P ( A ∣ B ) P ( A B ) P ( B ) P(A|B) \frac{P(AB)}{P(B)} P(A∣B)P(B)P(AB)​ P ( A B C ) P ( C ∣ B A ) P ( B A ) P ( C ∣ B A ) P ( B ∣ A ) P ( A ) P(A B C) P(C|B A)P(BA) P(C|B A)P(B|A)P(A) P(ABC)P(C∣BA)P…

Java | 自制AWT单词猜一猜小游戏(测试版)

目录 游戏标题 开发过程 开发想法 技术栈 代码呈现 导包 核心代码 游戏标题 探索知识的迷宫&#xff0c;体验自制AWT单词猜一猜小游戏 在数字时代&#xff0c;学习可以是多彩的&#xff0c;游戏可以是智慧的。我们自豪地推出“单词猜猜猜”是一款结合了教育与娱乐的自制…

NODEJS复习(ctfshow334-344)

NODEJS复习 web334 下载源码代码审计 发现账号密码 代码逻辑 var findUser function(name, password){ return users.find(function(item){ return name!CTFSHOW && item.username name.toUpperCase() && item.password password; }); }; 名字不等于ctf…

2015年全国大学生数学建模竞赛B题出租车资源配置(含word论文和源代码资源)

文章目录 一、部分题目二、部分论文三、部分源代码问题1问题3 四、完整word版论文和源代码 一、部分题目 2015高教社杯全国大学生数学建模竞赛题目 B题 “互联网”时代的出租车资源配置 出租车是市民出行的重要交通工具之一&#xff0c;“打车难”是人们关注的一个社会热点问…

【CSS in Depth 2 精译_019】3.2 CSS 的盒模型

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

STM32基础篇:USART(下)

双缓冲与连续发送 双缓冲 在发送数据的时候&#xff0c;首先将要发送的字节写入TDR中&#xff0c;然后TDR将此字节发生给移位寄存器&#xff0c;由移位寄存器执行串并转换&#xff0c;通过Tx引脚逐个比特位发送出去。 在此过程中&#xff0c;存在两级缓冲&#xff0c;即双缓…

[GIS实验]居住环境适宜性评价

目的&#xff1a; 拟购买住宅&#xff0c;需在现有条件下&#xff0c;基于地理空间分析方法和空间认知模型对居住环境进行综合评价。通过该实验掌握基于GIS的地理空间认知方法及土地适宜性评价基本原理与方法。 数据&#xff1a; &#xff08;1&#xff09;人口调查图&#…

记录uni-app横屏项目:自定义弹出框

目录 前言&#xff1a; 正文&#xff1a; 前言&#xff1a;横屏的尺寸问题 最近使用了uniapp写了一个横屏的微信小程序和H5的项目&#xff0c;也是本人首次写的横屏项目&#xff0c;多少是有点踩坑不太适应。。。 先说最让我一脸懵的点&#xff0c;尺寸大小&#xff0c;下面一…

探索Python错误美化:pretty_errors库的魔法之旅

探索Python错误美化&#xff1a;pretty_errors库的魔法之旅 背景&#xff1a;为什么需要pretty_errors&#xff1f; 在Python编程中&#xff0c;错误和异常是不可避免的。然而&#xff0c;Python默认的错误信息往往不够直观&#xff0c;对于新手来说可能难以理解。pretty_erro…