vue中使用vditor(发布,编辑,详情回显、上传图片+粘贴图片回显问题,表情的处理)

2023-11-07

1.使用方法

1.html

安装

npm install vditor --save

vue页面

<div id="markdownContent"></div>

2.dom(发布和编辑页面)

引入

import Vditor from "vditor"
import "vditor/dist/index.css"
mounted() {
 this.getToken()
 this.vditorFun()
},
methods: {
//编辑器
      vditorFun() {
        let self = this
        this.contentEditor = new Vditor("markdownContent",{
          height:600,
          width:800,
          placeholder:'开始编辑...',
          toolbar: [
            // "emoji",  表情
            "headings",
            "bold",
            "italic",
            "strike",
            "link",
            "|",
            "list",
            "ordered-list",
            // "check",
            "outdent",
            "indent",
            "|",
            "quote",
            "line",
            "code",
            "inline-code",
            "insert-before",
            "insert-after",
            "|",
            // "upload",默认上传
            { //自定义上传
              hotkey: "",
              name: "upload",
              // tipPosition: "s",
              tip: "上传图片",
              className: "right",
            },
            // "record",
            "table",
            "|",
            "undo",
            "redo",
            "|",
            "fullscreen",
            "edit-mode",
            {
              name: "more",
              toolbar: [
                "both",
                // "code-theme",
                // "content-theme",
                "export",
                "outline",
                "preview",
                // "devtools",
                // "info",
                // "help",
              ],
            }
            // ,"|",
            // {
            //   hotkey: "⌘-S",
            //   name: "save",
            //   tipPosition: "s",
            //   tip: "保存",
            //   className: "right",
            //   icon: `<img style="height: 16px" src='https://img.58cdn.com.cn/escstatic/docs/imgUpload/idocs/save.svg'/>`,
            //   click() {
            //     that.saveDoc();
            //   }
            // },
          ],
          toolbarConfig:{
            pin:true
          },
          counter: {
	          enable: true,
	          type:'字数统计',
	        },
          //默认开启了大纲
          outline: {
            enable: true
          },
          cache:{
            enable:false
          },
          //编辑器有焦点和失去焦点可以判断是否有内容,此处自己封装检查校验即可
          blur() {
            self.vaditEditorContent()
          },
          focus() {
            self.vaditEditorContent()
          },
          //因我的需求是不需要表情符号,所以把编辑器中的表情符号都删除
          input(val) {
            let pattern = new RegExp('[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]');
            if (val != "" && val != null) {
             //去除表情
            let rs = "";
            if (pattern.test(val)) {
              for (let i = 0; i < val.length; i++) {
                rs = rs + val.substr(i, 1).replace(pattern, '');
              }
            } else {
              rs = val
            }
            //替换防盗链图片,有两种方法,第一种是替换页面的图片路径,替换页面的需要在详情回显的时候也需要进行处理,方法和替换页面的方法一样;第二是直接替换md格式数据中的地址

			 第一种:
	           let reg = /(http|https):\/\/([\w.]+\/?)\S*/gi;
	            let valueMatch = rs.match(reg);
	            let replaceUrl = self.gb.mdImgPath('')
	            self.contentEditor.setValue(rs)
	            setTimeout(() => {
	              let imgLinkPar = $('.vditor-ir').find('.vditor-reset').children('p')
	              let childTag = imgLinkPar.find('span.vditor-ir__node')
	              childTag.each(function () {
	                let imgLinkTag = $(this).find('img').attr('src')+')'
	                for (let k = 0; k < valueMatch.length; k++) {
	                  if (imgLinkTag == valueMatch[k]) {
	                    $(this).find('img').attr('src', replaceUrl)
	                  }
	                }
	              })
	            }, 300);
	           第二种: 
	            setTimeout(() => {
	              //替换防盗链图片
	              let reg = /(http|https):\/\/([\w.]+\/?)\S*/gi;
	              if (reg.test(rs)) {
	                let valueMatch = rs.match(reg);
	                // console.log(valueMatch)
	                let replaceUrl = self.gb.mdImgPath('')+')'
	                let linkOutUrl = rs
	                let urlStr
	                for (let k = 0; k < valueMatch.length; k++) {
	                  let ishttps = 'https:' == valueMatch[k] ? true: false;
	                  if(ishttps){
	                    urlStr = valueMatch[k].split("https://");
	                  }else{
	                    urlStr = valueMatch[k].split("http://");
	                  }
	                  // console.log(urlStr)
	                  const index = valueMatch[k].indexOf("/")+2;
	                  let endUrl = valueMatch[k].substring(index)
	                  let threeSplit = endUrl.split('/')
	                  let getThree = threeSplit.slice(0, threeSplit.length-3).join('/')
	                  // console.log(getThree)
	                  if (getThree == 'mmbiz.qpic.cn') {
	                    linkOutUrl = linkOutUrl.replace(valueMatch[k], replaceUrl)
	                  }
	                }
	                self.contentEditor.setValue(linkOutUrl)
	              }
	            }, 2000);
            }
          },
          //编辑页面使用,发布页面不需要
          after: () => {
            self.contentEditor.setValue(self.activityForm.activity_content)
          },
          //这里写上传
          upload:{
            accept:'image/jpg, image/jpeg, image/png',//规定上传的图片格式
            url:this.gb.reqPath('/v1/Activity/upload'),//请求的接口
            multiple: false,
            fieldName: 'file',
            max: 2 * 1024 * 1024,//上传图片的大小
            extraData: {'access_token': this.token}, //为 FormData 添加额外的参数
            linkToImgUrl:this.gb.reqPath('/v1/Activity/upload'),
            filename(name) {
              return name.replace(/[^(a-zA-Z0-9\u4e00-\u9fa5\.)]/g, "")
                .replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, "")
                .replace("/\\s/g", "");
            },
            validate(msg) {
              console.log(msg+"格式")
            },
            //粘贴图片回显处理,如果有图片加了防盗链,则让后台代理替换成自己的图片
            linkToImgFormat(files) {
              let code = 0
              let msg = ''
              let data = JSON.parse(files)
              // let linkImgName = data.result.path
              // //上传图片请求状态
              if(data.ret_code == 200) {
                // let lastTipNum = linkImgName.substr(linkImgName.lastIndexOf('/', linkImgName.lastIndexOf('/') - 1) + 1);
                // let index = lastTipNum.lastIndexOf("\/");
                // let imgUrl = decodeURI(lastTipNum.substring(index + 1, lastTipNum.length));
                let responseData = self.gb.imgOutLinkPath(data.result.path)
                let succUrl = {}
                let originalURL = 'originalURL'
                let url = 'url'
                succUrl[originalURL] = data.result.originalURL
                succUrl[url] = responseData
                let end = JSON.stringify({
                  msg,
                  code,
                  data: succUrl
                })
                return end
              } else {
                self.$message({
                  message: '图片上传失败!',
                  type: 'error'
                })
              }
            },
            //上传图片回显处理
            format(files, responseText){
              // let imageResult = JSON.parse(responseText)
              let code = JSON.parse(responseText)
              let msg = JSON.parse(responseText)
              let data = JSON.parse(responseText)
              let filName = data.result.cover_files
              //上传图片请求状态
              if(data.ret_code == 200) {
                let lastTipNum = filName.substr(filName.lastIndexOf('/', filName.lastIndexOf('/') - 1) + 1);
                let index = lastTipNum.lastIndexOf("\/");
                self.imgNameStr = decodeURI(lastTipNum.substring(index + 1, lastTipNum.length));
                let responseData = self.gb.imgPath(data.result.cover_files)
                let succ = {}
                succ[self.imgNameStr] = responseData
                //图片回显
                return JSON.stringify({
                  msg,
                  code,
                  data:{
                    errFiles: [],
                    succMap: succ
                    // succMap: {
                    //   'default.png': `${responseData}`
                    // }
                  }
                })
              } else {
                self.$message({
                  message: '图片上传失败!',
                  type: 'error'
                })
              }

            },
            error(msg) {
              console.log(msg+"上传失败了")
            },
          }
        })
      },
      //token
      getToken () {
        this.token = getStore('token')
      },
}

