Markdown编辑器是一种用于编写和格式化文本的工具,支持Markdown语法,能够轻松地将简单的文本转化为格式化的内容。以下是Markdown编辑器的一些关键特点和功能:
-
简单易用:Markdown使用简单的符号和语法,使得用户可以快速上手。例如,使用
#
表示标题,*
或-
表示列表。 -
实时预览:许多Markdown编辑器提供实时预览功能,允许用户在编写时看到格式化后的效果。
-
支持多种格式:Markdown支持标题、段落、链接、图片、表格、代码块等多种格式,适合各种文档需求。
-
跨平台:大多数Markdown编辑器可以在网页、桌面和移动设备上使用,方便用户随时随地编辑内容。
-
导出功能:许多Markdown编辑器支持将文档导出为HTML、PDF等格式,方便分享和发布。
-
扩展性:一些Markdown编辑器允许用户自定义或扩展功能,比如添加自定义样式或插件。
常见的Markdown编辑器包括Typora、Obsidian、MarkdownPad、以及许多在线编辑器如StackEdit和Dillinger。
这篇文章我们介绍如何在项目中使用markdown-editor,文章使用的是django-web框架以及腾讯云cos服务。主要是如何在markdown-editor中上传本地图片。
下载插件
Editor.md - 开源在线 Markdown 编辑器 (pandao.github.io)
保存到static/plugin/
页面上显示markdown编辑器
定义一个div容器方便查找
<div id='editor'>...</div>
引入css样式和js
<link rel="stylesheet" href="{% static 'plugin/editor-md/css/editormd.min.css' %}">
<script src="{% static 'plugin/editor-md/editormd.min.js' %}"></script>
初始化markdown编辑器
<script>
// 页面框架加载完成之后自动执行函数
$(function () {initEditorMd();
});
function initEditorMd(){editormd('editor', { // 第一个参数是div容器的id-->editor 第二个是配置{...}//配置placeholder:"请输入内容",height:500,//指定组件地址path:"{% static 'plugin/editor-md/lib/' %}"})
}
</script>
显示markdown格式的文本
定义div容器方便查找
<div id="previewMarkdown"><textarea>文本内容</textarea>
</div>
引入js css
<link rel="stylesheet" href="{% static 'plugin/editor-md/css/editormd.preview.min.css' %}">
<script src="{% static 'plugin/editor-md/editormd.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/flowchart.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/jquery.flowchart.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/marked.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/prettify.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/raphael.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/sequence-diagram.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/underscore.min.js' %}"></script>
初始化
function previewMarkdown(){editormd.markdownToHTML('previewMarkdown', {htmlDecode:'style, script, iframe'});}// previewMarkdown 是div容器id
markdown编辑器里上传本地图片
1、添加图片时添加本地上传的选项
2、将选中的图片上传到对象存储服务
3、将对象存储返回的图片地址添加到markdown编辑器就可以显示图片了
python">from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from qcloud_cos import CosConfig, CosS3Client
import logging, sys
import uuid@csrf_exempt
def image_upload(request):if request.method == 'GET':return render(request, 'image_upload.html')result = {'success': 0, 'message': None, 'url': None}image_object = request.FILES.get('editormd-image-file')if not image_object:result['message'] = "文件不存在"return JsonResponse(result)# 腾讯云 COS 配置SecretId = ""SecretKey = ""REGION = '' # 已创建桶归属的 region BUCKET = '' # 桶名config = CosConfig(Region=REGION, SecretId=SecretId, SecretKey=SecretKey)client = CosS3Client(config)ext = image_object.name.rsplit('.')[-1]key = f"{uid('img_')}.{ext}"try:response = client.upload_file_from_buffer(Bucket=BUCKET,Body=image_object,Key=key,)image_url = f"https://zxm-1318306082.cos.{REGION}.myqcloud.com/{key}"result.update(success=1, url=image_url)except Exception as e:logging.error(e)result['message'] = str(e)return JsonResponse(result)
自定义中间件
python">class AllowIframeMiddleware:def __init__(self, get_response):self.get_response = get_responsedef __call__(self, request):response = self.get_response(request)response["X-Frame-Options"] = "ALLOWALL"return response
设置文件里添加中间件
python">MIDDLEWARE += ['apps.home.middleware.allowIframe.AllowIframeMiddleware',
]
AllowIframeMiddleware
中间件的作用是修改每个 HTTP 响应的头部信息,具体来说,它为所有响应添加了 X-Frame-Options: ALLOWALL
这个 HTTP 头.
具体功能
- 允许嵌套:通过设置
X-Frame-Options
为ALLOWALL
,浏览器将允许将该页面嵌入到其他页面的<iframe>
中,而不受限制。默认情况下,Django 会将此头部设置为DENY
,防止其他网站通过<iframe>
嵌入你的页面,这样可以提高安全性,防止点击劫持(clickjacking)攻击。 - 应用范围:这个中间件会影响所有通过 Django 处理的请求响应,因此每个响应都会带有这个头部,不论是静态文件、API 响应还是 HTML 页面。
使用场景
- 需要嵌入到其他页面:如果你的应用需要在其他网站或应用中通过 iframe 加载页面(例如,在线文档编辑器、第三方应用集成等),可以使用这个中间件。
注意事项
- 安全性考虑:虽然允许 iframe 嵌入可以满足某些业务需求,但同时也会增加安全风险。因此,在生产环境中使用时,请确保理解潜在的风险,必要时限制允许嵌入的域。
- 根据需求调整:如果只希望允许特定网站嵌入,可以考虑使用
ALLOW-FROM uri
来替代ALLOWALL
,但要注意这个选项在某些浏览器中的支持程度有限。
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"><link rel="stylesheet" href="{% static 'plugin/editor-md/css/editormd.min.css' %}"><link rel="stylesheet" href="{% static 'plugin/editor-md/css/editormd.preview.min.css' %}"><link rel="stylesheet" href="{% static 'plugin/editor-md/css/editormd.preview.min.css' %}"><script src="{% static 'plugin/editor-md/editormd.min.js' %}"><style>.error-msg {color: red;position: absolute;font-size: 13px;}.editormd-fullscreen {z-index: 1001;}</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.3.0/raphael.min.js"></script><script src="{% static 'plugin/editor-md/editormd.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/flowchart.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/jquery.flowchart.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/marked.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/prettify.min.js' %}"></script><script src="{% static 'plugin/editor-md/lib/underscore.min.js' %}"></script>
<script src="{% static 'plugin/editor-md/lib/sequence-diagram.min.js' %}"></script><script>$(function () {initEditorMd();previewMarkdown();setupImageUpload();});function initEditorMd() {editormd('editor', {placeholder: "请输入内容",height: 500,path: "{% static 'plugin/editor-md/lib/' %}",imageUpload: true,imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp"],imageUploadUrl: "{% url 'image_upload' %}",});}function previewMarkdown() {editormd.markdownToHTML('previewMarkdown', {htmlDecode: 'style,script,iframe',});}function setupImageUpload() {$('#uploadForm').submit(function (e) {e.preventDefault();var formData = new FormData(this);$.ajax({url: "{% url 'image_upload' %}",type: 'POST',data: formData,contentType: false,processData: false,success: function (response) {if (response.success) {alert('图片上传成功: ' + response.url);} else {alert('上传失败: ' + response.message);}},error: function (error) {console.error('上传出错:', error);},});});}</script>
<div id="editor"></div>