用ds生成markdown编辑器

• 21 分钟阅读 • web · deepseek

写作一直用的是gridea,自带有markdown编辑器,本文生成一个轻量级的编辑器。

程序主代码

提问:生成一个markdown编辑器,左右分屏,左边源代码,右边预览

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Markdown 编辑器</title>
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <style>
        body {
            margin: 0;
            padding: 0;
            font-family: Arial, sans-serif;
            display: flex;
            height: 100vh;
        }
        
        .editor-container {
            display: flex;
            width: 100%;
            height: 100%;
        }
        
        .editor-pane {
            flex: 1;
            padding: 10px;
            box-sizing: border-box;
            overflow: auto;
        }
        
        #editor {
            width: 100%;
            height: 100%;
            border: 1px solid #ddd;
            padding: 10px;
            font-family: monospace;
            resize: none;
            outline: none;
        }
        
        #preview {
            width: 100%;
            height: 100%;
            border: 1px solid #ddd;
            padding: 10px;
            overflow: auto;
        }
        
        .pane-header {
            font-weight: bold;
            margin-bottom: 10px;
            padding-bottom: 5px;
            border-bottom: 1px solid #eee;
        }
        
        .resize-handle {
            width: 10px;
            background: #f0f0f0;
            cursor: col-resize;
        }
    </style>
</head>
<body>
    <div class="editor-container">
        <div class="editor-pane">
            <div class="pane-header">Markdown 源代码</div>
            <textarea id="editor"># Markdown 编辑器

这是一个**左右分屏**的 Markdown 编辑器。

- 左边编辑 Markdown 源代码
- 右边实时预览渲染结果

## 功能特点

1. 实时预览
2. 语法高亮
3. 响应式布局

```javascript
// 示例代码
function hello() {
    console.log("Hello, Markdown!");
}
```</textarea>
        </div>
        
        <div class="resize-handle" id="resize-handle"></div>
        
        <div class="editor-pane">
            <div class="pane-header">预览</div>
            <div id="preview"></div>
        </div>
    </div>

    <script>
        const editor = document.getElementById('editor');
        const preview = document.getElementById('preview');
        const resizeHandle = document.getElementById('resize-handle');
        
        // 初始渲染
        updatePreview();
        
        // 实时更新预览
        editor.addEventListener('input', updatePreview);
        
        // 调整分屏大小
        let isResizing = false;
        resizeHandle.addEventListener('mousedown', (e) => {
            isResizing = true;
            document.body.style.cursor = 'col-resize';
        });
        
        document.addEventListener('mousemove', (e) => {
            if (!isResizing) return;
            
            const container = document.querySelector('.editor-container');
            const containerRect = container.getBoundingClientRect();
            const leftWidth = e.clientX - containerRect.left;
            const rightWidth = containerRect.width - leftWidth - 10; // 10px for handle
            
            container.children[0].style.flex = `0 0 ${leftWidth}px`;
            container.children[2].style.flex = `0 0 ${rightWidth}px`;
        });
        
        document.addEventListener('mouseup', () => {
            isResizing = false;
            document.body.style.cursor = '';
        });
        
        function updatePreview() {
            preview.innerHTML = marked.parse(editor.value);
        }
    </script>
</body>
</html>

功能说明:
左右分屏布局:

扩展

功能不够,再提示:编辑器改进: 增加工具栏,本地保存,语法高亮,可插入图片,图片以当前时间随机命名。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>高级 Markdown 编辑器</title>
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        :root {
            --primary-color: #4285f4;
            --border-color: #dadce0;
        }
        
        body {
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            height: 100vh;
            display: grid;
            grid-template-rows: auto 1fr auto;
        }
        
        .toolbar {
            padding: 8px;
            border-bottom: 1px solid var(--border-color);
            display: flex;
            gap: 5px;
            flex-wrap: wrap;
        }
        
        .toolbar button {
            background: white;
            border: 1px solid var(--border-color);
            border-radius: 4px;
            padding: 6px 10px;
            cursor: pointer;
        }
        
        .editor-container {
            display: grid;
            grid-template-columns: 1fr 10px 1fr;
            height: 100%;
        }
        
        .editor-pane {
            overflow: auto;
            display: flex;
            flex-direction: column;
        }
        
        #editor {
            width: 100%;
            height: 100%;
            border: none;
            padding: 15px;
            font-family: 'Consolas', monospace;
            resize: none;
            outline: none;
            font-size: 14px;
            line-height: 1.5;
        }
        
        #preview {
            padding: 15px;
            overflow: auto;
        }
        
        .resize-handle {
            background: #f1f3f4;
            cursor: col-resize;
        }
        
        .status-bar {
            padding: 5px 10px;
            border-top: 1px solid var(--border-color);
            font-size: 12px;
        }
        
        #file-input, #image-upload {
            display: none;
        }
    </style>