3.(详情页面)

1.页面

<span class="markDownTitle">活动详情:</span>
<div id="previewVd"></div>

2.引入

  import Vditor from "vditor"
  import "vditor/dist/index.css"

3.dom

mounted() {
      setTimeout(() => {
        //编辑器回显,this.activityInfo为后端返回的编辑器内容,也可在返回成功中引用
        Vditor.preview(document.getElementById('previewVd'),this.activityInfo)
      }, 500);
    },

效果图

两种样式,图一有的图标是自己加的
在这里插入图片描述
在这里插入图片描述

补充遗漏的XSS过滤

1.注入脚本

[XSS](javascript:alert(123454566))


<iframe src="data:text/html;base64,PGJvZEpPg==">

2.过滤方法

passXssFun() {
  let findHaveTag = $('.vditor-ir').find(".vditor-reset").children("p");
  let findHaveDiv = $('.vditor-ir').find(".vditor-reset").children("div.vditor-ir__node");
  let childTag = findHaveTag.find("span.vditor-ir__node");
  let preCode = findHaveDiv.find("pre.vditor-ir__preview")
  childTag.each(function () {
    let xssGet = $(this).find('.vditor-ir__marker--link').html();
    let getHtml = $(this).find('.vditor-ir__link').html();
    if(xssGet == undefined) {
    } else {
      if(xssGet.indexOf("javascript:alert") >= 0 ) {
        $(this).closest('p').html(getHtml)
      }
    }
  })
  preCode.each(function () {
    let preCodeHtml = $(this).prev().find('code').html();
    let haveStatus = preCodeHtml.indexOf("&lt;iframe src=\"data:") >= 0
    if (haveStatus == false) {
    } else {
      $(this).html(preCodeHtml)
    }
  })
},

