Vue项目中集成TinyMCE富文本编辑器(图片批量上传等)
TinyMCE富文本在Vue中的使用
关于TinyMCE
实现效果
安装使用TinyMCE
第一步
第二步
1.官网申请Your Tiny API Key,并且配置访问域名:
2.使用css隐藏(这个就不讲了,不推荐使用)
3.全部由本地加载(推荐)
第三步(汉化包)
第四步(封装组件)
1.动态引入JS文件
2.自定义图片上传逻辑
3.上传图片文件路径变为相对路径
4.图片批量上传(非官方插件的使用)
总结
关于TinyMCE
TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有:UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等等。因为项目原因,本文章是在Vue2中封装TinyMce富文本组件。
实现效果

基本效果如图,还可以自己替换图标等,我这里额外引入了图片批量上传插件,后面会讲如何使引用且使用插件,需要使用其他插件的也是一个套路。
安装使用TinyMCE
第一步
//安装tinymce
yarn add tinymce@5.10.0 -S
//安装tinymce-vue
yarn add @tinymce/tinymce-vue@3.0.1 -S
第二步

在使用TinyMCE过程中,会出现如上图提示,是因为TinyMCE官方需要apiKey,解决办法有三种:
1.官网申请Your Tiny API Key,并且配置访问域名:
TinyMCE官网地址https://www.tiny.cloud/
注册登录后拿到apiKey

然后配置域名
具体代码中的使用在后面。
2.使用css隐藏(这个就不讲了,不推荐使用)
3.全部由本地加载(推荐)
在node_modules中找到tinymce文件夹(注意不是@tinymce文件夹)

然后将文件移入到pubilc/tinymce文件夹中

网上大部分相关教程都是在index.html中引入,如下:

但我在项目中出现,当浏览器左上角强制刷新页面时,可能会出现组件找不到tinymce.min.js文件问题,如下:

看报错,很明显引入时机有问题,那就只能在每次使用组件时动态去引入tinymce.min.js文件了,具体代码在后文。
第三步(汉化包)
在public下新建/lang/zh_CN.js 如下:

文件内容如下(粘贴复制就可):
tinymce.addI18n("zh_CN", {Redo: "\u91cd\u505a",Undo: "\u64a4\u9500",Cut: "\u526a\u5207",Copy: "\u590d\u5236",Paste: "\u7c98\u8d34","Select all": "\u5168\u9009","New document": "\u65b0\u6587\u4ef6",Ok: "\u786e\u5b9a",Cancel: "\u53d6\u6d88","Visual aids": "\u7f51\u683c\u7ebf",Bold: "\u7c97\u4f53",Italic: "\u659c\u4f53",Underline: "\u4e0b\u5212\u7ebf",Strikethrough: "\u5220\u9664\u7ebf",Superscript: "\u4e0a\u6807",Subscript: "\u4e0b\u6807","Clear formatting": "\u6e05\u9664\u683c\u5f0f","Align left": "\u5de6\u8fb9\u5bf9\u9f50","Align center": "\u4e2d\u95f4\u5bf9\u9f50","Align right": "\u53f3\u8fb9\u5bf9\u9f50",Justify: "\u4e24\u7aef\u5bf9\u9f50","Bullet list": "\u9879\u76ee\u7b26\u53f7","Numbered list": "\u7f16\u53f7\u5217\u8868","Decrease indent": "\u51cf\u5c11\u7f29\u8fdb","Increase indent": "\u589e\u52a0\u7f29\u8fdb",Close: "\u5173\u95ed",Formats: "\u683c\u5f0f","Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.":"\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u6253\u5f00\u526a\u8d34\u677f\uff0c\u8bf7\u4f7f\u7528Ctrl+X/C/V\u7b49\u5feb\u6377\u952e\u3002",Headers: "\u6807\u9898","Header 1": "\u6807\u98981","Header 2": "\u6807\u98982","Header 3": "\u6807\u98983","Header 4": "\u6807\u98984","Header 5": "\u6807\u98985","Header 6": "\u6807\u98986",Headings: "\u6807\u9898","Heading 1": "\u6807\u98981","Heading 2": "\u6807\u98982","Heading 3": "\u6807\u98983","Heading 4": "\u6807\u98984","Heading 5": "\u6807\u98985","Heading 6": "\u6807\u98986",Preformatted: "\u9884\u5148\u683c\u5f0f\u5316\u7684",Div: "Div",Pre: "Pre",Code: "\u4ee3\u7801",Paragraph: "\u6bb5\u843d",Blockquote: "\u5f15\u6587\u533a\u5757",Inline: "\u6587\u672c",Blocks: "\u57fa\u5757","Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.":"\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002",Fonts: "\u5b57\u4f53","Font Sizes": "\u5b57\u53f7",Class: "\u7c7b\u578b","Browse for an image": "\u6d4f\u89c8\u56fe\u50cf",OR: "\u6216","Drop an image here": "\u62d6\u653e\u4e00\u5f20\u56fe\u50cf\u81f3\u6b64",Upload: "\u4e0a\u4f20",Block: "\u5757",Align: "\u5bf9\u9f50",Default: "\u9ed8\u8ba4",Circle: "\u7a7a\u5fc3\u5706",Disc: "\u5b9e\u5fc3\u5706",Square: "\u65b9\u5757","Lower Alpha": "\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd","Lower Greek": "\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd","Lower Roman": "\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd","Upper Alpha": "\u5927\u5199\u82f1\u6587\u5b57\u6bcd","Upper Roman": "\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd","Anchor...": "\u951a\u70b9...",Name: "\u540d\u79f0",Id: "\u6807\u8bc6\u7b26","Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.":"\u6807\u8bc6\u7b26\u5e94\u8be5\u4ee5\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u8ddf\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002","You have unsaved changes are you sure you want to navigate away?":"\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f","Restore last draft": "\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f","Special character...": "\u7279\u6b8a\u5b57\u7b26...","Source code": "\u6e90\u4ee3\u7801","Insert/Edit code sample":"\u63d2\u5165/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b",Language: "\u8bed\u8a00","Code sample...": "\u793a\u4f8b\u4ee3\u7801...","Color Picker": "\u9009\u8272\u5668",R: "R",G: "G",B: "B","Left to right": "\u4ece\u5de6\u5230\u53f3","Right to left": "\u4ece\u53f3\u5230\u5de6",Emoticons: "\u8868\u60c5","Emoticons...": "\u8868\u60c5\u7b26\u53f7...","Metadata and Document Properties":"\u5143\u6570\u636e\u548c\u6587\u6863\u5c5e\u6027",Title: "\u6807\u9898",Keywords: "\u5173\u952e\u8bcd",Description: "\u63cf\u8ff0",Robots: "\u673a\u5668\u4eba",Author: "\u4f5c\u8005",Encoding: "\u7f16\u7801",Fullscreen: "\u5168\u5c4f",Action: "\u64cd\u4f5c",Shortcut: "\u5feb\u6377\u952e",Help: "\u5e2e\u52a9",Address: "\u5730\u5740","Focus to menubar": "\u79fb\u52a8\u7126\u70b9\u5230\u83dc\u5355\u680f","Focus to toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u5de5\u5177\u680f","Focus to element path":"\u79fb\u52a8\u7126\u70b9\u5230\u5143\u7d20\u8def\u5f84","Focus to contextual toolbar":"\u79fb\u52a8\u7126\u70b9\u5230\u4e0a\u4e0b\u6587\u83dc\u5355","Insert link (if link plugin activated)":"\u63d2\u5165\u94fe\u63a5 (\u5982\u679c\u94fe\u63a5\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Save (if save plugin activated)":"\u4fdd\u5b58(\u5982\u679c\u4fdd\u5b58\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Find (if searchreplace plugin activated)":"\u67e5\u627e(\u5982\u679c\u67e5\u627e\u66ff\u6362\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Plugins installed ({0}):": "\u5df2\u5b89\u88c5\u63d2\u4ef6 ({0}):","Premium plugins:": "\u4f18\u79c0\u63d2\u4ef6\uff1a","Learn more...": "\u4e86\u89e3\u66f4\u591a...","You are using {0}": "\u4f60\u6b63\u5728\u4f7f\u7528 {0}",Plugins: "\u63d2\u4ef6","Handy Shortcuts": "\u5feb\u6377\u952e","Horizontal line": "\u6c34\u5e73\u5206\u5272\u7ebf","Insert/edit image": "\u63d2\u5165/\u7f16\u8f91\u56fe\u7247","Alternative description": "\u66ff\u4ee3\u63cf\u8ff0",Accessibility: "\u8f85\u52a9\u529f\u80fd","Image is decorative": "\u56fe\u50cf\u662f\u88c5\u9970\u6027\u7684",Source: "\u5730\u5740",Dimensions: "\u5927\u5c0f","Constrain proportions": "\u4fdd\u6301\u7eb5\u6a2a\u6bd4",General: "\u666e\u901a",Advanced: "\u9ad8\u7ea7",Style: "\u6837\u5f0f","Vertical space": "\u5782\u76f4\u8fb9\u8ddd","Horizontal space": "\u6c34\u5e73\u8fb9\u8ddd",Border: "\u8fb9\u6846","Insert image": "\u63d2\u5165\u56fe\u7247","Image...": "\u56fe\u7247...","Image list": "\u56fe\u7247\u5217\u8868","Rotate counterclockwise": "\u9006\u65f6\u9488\u65cb\u8f6c","Rotate clockwise": "\u987a\u65f6\u9488\u65cb\u8f6c","Flip vertically": "\u5782\u76f4\u7ffb\u8f6c","Flip horizontally": "\u6c34\u5e73\u7ffb\u8f6c","Edit image": "\u7f16\u8f91\u56fe\u7247","Image options": "\u56fe\u7247\u9009\u9879","Zoom in": "\u653e\u5927","Zoom out": "\u7f29\u5c0f",Crop: "\u88c1\u526a",Resize: "\u8c03\u6574\u5927\u5c0f",Orientation: "\u65b9\u5411",Brightness: "\u4eae\u5ea6",Sharpen: "\u9510\u5316",Contrast: "\u5bf9\u6bd4\u5ea6","Color levels": "\u989c\u8272\u5c42\u6b21",Gamma: "\u4f3d\u9a6c\u503c",Invert: "\u53cd\u8f6c",Apply: "\u5e94\u7528",Back: "\u540e\u9000","Insert date/time": "\u63d2\u5165\u65e5\u671f/\u65f6\u95f4","Date/time": "\u65e5\u671f/\u65f6\u95f4","Insert/edit link": "\u63d2\u5165/\u7f16\u8f91\u94fe\u63a5","Text to display": "\u663e\u793a\u6587\u5b57",Url: "\u5730\u5740","Open link in...": "\u94fe\u63a5\u6253\u5f00\u4f4d\u7f6e...","Current window": "\u5f53\u524d\u7a97\u53e3",None: "\u65e0","New window": "\u5728\u65b0\u7a97\u53e3\u6253\u5f00","Open link": "\u6253\u5f00\u94fe\u63a5","Remove link": "\u5220\u9664\u94fe\u63a5",Anchors: "\u951a\u70b9","Link...": "\u94fe\u63a5...","Paste or type a link": "\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5","The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?":"\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7f00\u5417\uff1f","The URL you entered seems to be an external link. Do you want to add the required http:// prefix?":"\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp://:\u524d\u7f00\u5417\uff1f","The URL you entered seems to be an external link. Do you want to add the required https:// prefix?":"\u60a8\u8f93\u5165\u7684 URL \u4f3c\u4e4e\u662f\u4e00\u4e2a\u5916\u90e8\u94fe\u63a5\u3002\u60a8\u60f3\u6dfb\u52a0\u6240\u9700\u7684 https:// \u524d\u7f00\u5417\uff1f","Link list": "\u94fe\u63a5\u5217\u8868","Insert video": "\u63d2\u5165\u89c6\u9891","Insert/edit video": "\u63d2\u5165/\u7f16\u8f91\u89c6\u9891","Insert/edit media": "\u63d2\u5165/\u7f16\u8f91\u5a92\u4f53","Alternative source": "\u955c\u50cf","Alternative source URL": "\u66ff\u4ee3\u6765\u6e90\u7f51\u5740","Media poster (Image URL)": "\u5c01\u9762(\u56fe\u7247\u5730\u5740)","Paste your embed code below:":"\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:",Embed: "\u5185\u5d4c","Media...": "\u591a\u5a92\u4f53...","Nonbreaking space": "\u4e0d\u95f4\u65ad\u7a7a\u683c","Page break": "\u5206\u9875\u7b26","Paste as text": "\u7c98\u8d34\u4e3a\u6587\u672c",Preview: "\u9884\u89c8","Print...": "\u6253\u5370...",Save: "\u4fdd\u5b58",Find: "\u67e5\u627e","Replace with": "\u66ff\u6362\u4e3a",Replace: "\u66ff\u6362","Replace all": "\u5168\u90e8\u66ff\u6362",Previous: "\u4e0a\u4e00\u4e2a",Next: "\u4e0b\u4e00\u4e2a","Find and Replace": "\u67e5\u627e\u548c\u66ff\u6362","Find and replace...": "\u67e5\u627e\u5e76\u66ff\u6362...","Could not find the specified string.":"\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9.","Match case": "\u533a\u5206\u5927\u5c0f\u5199","Find whole words only": "\u5168\u5b57\u5339\u914d","Find in selection": "\u5728\u9009\u533a\u4e2d\u67e5\u627e",Spellcheck: "\u62fc\u5199\u68c0\u67e5","Spellcheck Language": "\u62fc\u5199\u68c0\u67e5\u8bed\u8a00","No misspellings found.": "\u6ca1\u6709\u53d1\u73b0\u62fc\u5199\u9519\u8bef",Ignore: "\u5ffd\u7565","Ignore all": "\u5168\u90e8\u5ffd\u7565",Finish: "\u5b8c\u6210","Add to Dictionary": "\u6dfb\u52a0\u5230\u5b57\u5178","Insert table": "\u63d2\u5165\u8868\u683c","Table properties": "\u8868\u683c\u5c5e\u6027","Delete table": "\u5220\u9664\u8868\u683c",Cell: "\u5355\u5143\u683c",Row: "\u884c",Column: "\u5217","Cell properties": "\u5355\u5143\u683c\u5c5e\u6027","Merge cells": "\u5408\u5e76\u5355\u5143\u683c","Split cell": "\u62c6\u5206\u5355\u5143\u683c","Insert row before": "\u5728\u4e0a\u65b9\u63d2\u5165","Insert row after": "\u5728\u4e0b\u65b9\u63d2\u5165","Delete row": "\u5220\u9664\u884c","Row properties": "\u884c\u5c5e\u6027","Cut row": "\u526a\u5207\u884c","Copy row": "\u590d\u5236\u884c","Paste row before": "\u7c98\u8d34\u5230\u4e0a\u65b9","Paste row after": "\u7c98\u8d34\u5230\u4e0b\u65b9","Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165","Insert column after": "\u5728\u53f3\u4fa7\u63d2\u5165","Delete column": "\u5220\u9664\u5217",Cols: "\u5217",Rows: "\u884c",Width: "\u5bbd",Height: "\u9ad8","Cell spacing": "\u5355\u5143\u683c\u5916\u95f4\u8ddd","Cell padding": "\u5355\u5143\u683c\u5185\u8fb9\u8ddd",Caption: "\u6807\u9898","Show caption": "\u663e\u793a\u6807\u9898",Left: "\u5de6\u5bf9\u9f50",Center: "\u5c45\u4e2d",Right: "\u53f3\u5bf9\u9f50","Cell type": "\u5355\u5143\u683c\u7c7b\u578b",Scope: "\u8303\u56f4",Alignment: "\u5bf9\u9f50\u65b9\u5f0f","H Align": "\u6c34\u5e73\u5bf9\u9f50","V Align": "\u5782\u76f4\u5bf9\u9f50",Top: "\u9876\u90e8\u5bf9\u9f50",Middle: "\u5782\u76f4\u5c45\u4e2d",Bottom: "\u5e95\u90e8\u5bf9\u9f50","Header cell": "\u8868\u5934\u5355\u5143\u683c","Row group": "\u884c\u7ec4","Column group": "\u5217\u7ec4","Row type": "\u884c\u7c7b\u578b",Header: "\u8868\u5934",Body: "\u8868\u4f53",Footer: "\u8868\u5c3e","Border color": "\u8fb9\u6846\u989c\u8272","Insert template...": "\u63d2\u5165\u6a21\u677f...",Templates: "\u6a21\u677f",Template: "\u6a21\u677f","Text color": "\u6587\u5b57\u989c\u8272","Background color": "\u80cc\u666f\u8272","Custom...": "\u81ea\u5b9a\u4e49...","Custom color": "\u81ea\u5b9a\u4e49\u989c\u8272","No color": "\u65e0","Remove color": "\u79fb\u9664\u989c\u8272","Table of Contents": "\u5185\u5bb9\u5217\u8868","Show blocks": "\u663e\u793a\u533a\u5757\u8fb9\u6846","Show invisible characters": "\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26","Word count": "\u5b57\u6570",Count: "\u8ba1\u6570",Document: "\u6587\u6863",Selection: "\u9009\u62e9",Words: "\u5355\u8bcd","Words: {0}": "\u5b57\u6570\uff1a{0}","{0} words": "{0} \u5b57",File: "\u6587\u4ef6",Edit: "\u7f16\u8f91",Insert: "\u63d2\u5165",View: "\u89c6\u56fe",Format: "\u683c\u5f0f",Table: "\u8868\u683c",Tools: "\u5de5\u5177","Powered by {0}": "\u7531{0}\u9a71\u52a8","Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help":"\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9","Image title": "\u56fe\u7247\u6807\u9898","Border width": "\u8fb9\u6846\u5bbd\u5ea6","Border style": "\u8fb9\u6846\u6837\u5f0f",Error: "\u9519\u8bef",Warn: "\u8b66\u544a",Valid: "\u6709\u6548","To open the popup, press Shift+Enter":"\u6309Shitf+Enter\u952e\u6253\u5f00\u5bf9\u8bdd\u6846","Rich Text Area. Press ALT-0 for help.":"\u7f16\u8f91\u533a\u3002\u6309Alt+0\u952e\u6253\u5f00\u5e2e\u52a9\u3002","System Font": "\u7cfb\u7edf\u5b57\u4f53","Failed to upload image: {0}": "\u56fe\u7247\u4e0a\u4f20\u5931\u8d25: {0}","Failed to load plugin: {0} from url {1}":"\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25: {0} \u6765\u81ea\u94fe\u63a5 {1}","Failed to load plugin url: {0}":"\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25 \u94fe\u63a5: {0}","Failed to initialize plugin: {0}":"\u63d2\u4ef6\u521d\u59cb\u5316\u5931\u8d25: {0}",example: "\u793a\u4f8b",Search: "\u641c\u7d22",All: "\u5168\u90e8",Currency: "\u8d27\u5e01",Text: "\u6587\u5b57",Quotations: "\u5f15\u7528",Mathematical: "\u6570\u5b66","Extended Latin": "\u62c9\u4e01\u8bed\u6269\u5145",Symbols: "\u7b26\u53f7",Arrows: "\u7bad\u5934","User Defined": "\u81ea\u5b9a\u4e49","dollar sign": "\u7f8e\u5143\u7b26\u53f7","currency sign": "\u8d27\u5e01\u7b26\u53f7","euro-currency sign": "\u6b27\u5143\u7b26\u53f7","colon sign": "\u5192\u53f7","cruzeiro sign": "\u514b\u9c81\u8d5b\u7f57\u5e01\u7b26\u53f7","french franc sign": "\u6cd5\u90ce\u7b26\u53f7","lira sign": "\u91cc\u62c9\u7b26\u53f7","mill sign": "\u5bc6\u5c14\u7b26\u53f7","naira sign": "\u5948\u62c9\u7b26\u53f7","peseta sign": "\u6bd4\u585e\u5854\u7b26\u53f7","rupee sign": "\u5362\u6bd4\u7b26\u53f7","won sign": "\u97e9\u5143\u7b26\u53f7","new sheqel sign": "\u65b0\u8c22\u514b\u5c14\u7b26\u53f7","dong sign": "\u8d8a\u5357\u76fe\u7b26\u53f7","kip sign": "\u8001\u631d\u57fa\u666e\u7b26\u53f7","tugrik sign": "\u56fe\u683c\u91cc\u514b\u7b26\u53f7","drachma sign": "\u5fb7\u62c9\u514b\u9a6c\u7b26\u53f7","german penny symbol": "\u5fb7\u56fd\u4fbf\u58eb\u7b26\u53f7","peso sign": "\u6bd4\u7d22\u7b26\u53f7","guarani sign": "\u74dc\u62c9\u5c3c\u7b26\u53f7","austral sign": "\u6fb3\u5143\u7b26\u53f7","hryvnia sign": "\u683c\u91cc\u592b\u5c3c\u4e9a\u7b26\u53f7","cedi sign": "\u585e\u5730\u7b26\u53f7","livre tournois sign": "\u91cc\u5f17\u5f17\u5c14\u7b26\u53f7","spesmilo sign": "spesmilo\u7b26\u53f7","tenge sign": "\u575a\u6208\u7b26\u53f7","indian rupee sign": "\u5370\u5ea6\u5362\u6bd4","turkish lira sign": "\u571f\u8033\u5176\u91cc\u62c9","nordic mark sign": "\u5317\u6b27\u9a6c\u514b","manat sign": "\u9a6c\u7eb3\u7279\u7b26\u53f7","ruble sign": "\u5362\u5e03\u7b26\u53f7","yen character": "\u65e5\u5143\u5b57\u6837","yuan character": "\u4eba\u6c11\u5e01\u5143\u5b57\u6837","yuan character, in hong kong and taiwan":"\u5143\u5b57\u6837\uff08\u6e2f\u53f0\u5730\u533a\uff09","yen/yuan character variant one":"\u5143\u5b57\u6837\uff08\u5927\u5199\uff09","Loading emoticons...": "\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7...","Could not load emoticons":"\u4e0d\u80fd\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7",People: "\u4eba\u7c7b","Animals and Nature": "\u52a8\u7269\u548c\u81ea\u7136","Food and Drink": "\u98df\u7269\u548c\u996e\u54c1",Activity: "\u6d3b\u52a8","Travel and Places": "\u65c5\u6e38\u548c\u5730\u70b9",Objects: "\u7269\u4ef6",Flags: "\u65d7\u5e1c",Characters: "\u5b57\u7b26","Characters (no spaces)": "\u5b57\u7b26(\u65e0\u7a7a\u683c)","{0} characters": "{0} \u4e2a\u5b57\u7b26","Error: Form submit field collision.":"\u9519\u8bef: \u8868\u5355\u63d0\u4ea4\u5b57\u6bb5\u51b2\u7a81\u3002","Error: No form element found.":"\u9519\u8bef: \u6ca1\u6709\u8868\u5355\u63a7\u4ef6\u3002",Update: "\u66f4\u65b0","Color swatch": "\u989c\u8272\u6837\u672c",Turquoise: "\u9752\u7eff\u8272",Green: "\u7eff\u8272",Blue: "\u84dd\u8272",Purple: "\u7d2b\u8272","Navy Blue": "\u6d77\u519b\u84dd","Dark Turquoise": "\u6df1\u84dd\u7eff\u8272","Dark Green": "\u6df1\u7eff\u8272","Medium Blue": "\u4e2d\u84dd\u8272","Medium Purple": "\u4e2d\u7d2b\u8272","Midnight Blue": "\u6df1\u84dd\u8272",Yellow: "\u9ec4\u8272",Orange: "\u6a59\u8272",Red: "\u7ea2\u8272","Light Gray": "\u6d45\u7070\u8272",Gray: "\u7070\u8272","Dark Yellow": "\u6697\u9ec4\u8272","Dark Orange": "\u6df1\u6a59\u8272","Dark Red": "\u6df1\u7ea2\u8272","Medium Gray": "\u4e2d\u7070\u8272","Dark Gray": "\u6df1\u7070\u8272","Light Green": "\u6d45\u7eff\u8272","Light Yellow": "\u6d45\u9ec4\u8272","Light Red": "\u6d45\u7ea2\u8272","Light Purple": "\u6d45\u7d2b\u8272","Light Blue": "\u6d45\u84dd\u8272","Dark Purple": "\u6df1\u7d2b\u8272","Dark Blue": "\u6df1\u84dd\u8272",Black: "\u9ed1\u8272",White: "\u767d\u8272","Switch to or from fullscreen mode": "\u5207\u6362\u5168\u5c4f\u6a21\u5f0f","Open help dialog": "\u6253\u5f00\u5e2e\u52a9\u5bf9\u8bdd\u6846",history: "\u5386\u53f2",styles: "\u6837\u5f0f",formatting: "\u683c\u5f0f\u5316",alignment: "\u5bf9\u9f50",indentation: "\u7f29\u8fdb",Font: "\u5b57\u4f53",Size: "\u5b57\u53f7","More...": "\u66f4\u591a...","Select...": "\u9009\u62e9...",Preferences: "\u9996\u9009\u9879",Yes: "\u662f",No: "\u5426","Keyboard Navigation": "\u952e\u76d8\u6307\u5f15",Version: "\u7248\u672c","Code view": "\u4ee3\u7801\u89c6\u56fe","Open popup menu for split buttons":"\u6253\u5f00\u5f39\u51fa\u5f0f\u83dc\u5355\uff0c\u7528\u4e8e\u62c6\u5206\u6309\u94ae","List Properties": "\u5217\u8868\u5c5e\u6027","List properties...": "\u6807\u9898\u5b57\u4f53\u5c5e\u6027","Start list at number": "\u4ee5\u6570\u5b57\u5f00\u59cb\u5217\u8868","Line height": "\u884c\u9ad8",comments: "\u5907\u6ce8","Format Painter": "\u683c\u5f0f\u5237","Insert/edit iframe": "\u63d2\u5165/\u7f16\u8f91\u6846\u67b6",Capitalization: "\u5927\u5199",lowercase: "\u5c0f\u5199",UPPERCASE: "\u5927\u5199","Title Case": "\u9996\u5b57\u6bcd\u5927\u5199","permanent pen": "\u8bb0\u53f7\u7b14","Permanent Pen Properties": "\u6c38\u4e45\u7b14\u5c5e\u6027","Permanent pen properties...": "\u6c38\u4e45\u7b14\u5c5e\u6027...","case change": "\u6848\u4f8b\u66f4\u6539","page embed": "\u9875\u9762\u5d4c\u5165","Advanced sort...": "\u9ad8\u7ea7\u6392\u5e8f...","Advanced Sort": "\u9ad8\u7ea7\u6392\u5e8f","Sort table by column ascending": "\u6309\u5217\u5347\u5e8f\u8868","Sort table by column descending": "\u6309\u5217\u964d\u5e8f\u8868",Sort: "\u6392\u5e8f",Order: "\u6392\u5e8f","Sort by": "\u6392\u5e8f\u65b9\u5f0f",Ascending: "\u5347\u5e8f",Descending: "\u964d\u5e8f","Column {0}": "\u5217{0}","Row {0}": "\u884c{0}","Spellcheck...": "\u62fc\u5199\u68c0\u67e5...","Misspelled word": "\u62fc\u5199\u9519\u8bef\u7684\u5355\u8bcd",Suggestions: "\u5efa\u8bae",Change: "\u66f4\u6539","Finding word suggestions": "\u67e5\u627e\u5355\u8bcd\u5efa\u8bae",Success: "\u6210\u529f",Repair: "\u4fee\u590d","Issue {0} of {1}": "\u5171\u8ba1{1}\u95ee\u9898{0}","Images must be marked as decorative or have an alternative text description":"\u56fe\u50cf\u5fc5\u987b\u6807\u8bb0\u4e3a\u88c5\u9970\u6027\u6216\u5177\u6709\u66ff\u4ee3\u6587\u672c\u63cf\u8ff0","Images must have an alternative text description. Decorative images are not allowed.":"\u56fe\u50cf\u5fc5\u987b\u5177\u6709\u66ff\u4ee3\u6587\u672c\u63cf\u8ff0\u3002\u4e0d\u5141\u8bb8\u4f7f\u7528\u88c5\u9970\u56fe\u50cf\u3002","Or provide alternative text:":"\u6216\u63d0\u4f9b\u5907\u9009\u6587\u672c\uff1a","Make image decorative:": "\u4f7f\u56fe\u50cf\u88c5\u9970\uff1a","ID attribute must be unique":"ID \u5c5e\u6027\u5fc5\u987b\u662f\u552f\u4e00\u7684","Make ID unique": "\u4f7f ID \u72ec\u4e00\u65e0\u4e8c","Keep this ID and remove all others":"\u4fdd\u7559\u6b64 ID \u5e76\u5220\u9664\u6240\u6709\u5176\u4ed6","Remove this ID": "\u5220\u9664\u6b64 ID","Remove all IDs": "\u6e05\u9664\u5168\u90e8IDs",Checklist: "\u6e05\u5355",Anchor: "\u951a\u70b9","Special character": "\u7279\u6b8a\u7b26\u53f7","Code sample": "\u4ee3\u7801\u793a\u4f8b",Color: "\u989c\u8272","Document properties": "\u6587\u6863\u5c5e\u6027","Image description": "\u56fe\u7247\u63cf\u8ff0",Image: "\u56fe\u7247","Insert link": "\u63d2\u5165\u94fe\u63a5",Target: "\u6253\u5f00\u65b9\u5f0f",Link: "\u94fe\u63a5",Poster: "\u5c01\u9762",Media: "\u5a92\u4f53",Print: "\u6253\u5370",Prev: "\u4e0a\u4e00\u4e2a","Find and replace": "\u67e5\u627e\u548c\u66ff\u6362","Whole words": "\u5168\u5b57\u5339\u914d","Insert template": "\u63d2\u5165\u6a21\u677f",
});
第四步(封装组件)
在src/components文件夹中封装Tinymce组件,文件目录如下:

plugins.js用来指定哪些插件被用在当前编辑器实例中:
// Any plugins you want to use has to be imported
// Deatil plugins list see https://www.tiny.cloud/docs/plugins/const plugins = [`advlist autolink lists link image charmap print preview anchor,searchreplace visualblocks code fullscreen,insertdatetime media table help wordcount image `
]export default plugins
toolbar.js用来配置工具栏上可用的按钮,多个控件使用空格分隔,使用“|”来创建分组:
// Here is a list of the toolbar
// Detail list see https://www.tiny.cloud/docs/general-configuration-guide/basic-setup/#toolbarconfigurationconst toolbars = ` | undo redo | cut copy | bold italic forecolor backcolor |alignleft aligncenter alignright alignjustify | formatselect | image | fullscreen preview | help `export default toolbars
index.vue文件完整内容如下:
<template><editorv-if="status === 'success'"v-model="myValue":init="init"></editor><!-- apiKey的使用方法 --><!-- <editor--><!-- v-model="myValue"--><!-- :init="init"--><!-- :api-key="apiKey"--><!-- >--><!-- </editor>--></template>
<script>
import Editor from "@tinymce/tinymce-vue"
import {uploadFile} from "@/request";
import config from "@/config";
import plugins from './plugins'
import toolbar from './toolbar'const defaultConfig = {width: 1000,height: 600,menubar: true,language: 'zh_CN'
}
export default {components: {Editor},props: {value: {type: String,default: "",},config: {type: Object,default: () => {return {width: 1000,height: 600,menubar: true,language: 'zh_CN'}}}},data() {return {myValue: this.value,apiKey: "在TinyMCE中申请的apiKey",//使用本地加载js的话可以不用apiKey'init: {plugins,toolbar,convert_urls: false,// 上传图片文件路径变为相对路径的解决方法removed_menuitems: 'media',width: Object.assign(defaultConfig, this.config).width,height: Object.assign(defaultConfig, this.config).height,menubar: Object.assign(defaultConfig, this.config).menubar,language: Object.assign(defaultConfig, this.config).language,language_url: "/tinymce/langs/zh_CN.js",// 汉化包resize: 'both',// 自定义图片上传images_upload_handler: async (blobInfo, success, failure) => {try {let formData = new FormData();formData.append("file", blobInfo.blob())formData.append("type", 1);let res = await uploadFile(formData);let url = `${config.downloadUrl}${res.url}`success(url)} catch (err) {console.log(err)}},},// tinymce组件scripttinyScript: null,status: 'pending'}},watch: {value(newValue) {this.myValue = newValue;},myValue(newValue) {this.$emit("input", newValue);},},created() {this.initTinyMceScript().then(() => {tinymce.init({})this.status = 'success'})},methods: {initTinyMceScript() {return new Promise(resolve => {if (this.tinyScript) {return resolve(null)}this.tinyScript = document.createElement("script");this.tinyScript.type = "text/javascript";this.tinyScript.src = "/tinymce/tinymce.min.js";document.body.appendChild(this.tinyScript);this.tinyScript.onload = () => {resolve(null)}})},desTinyMceScript() {if (this.tinyScript) {document.body.removeChild(this.tinyScript)this.tinyScript = null}}},beforeDestroy() {this.desTinyMceScript()}
}
</script>
封装的组件代码都在上面,然后简单讲下上面代码中踩过的坑及注意点:
1.动态引入JS文件
前面说过在项目中可能存在tinymce.min.js文件引入时机问题导致的报错,所以我们需要在组件内部动态引用js,代码如下,封装创建和销毁方法,在页面创建script标签并给属性赋值,然后监听加载完成,当加载完成后再去执行后续操作。
initTinyMceScript() {return new Promise(resolve => {if (this.tinyScript) {return resolve(null)}this.tinyScript = document.createElement("script");this.tinyScript.type = "text/javascript";this.tinyScript.src = "/tinymce/tinymce.min.js";document.body.appendChild(this.tinyScript);this.tinyScript.onload = () => {resolve(null)}})},desTinyMceScript() {if (this.tinyScript) {document.body.removeChild(this.tinyScript)this.tinyScript = null}}
要记得销毁噢:
beforeDestroy() {this.desTinyMceScript()}
2.自定义图片上传逻辑
有关图片上传的参数:

使用 images_upload_handler 可自定义上传处理逻辑。使用该配置,则无需使用其他上传配置选项,具体使用如下:
// 自定义图片上传images_upload_handler: async (blobInfo, success, failure) => {try {let formData = new FormData();formData.append("file", blobInfo.blob())formData.append("type", 1);let res = await uploadFile(formData);let url = `${config.downloadUrl}${res.url}`success(url)} catch (err) {console.log(err)}},
其中图片上传uploadFile()方法如下,这里就使用自己项目中封装的图片上传方法就OK:
/*** 上传文件* @param formData formData对象*/
const uploadFile = (formData: FormData) => request({url: cusConfig.uploadUrl,method: "POST",headers: {'Content-Type': 'multipart/form-data'},data: formData
})
如此就实现了图片的自定义上传。
3.上传图片文件路径变为相对路径
使用TinyMCE上传图片文件,接口返回相对根目录的地址,但是在TinyMCE编辑器源文件里路径变成了../../路径。

这很明显不是我们想要的,这样的路径后面是拿不到图片的,这里就需要配置convert_urls:false解决问题:
convert_urls: false,// 上传图片文件路径变为相对路径的解决方法
4.图片批量上传(非官方插件的使用)
首先去大佬的Tiny中文文档下载插件中文文档地址

将解压得到的文件夹,放到pubilc/tinymce目录下的plugins文件夹内:

并且创建index.js文件,内容如下:
// Exports the "axupimgs" plugin for usage with module loaders
// Usage:
// CommonJS:
// require('tinymce/plugins/axupimgs')
// ES2015:
// import 'tinymce/plugins/axupimgs'
require('./plugin.js');
接下来就去 toolbar.js和plugins.js中添加axupimgs:

此插件依赖image插件,不能单独使用,我们前面已经配置了图片的自定义上传,这里就不需要再做配置,功能如下:

总结
TinyMCE确实是一款易用、且功能强大的所见即所得的富文本编辑器,并且可扩展性非常强,如果文中出现有瑕疵的地方各位通过评论或者私信联系我,我们一起进步,有兴趣的伙伴可以关注订阅一下:点击查看更多实用技巧及技术

相关文章:
Vue项目中集成TinyMCE富文本编辑器(图片批量上传等)
TinyMCE富文本在Vue中的使用 关于TinyMCE 实现效果 安装使用TinyMCE 第一步 第二步 1.官网申请Your Tiny API Key,并且配置访问域名: 2.使用css隐藏(这个就不讲了,不推荐使用) 3.全部由本地加载(推荐) 第三步(汉化包) 第四步(封装组…...
前端数据可视化之【title、legend、tooltip、toolbox 】配置项
目录 🌟Echarts配置项🌟Echarts配置项之 title组件🌟Echarts配置项之 legend组件🌟Echarts配置项之 tooltip组件🌟Echarts配置项之 toolbox组件🌟写在最后 🌟Echarts配置项 ECharts开源来自百度…...
microcom串口调试工具使用
microcom串口助手使用介绍 microcom是一个在终端中使用的串口助手,类似平常使用SSCOM一样的东西,不过是在终端中使用而已。 使用的是busybox构建的文件系统 microcom源码路径:busybox/miscutils/microcom.c microcom 参数: [r…...
深入了解Golang:基本语法与核心特性解析
1. 引言 Golang(Go)是谷歌开发的一门开源编程语言,于2007年首次公开亮相,随后在2012年正式发布。Golang以其简洁、高效和可靠的设计而备受开发者青睐。作为一门编译型语言,Golang具有静态类型和垃圾回收功能ÿ…...
短视频矩阵系统源码---php搭建
一、智能剪辑、矩阵分发、无人直播、爆款文案于一体独立应用开发 抖去推----主要针对本地生活的----移动端(小程序软件系统,目前是全国源头独立开发),开发功能大拆解分享,功能大拆解: (1)数据概览&#x…...
mysql 查询表字段名,注释 , 以及sql拼接查询出的内容
#sql查询字段名,注释操作拼接 #查询字段名和注释 select COLUMN_NAME,COLUMN_COMMENT from information_schema.COLUMNS where table_name 表名 and table_schema 库名 order by ordinal_position #查询整个内容 select * from information_schema.COLUMNS wh…...
【JavaEE】_Servlet API
目录 1. HttpServlet 1.1 init方法 1.2 destroy方法 1.3 service方法 1.4 Servlet的生命周期 1.5 代码示例 1.5.1 使用postman构造请求 1.5.2 使用ajax构造请求 2. HttpServletRequest 2.1 核心方法 2.2 代码示例1:打印请求信息 3. 前端给后端传参 3.1…...
macOS下matplotlib如何显示中文字体?
一般要显示中文会使用: plt.rcParams[font.sans-serif][SimHei] #用来正常显示中文标签 plt.rcParams[axes.unicode_minus]False #用来正常显示负号不过在macOS下通常会显示方块字: 解决方案: 把上面两句注释掉,更换为…...
7-Zip怎么设置字典大小 单词大小 固实数据大小,把大文件9.35G压缩成小1.56G
环境: Win10 专业版 7-Zip v23.01 问题描述: 7-Zip怎么设置字典大小 单词大小 固实数据大小,把大文件9.28G压缩成小1.56G 解决方案: 要在7-Zip中设置字典大小、单词大小和固实数据大小,可以按照以下步骤进行操作: 打开7-Zip文件管理器,并导航到你要压缩的文件所在的…...
使用CPR库和Python编写程序
以下是一个使用CPR库和Python编写的爬虫程序,用于爬取。此程序使用了proxy的代码。 import requests from cpr import CPR def get_proxy():url "https://www.duoip.cn/get_proxy"headers {"User-Agent": "Mozilla/5.0 (Windows NT …...
axios 请求的缓存封装
前言 咱们的网站或者程序,每一个页面和操作都需要请求后端接口来获取响应和渲染页面,抛开post请求方式的接口不说,部分get请求得到的数据,短时间内不会更新,或者短时间得到的响应数据不会变化,这个时候就可…...
Oracle性能调优实践中的几点心得
很多的时侯,做OracleDBA的我们,当应用管理员向我们通告现在应用很慢、数据库很慢的时侯,我们到数据库时做几个示例的Select也发现同样的问题时,有些时侯我们会无从下手,因为我们认为数据库的各种命种率都是满足Oracle文…...
勒索病毒最新变种.halo勒索病毒来袭,如何恢复受感染的数据?
引言: 在当今数字化时代,勒索病毒的威胁不断升级,其中.halo勒索病毒引起了广泛关注。本文91数据恢复将深入研究.halo勒索病毒的特点,探讨如何有效地恢复被其加密的数据文件,并分享预防这一威胁的关键措施。 .halo勒索…...
大厂秋招真题【前缀和】美团20230826秋招T5-平均数为k的最长连续子数组
文章目录 【前缀和】美团20230826秋招T5-平均数为k的最长连续子数组题目描述与示例题目描述输入描述输出描述示例输入输出说明 解题思路代码PythonJavaC时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 【前缀和】美团20230826秋招T5-平均数为k的最长连续子数组 题目描…...
bazel远程构建(Remote Execution) --- linux安装Redis
采用源码安装方式 下载地址:Download | Redis,下载最新稳定版本。 step1: 下载最新稳定版本 wget https://download.redis.io/redis-stable.tar.gz step2: 解压安装 tar -xzvf redis-stable.tar.gz cd redis-stable make 执行完 make 命令后&#…...
Maven在开发中的使用及理解
在JAVA项目中,我们通常需要对项目的构建和依赖进行管理,这个时候我们就需要MAVEN来对项目进行支持。 一.MAVEN构建 在整个MAVEN构建的过程中包含以下环节,也对应IDEA中MAVEN的对应功能。 清理Maven Clean 清理,则代表删除上一…...
2023/10/30-LED灯驱动开发
k1.c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h> #include "head.h" char kbuf[128] {}; unsigned int major; //定义三个指针指向映射后的虚拟内…...
华为OD 报文解压缩(100分)【java】B卷
华为OD统一考试A卷+B卷 新题库说明 你收到的链接上面会标注A卷还是B卷。目前大部分收到的都是B卷。 B卷对应20022部分考题以及新出的题目,A卷对应的是新出的题目。 我将持续更新最新题目 获取更多免费题目可前往夸克网盘下载,请点击以下链接进入: 我用夸克网盘分享了「华为O…...
二、vue基础语法
一、模板语法 1、文本渲染 使用双花括号语法插入文本 <template><div><h3>msg: {{ message }}</h3></div> </template><script> export default {data() {return {message: "输出信息"}} } </script><style s…...
Java —— 程序逻辑控制
目录 1. 顺序结构 2. 分支结构 2.1 if 语句 2.1.1 语法格式1 2.1.2 语法格式2 2.1.3 语法格式3 2.2 switch 语句 3. 循环结构 3.1 while循环 3.2 break与continue 3.3 for循环 4. 输入输出 4.1 输出到控制台 格式化字符串 4.2 从键盘输入 5. 练习 和C语言类似地, Java的程序逻辑…...
最危险的内耗:试图靠打鸡血冲出人生低谷
前几天,在双井的一家精酿酒馆里,见到了小半年没露面的老赵。老赵今年刚过四十,原本在一家教培机构做中层,前阵子行业一震荡,他所在的整个部门直接被裁撤了。原本以为他这次出来喝酒会是一顿大倒苦水,结果一…...
Java 的基础语法
1. Java 的基础语法与数据类型基础语法:大小写敏感:Java 是区分大小写的语言,System和system代表不同的含义。类名规范:所有类名首字母必须大写,采用大驼峰命名法,例如HelloWorld。主方法入口:p…...
保姆级教程:在Ubuntu 22.04上从源码编译OpenWrt 23.05(附8个常见报错解决方案)
Ubuntu 22.04源码编译OpenWrt 23.05全流程指南与深度排错手册 在开源路由系统的世界里,OpenWrt以其高度定制化和强大的扩展能力成为技术爱好者的首选。本文将带你完整走过在Ubuntu 22.04 LTS环境下从源码编译OpenWrt 23.05的全过程,不仅提供标准操作流程…...
Ryujinx模拟器完全指南:轻松在PC上畅玩Switch游戏
Ryujinx模拟器完全指南:轻松在PC上畅玩Switch游戏 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx Ryujinx是一款用C#编写的开源Nintendo Switch模拟器,致力于为…...
深度学习权重约束技术:原理与实践指南
1. 深度学习中的权重约束:从理论到实践在训练深度神经网络时,我们常常面临一个关键挑战:如何在保持模型强大表达能力的同时,防止它过度记忆训练数据中的噪声和无关细节。传统方法如权重衰减(weight decay)通…...
跨平台音频下载工具终极指南:快速掌握喜马拉雅VIP内容本地化管理
跨平台音频下载工具终极指南:快速掌握喜马拉雅VIP内容本地化管理 【免费下载链接】xmly-downloader-qt5 喜马拉雅FM专辑下载器. 支持VIP与付费专辑. 使用GoQt5编写(Not Qt Binding). 项目地址: https://gitcode.com/gh_mirrors/xm/xmly-downloader-qt5 你是否…...
如何用LunaTranslator打破游戏语言壁垒:3种实时翻译方法全解析
如何用LunaTranslator打破游戏语言壁垒:3种实时翻译方法全解析 【免费下载链接】LunaTranslator 视觉小说翻译器 / Visual Novel Translator 项目地址: https://gitcode.com/GitHub_Trending/lu/LunaTranslator 还在为看不懂日文游戏剧情而烦恼吗?…...
C程序员必须立即升级的4类函数签名——2026规范已废止`gets`/`strcpy`等12个API(附自动化检测脚本)
更多请点击: https://intelliparadigm.com 第一章:现代 C 语言内存安全编码规范 2026 概述 C 语言在嵌入式系统、操作系统内核及高性能基础设施中仍占据不可替代地位,但其原始内存模型长期带来缓冲区溢出、悬垂指针、未初始化内存访问等高危…...
Element UI项目里藏了个老版本lodash?手把手教你排查和修复这个原型污染漏洞
Element UI项目中隐藏的lodash漏洞:从定位到修复的完整指南 引言 最近一次例行安全扫描后,我的团队收到了一个令人不安的警报:我们的Vue项目存在lodash原型污染漏洞。奇怪的是,项目package.json中根本没有直接声明lodash依赖。经过…...
Bebas Neue:为什么这款免费开源字体成为设计师的终极标题解决方案
Bebas Neue:为什么这款免费开源字体成为设计师的终极标题解决方案 【免费下载链接】Bebas-Neue Bebas Neue font 项目地址: https://gitcode.com/gh_mirrors/be/Bebas-Neue 在当今数字设计领域,寻找一款既专业又完全免费的标题字体往往是设计师面…...