</head>
<body>
    <div class="toolbar">
        <button onclick="insertText('**', '**')"><i class="fas fa-bold"></i></button>
        <button onclick="insertText('*', '*')"><i class="fas fa-italic"></i></button>
        <button onclick="insertText('# ', '')"><i class="fas fa-heading"></i></button>
        <button onclick="insertText('[', '](url)')"><i class="fas fa-link"></i></button>
        <button onclick="document.getElementById('image-upload').click()"><i class="fas fa-image"></i></button>
        <button onclick="insertText('```\n', '\n```')"><i class="fas fa-code"></i></button>
        <div style="flex-grow: 1;"></div>
        <button onclick="saveAsMd()"><i class="fas fa-save"></i> 保存为.md</button>
        <button onclick="document.getElementById('file-input').click()"><i class="fas fa-folder-open"></i> 打开</button>
    </div>
    
    <div class="editor-container">
        <div class="editor-pane">
            <textarea id="editor"># Markdown 编辑器

这是一个左右分屏的Markdown编辑器。

- 左边编辑源代码
- 右边实时预览

**功能特点**:
1. 可保存为.md文件
2. 图片上传功能
3. 语法高亮</textarea>
        </div>
        
        <div class="resize-handle" id="resize-handle"></div>
        
        <div class="editor-pane">
            <div id="preview"></div>
        </div>
    </div>
    
    <div class="status-bar">
        <span id="status">就绪</span>
    </div>
    
    <input type="file" id="file-input" accept=".md,.markdown,.txt">
    <input type="file" id="image-upload" accept="image/*">
    
    <script>
        const editor = document.getElementById('editor');
        const preview = document.getElementById('preview');
        const resizeHandle = document.getElementById('resize-handle');
        const fileInput = document.getElementById('file-input');
        const imageUpload = document.getElementById('image-upload');
        const statusEl = document.getElementById('status');
        
        // 配置marked
        marked.setOptions({
            breaks: true,
            gfm: true,
            highlight: (code, lang) => {
                if (Prism.languages[lang]) {
                    return Prism.highlight(code, Prism.languages[lang], lang);
                }
                return code;
            }
        });
        
        // 初始渲染
        updatePreview();
        
        // 实时预览
        editor.addEventListener('input', updatePreview);
        
        // 分屏调整
        let isResizing = false;
        resizeHandle.addEventListener('mousedown', () => {
            isResizing = true;
            document.body.style.cursor = 'col-resize';
        });
        
        document.addEventListener('mousemove', (e) => {
            if (!isResizing) return;
            
            const container = document.querySelector('.editor-container');
            const containerRect = container.getBoundingClientRect();
            const leftWidth = e.clientX - containerRect.left;
            
            container.style.gridTemplateColumns = `${leftWidth}px 10px 1fr`;
        });
        
        document.addEventListener('mouseup', () => {
            isResizing = false;
            document.body.style.cursor = '';
        });
        
        // 打开文件
        fileInput.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (!file) return;
            
            const reader = new FileReader();
            reader.onload = (event) => {
                editor.value = event.target.result;
                updatePreview();
                showStatus(`已加载: ${file.name}`);
            };
            reader.readAsText(file);
        });
        
        // 图片上传处理
        let imageUploadPath = ''; // 在实际应用中替换为您的图片上传API
        
        imageUpload.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (!file) return;
            
            // 实际应用中应该上传到服务器并返回URL
            // 这里模拟上传后返回固定URL
            const fileName = `image-${Date.now()}.${file.name.split('.').pop()}`;
            const imageUrl = imageUploadPath ? `${imageUploadPath}/${fileName}` : fileName;
            
            insertText(`![${file.name}](${imageUrl})`);
            showStatus(`已插入图片: ${fileName}`);
            imageUpload.value = '';
        });
        
        // 保存为.md文件
        function saveAsMd() {
            const content = editor.value;
            const blob = new Blob([content], { type: 'text/markdown' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `markdown-${new Date().toISOString().slice(0,10)}.md`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
            showStatus('已保存为.md文件');
        }
        
        // 更新预览
        function updatePreview() {
            preview.innerHTML = marked.parse(editor.value);
        }
        
        // 插入文本
        function insertText(prefix, suffix = '') {
            const start = editor.selectionStart;
            const end = editor.selectionEnd;
            const selected = editor.value.substring(start, end);
            const before = editor.value.substring(0, start);
            const after = editor.value.substring(end);
            
            editor.value = before + prefix + selected + suffix + after;
            editor.focus();
            editor.selectionStart = start + prefix.length;
            editor.selectionEnd = end + prefix.length;
            updatePreview();
        }
        
        // 显示状态
        function showStatus(message) {
            statusEl.textContent = message;
            setTimeout(() => statusEl.textContent = '就绪', 3000);
        }
    </script>
</body>
</html>

如图:

经过与ds反复交流,生成了一个index.html版的markdown编辑器。

预览:markdown编辑器

文章标签: web, deepseek

上一篇 : 将 HTML/CSS/JS 编辑器打包为 Windows 应用程序
下一篇 : 用ds生成小工具image_converter
留言
阅读进度 0%