3.在input(val)中调用

setTimeout(() => {
   self.passXssFun()
 }, 500);

补充防盗链功能,此方法有视觉变化,3秒后如果接口没有返回或者进行处理的,统一都换成防盗链,同在input(val)中调用

//替换防盗链图片
 outLinkImgFun() {
   let markCont = this.contentEditor.getValue();
   let reg = /(http|https):\/\/([\w.]+\/?)\S*/gi;
   let replaceUrl = this.gb.mdImgPath("");
   let valueMatch = markCont.match(reg);
   let imgLinkPar = $(".vditor-ir").find(".vditor-reset").children("p");
   let childTag = imgLinkPar.find("span.vditor-ir__node");
   childTag.each(function () {
     let imgLinkTag = $(this).find("img").attr("src") + ")";
     // console.log(imgLinkTag)
     for (let k = 0; k < valueMatch.length; k++) {
       if (imgLinkTag == valueMatch[k]) {
         $(this).find(".vditor-ir__marker--link").html(replaceUrl);
         $(this).find("img").attr("src", replaceUrl);
       }
     }
   });
 },
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue中使用vditor(发布,编辑,详情回显、上传图片+粘贴图片回显问题,表情的处理) 的相关文章

  • Vue 组件方法未在动态 HTML 中的事件上运行

    我正在尝试动态创建一些 HTML 内容并将 Vue 组件方法绑定到元素上的事件 然而这不起作用 下面是问题的描述和测试用例的片段 重现问题的步骤 Click 点我1 观察控制台 Click 切换工具提示的弹出框 Click 点我2 观察控制
  • 每次页面重新启动时,Firebase.auth().currentUser 都会变为 null

    我正在使用 firebase 身份验证与 vue 应用程序 每次登录用户后重新启动页面时 currentUser 都会变为 null firebase auth signInWithEmailAndPassword this email t
  • 如何在 Nuxt 中点击链接下载文件?

    我遇到了一个边缘情况问题 如果用户浏览几条 Nuxt 路线 单击网站 徽标 这是一个锚标记返回主页 然后单击浏览器本机后退按钮 最后单击一个应该的链接要打开 pdf 它会重定向到我的 404 页面 如果用户在页面加载时单击 pdf 链接 它
  • Vue:单个网站可以使用多个 Vue 应用程序吗? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我有一个 Hugo 静态网站 我正在使用 Vue 使其动态化 我们正在转型 长期计划尚未确定 但在中期阶段我们正在使用 Vue 我已经在一个页面
  • 如何在Vuejs中动态管理页面标题?

    我构建一个应用程序 我有一个带有页面标题的标题 目前 我使用视图路由器来定义我的标题 path events name events component Events meta title Liste des v nements 在我的刀片
  • 如何从 vue 组件调用 App.vue 中的方法

    我有一个 vue 组件和一个 vue 元素声明 如下所示 Vue component todo item template li This is a todo li methods test function I am getting an
  • 使用 Javascript 在前端创建基本 URL(开发、API 和生产)

    无论开发和部署如何 如何制作适用于 http https localhost 端口和实际域的基本 url 我想创建一个可以在所有场景或条件下工作的基本 url 无论 http https 协议 端口 本地主机和实际域如何 无论是在开发中还是
  • Vuejs ssr 检查用户是否针对每个请求进行了身份验证

    我正在为我的应用程序使用这个 ssr 样板 https github com vuejs vue hackernews 2 0 https github com vuejs vue hackernews 2 0 我不知道如何实现逻辑来检查每
  • Vue 3 控制台中的 Proxy 是什么意思?

    我正在对数组进行洗牌 并在控制台中收到一条奇怪的消息 我的 JSON 文件如下所示 id 1 name Sushi image https images pexels com photos 1640777 pexels photo 1640
  • node.js、vue.js 和express.js 堆栈开发

    我正在尝试使用 Linux 上的 Visual Studio Code IDE 使用 vue js express js 和 node js 创建一个 Web 应用程序 根据网上的一些文档 我读到安装 vue js 后 可以创建一个vue
  • 如何修复套接字 io 中的 400 错误错误请求?

    我有一个前端应用程序 VUE JS 我有一个后端 Nest JS Vue JS 应用程序使用 vue socket io extended 库通过 websockets 从后端获取数据 当 Vue JS 应用程序启动时 我在浏览器中看到错误
  • 如何在Vue中提交表单,重定向到新路由并传递参数?

    我正在使用 Nuxt 和 Vue 我正在尝试提交表单 将用户重定向到包含提交的参数的新路由 发送 API 请求以获取一些数据 然后渲染该数据 我通过简单地将表单操作设置为新路径并手动将所有 URL 参数添加到 API 请求来实现此目的 首先
  • 如何在Vue中获取输入字段值

    我是 Vue 新手 我需要一些帮助来从输入字段获取值 在我的表格中 我有
  • 如何同时模拟Pinia和vue-i18n?

    我正在使用 Vue 3 的 Composition API 如下所示 store ts import ref Ref from vue import defineStore from pinia export const useStore
  • 在新窗口中打开 VueJS 组件

    我有一个只有一页的基本 VueJS 应用程序 它不是 SPA 而且我不使用 vue router 我想实现一个按钮 单击该按钮时会使用我的 Vue 组件之一的内容执行 window open 函数 查看来自的文档window open ht
  • 从组件传递数据

    我对 Vue 相当陌生 我正在尝试将数据从组件传递到视图 我不确定我是否在使用props正确的 我有一个对话框 当我保存时 我想将数据插入数据库 我也想重复使用addCustomer function 这就是为什么我没有将该函数放置在组件中
  • Laravel Vue 组件只能传递数字?

    在我的 UserMenu vue 中我写道 export default props nameVal data return 并在blade php中
  • 使用 Vue 的多模式组件

    我在 Vue 中实现动态模式组件时遇到问题 A common approach I follow to display a set of data fetched from the db is I dump each of the rows
  • 分页在服务器端好还是前端好? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我正在构建 Laravel Vue 应用程序 我想知道在后端使用分页还是在前端使用分页更好 我认为最好在每页发送尽可能少的数据的请求 但我想听听
  • Vue.js[vuex] 如何从突变中调度?

    我有一个要应用于 json 对象的过滤器列表 我的突变看起来像这样 const mutations setStars state payload state stars payload this dispatch filter setRev

随机推荐

  • 逻辑综合——优化电路

    对进行时序路径 工作环境 设计规则等进行约束完成之后 DC就可以进行综合 优化时序了 DC在优化过程中主要的策略将在下面进行说明 然而 当普通模式下不能进行优化的 就需要我们进行编写脚本来改进DC的优化来达到时序要求 DC进行优化的目的是权
  • CTFSHOW萌新计划 web16-17

    题目地址 https ctf show 0x01 web16 这个直接爆破就可以了 但是如果你是官网群里的成员 就会知道有个36d的梗 payload 36d 爆破的话给个脚本 import hashlib str1 abcdefghijk
  • emulator: ERROR: x86 emulation currently requires hardware acceleration! Please ensure Intel HAXM is

    原文错误提示 emulator ERROR x86 emulation currently requires hardware acceleration Please ensure Intel HAXM is properly instal
  • ege库基于前中后序动态建立二叉树、序列检错以及查找公共父节点C++

    一 需求分析 1 任意输入前序 中序序列或者中序 后序序列 生成二叉树 3 利用打印二叉树功能显示二叉树的逐步构造过程 使用自上而下的二叉树显示 4 使用EGE xege org SFML www sfml dev org download
  • 写给程序员的机器学习入门 (九) - 对象识别 RCNN 与 Fast-RCNN

    因为这几个月饭店生意恢复 加上研究 Faster RCNN 用掉了很多时间 就没有更新博客了 这篇开始会介绍对象识别的模型与实现方法 首先会介绍最简单的 RCNN 与 Fast RCNN 模型 下一篇会介绍 Faster RCNN 模型 再
  • 如何利用双休日,每月稳定增加额外1500元收入?

    针对8种不同标签的人群 良心推荐12个稳定增加收入的副业 最短一天就能有收入 月入几千的大有人在 认真看有干货 很可能会成为你的主业 最好先点赞收藏 以免后面找不到 不管你是上班族还是学生党 一个副业除了可以帮助你赚钱 更重要的是给了你平淡
  • 国家开源软件资源库

    http yp oss org cn software show cat php cat id 5 基本信息 成熟度 Dimdim 2009 05 19 1 2 3 4 5 6 7
  • C++模板详解

    目录 1 什么是c 的模板 2 模板的概念 3 函数模板 1 什么是函数模板 2 函数模板的定义格式 3 案例 4 函数模板的实例化 1 隐式实例化 2 显式实例化 5 函数模板的重载 6 函数模板与普通函数小结 7 使用函数模板要注意的问
  • 将生成的pandas DataFrame数据写入excel的指定位置

    在文件中生成了DataFrame格式数据想要写入excel的指定位置 比如第三行的第二列 网上的方法基本是使用to excel直接写入 这样写入的位置就是固定的 不能指定位置 通过openpyxl灵活设置的方式写入数据 这种方式对传统的中国
  • LoadLibrary错误182

    转载请标明是引用于 http blog csdn net chenyujing1234 欢迎大家拍砖 一 问题描述 在win7下用一个MFC程序把从XP拷过来的msgina dll加载起来 调用LoadLibrary后返回错误码为 二 解决
  • 二进制安全虚拟机Protostar靶场(2)基础知识讲解,栈溢出覆盖变量 Stack One,Stack Two

    前言 Protostar靶场的安装和一些二进制安全的基础介绍在前文已经介绍过了 这里是文章链接 https blog csdn net qq 45894840 article details 129490504 spm 1001 2014
  • 【python练习题 02】按身高和体重排队

    题目 某学校举行运动会 学生们按编号 1 2 3 n 进行标识 现需要按照身高由低到高排列 对身高相同的人 按体重由轻到重排列 对于身高体重都相同的人 维持原有的编号顺序关系 请输出排列后的学生编号 输入 两个序列 每个序列由n个正整数组成
  • Q-learning

    学习增强学习有段时间了 也接触了 learning了 但对此理解不是很透彻 知道看到头条文章对一篇 翻译文才对此有了较深的理解 特此copy 望见谅 目录 故事案例 table简介 Q learning 算法 学习动作值函数 action
  • MATLAB中生成随机数方法总结

    好久没用MATLAB了 今天在利用MATLAB进行数据处理时 突然发现自己忘记了该如何产生自己需要的随机数形式 于是又查了一通资料 现对其进行一个简单的总结 供自己和大家以后参考 1 randi 产生均匀分布的伪随机整数 产生一个1至10之
  • linux下查询缺少的依赖文件归属于哪个rpm包

    我们在redhat下使用rpm ivh安装rpm包的时候 经常会报缺少依赖条件的错误 如下 root abc Packages rpm ivh httpd 2 4 6 17 el7 x8664 rpm 错误 依赖检测失败 etc mime
  • 浏览器的跨域问题

    什么导致的浏览器的跨域问题 不同源的ajax请求会导致出现跨域的错误 必须要是ajax请求 并且是不同源的才会出现跨域问题 跨域主要是出现在浏览器阻止了响应的接收 服务器有接收到请求也有发出响应 这里是浏览器存在同源策略 什么是同源 同源是
  • 视频剪辑利器:全能的音视频处理工具

    本次推荐的四个开源项目共同展现了开放 灵活和高效的多媒体处理能力 你可以使用它们进行剪辑 格式转换 添加音频轨道或字幕 甚至通过自动生成字幕来裁剪视频 无论是优化媒体文件 节省存储空间还是创造出令人惊叹的视觉效果 这些项目都将成为你不可或缺
  • (转)知乎-区块链技术:如何赋能供应链创新

    区块链技术 如何赋能供应链创新 佳晨说 可能很多人对区块链技术有一定的了解 这份了解大多数都是来自于比特币这样的一个概念 区块链的本质到底是什么 为什么又能够为供应链创新提供新的动力 因为区块链技术可以在供应链的物流 信息流 资金流和业务流
  • Android 11.0 无源码apk设置默认启动Launcher的相关属性

    目录 1 概述 2 无源码apk设置默认启动Launcher的相关属性的核心类
  • vue中使用vditor(发布,编辑,详情回显、上传图片+粘贴图片回显问题,表情的处理)

    文章目录 1 使用方法 1 html 2 dom 发布和编辑页面 3 详情页面 1 页面 2 引入 3 dom 效果图 补充遗漏的XSS过滤 1 注入脚本 2 过滤方法 3 在input val 中调用 补充防盗链功能 此方法有视觉变化 3