微信公众号文章编辑器

一个用于编辑和格式化内容以便发布到微信公众号的工具,支持Markdown语法和实时预览

// ==UserScript==
// @name         微信公众号文章编辑器
// @namespace    http://tampermonkey.net/
// @version      2.0.0
// @description  一个用于编辑和格式化内容以便发布到微信公众号的工具,支持Markdown语法和实时预览
// @author       shenfangda
// @match        *://*/*
// @grant        GM_setClipboard
// @grant        GM_addStyle
// @license      MIT
// @icon         data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzAwQjM3QiIgd2lkdGg9IjQ4cHgiIGhlaWdodD0iNDhweCI+PHBhdGggZD0iTTE0LjkgMTAuNXYyaC01di0yaC0ydjdoMTB2LTdoLTN6bTcuMSA3LjVIMlY2aDIwdjEyem0tMTgtMWgxNlY4SDRWMTZ6Ii8+PC9zdmc+
// ==/UserScript==

(function() {
    'use strict';

    // 主要功能类
    class WeChatArticleEditor {
        constructor() {
            this.init();
        }

        init() {
            console.log('微信公众号文章编辑器已启动');
            this.createUI();
            this.bindEvents();
        }

        // 创建用户界面
        createUI() {
            GM_addStyle(`
                #wechat-editor-panel {
                    position: fixed;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    width: 80%;
                    height: 80%;
                    background: #fff;
                    border-radius: 8px;
                    box-shadow: 0 4px 20px rgba(0,0,0,0.15);
                    z-index: 100000;
                    display: none;
                    flex-direction: column;
                    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
                }

                #wechat-editor-panel-header {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    padding: 15px 20px;
                    border-bottom: 1px solid #eee;
                    background: #f8f9fa;
                    border-radius: 8px 8px 0 0;
                }

                #wechat-editor-panel-title {
                    font-size: 18px;
                    font-weight: 600;
                    color: #333;
                }

                #wechat-editor-close-btn {
                    background: none;
                    border: none;
                    font-size: 24px;
                    cursor: pointer;
                    color: #999;
                    width: 30px;
                    height: 30px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    border-radius: 50%;
                }

                #wechat-editor-close-btn:hover {
                    background: #eee;
                    color: #666;
                }

                #wechat-editor-content {
                    display: flex;
                    flex: 1;
                    overflow: hidden;
                }

                #wechat-editor-input-area {
                    flex: 1;
                    display: flex;
                    flex-direction: column;
                    border-right: 1px solid #eee;
                }

                #wechat-editor-toolbar {
                    padding: 10px 15px;
                    border-bottom: 1px solid #eee;
                    background: #f8f9fa;
                    display: flex;
                    gap: 10px;
                    flex-wrap: wrap;
                }

                .wechat-editor-tool-btn {
                    background: #f1f1f1;
                    border: 1px solid #ddd;
                    border-radius: 4px;
                    padding: 5px 10px;
                    font-size: 14px;
                    cursor: pointer;
                }

                .wechat-editor-tool-btn:hover {
                    background: #e9e9e9;
                }

                #wechat-editor-textarea {
                    flex: 1;
                    padding: 20px;
                    border: none;
                    resize: none;
                    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
                    font-size: 14px;
                    line-height: 1.5;
                    outline: none;
                }

                #wechat-editor-preview-area {
                    flex: 1;
                    padding: 20px;
                    overflow-y: auto;
                    background: #fff;
                }

                #wechat-editor-preview-content {
                    max-width: 100%;
                }

                #wechat-editor-footer {
                    padding: 15px 20px;
                    border-top: 1px solid #eee;
                    background: #f8f9fa;
                    display: flex;
                    justify-content: flex-end;
                    gap: 10px;
                    border-radius: 0 0 8px 8px;
                }

                .wechat-editor-action-btn {
                    padding: 8px 16px;
                    border-radius: 4px;
                    border: none;
                    font-size: 14px;
                    cursor: pointer;
                }

                #wechat-editor-copy-btn {
                    background: #07c160;
                    color: white;
                }

                #wechat-editor-copy-btn:hover {
                    background: #06a050;
                }

                #wechat-editor-reset-btn {
                    background: #f1f1f1;
                    color: #333;
                }

                #wechat-editor-reset-btn:hover {
                    background: #e9e9e9;
                }

                #wechat-editor-toggle-btn {
                    position: fixed;
                    top: 70px;
                    right: 20px;
                    width: 45px;
                    height: 45px;
                    background: #00b37b;
                    color: white;
                    border: none;
                    border-radius: 50%;
                    box-shadow: 0 2px 10px rgba(0,0,0,0.2);
                    cursor: pointer;
                    z-index: 99999;
                    font-size: 16px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    transition: all 0.3s ease;
                }

                #wechat-editor-toggle-btn:hover {
                    background: #009966;
                    transform: scale(1.1);
                }

                /* Markdown样式 */
                .wechat-editor-preview h1,
                .wechat-editor-preview h2,
                .wechat-editor-preview h3,
                .wechat-editor-preview h4,
                .wechat-editor-preview h5,
                .wechat-editor-preview h6 {
                    margin: 20px 0 15px;
                    font-weight: bold;
                    color: #333;
                }

                .wechat-editor-preview h1 {
                    font-size: 24px;
                }

                .wechat-editor-preview h2 {
                    font-size: 22px;
                }

                .wechat-editor-preview h3 {
                    font-size: 20px;
                }

                .wechat-editor-preview h4 {
                    font-size: 18px;
                }

                .wechat-editor-preview h5 {
                    font-size: 16px;
                }

                .wechat-editor-preview h6 {
                    font-size: 14px;
                }

                .wechat-editor-preview p {
                    margin: 0 0 15px;
                    line-height: 1.7;
                    color: #333;
                    font-size: 16px;
                }

                .wechat-editor-preview ul,
                .wechat-editor-preview ol {
                    margin: 10px 0 15px;
                    padding-left: 20px;
                }

                .wechat-editor-preview li {
                    margin-bottom: 8px;
                    line-height: 1.6;
                }

                .wechat-editor-preview a {
                    color: #00b37b;
                    text-decoration: none;
                }

                .wechat-editor-preview pre,
                .wechat-editor-preview code {
                    background: #f8f8f8;
                    border-radius: 4px;
                    padding: 12px;
                    font-size: 14px;
                    line-height: 1.5;
                    overflow-x: auto;
                    margin: 15px 0;
                    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
                }

                .wechat-editor-preview blockquote {
                    border-left: 4px solid #00b37b;
                    margin: 15px 0;
                    padding: 10px 20px;
                    background: #f8f8f8;
                    color: #666;
                }

                .wechat-editor-preview img {
                    max-width: 100%;
                    height: auto;
                    border-radius: 4px;
                    margin: 10px 0;
                }

                .wechat-editor-preview table {
                    width: 100%;
                    margin: 15px 0;
                    border-collapse: collapse;
                    font-size: 14px;
                }

                .wechat-editor-preview td,
                .wechat-editor-preview th {
                    padding: 8px 12px;
                    border: 1px solid #ddd;
                    text-align: left;
                }

                .wechat-editor-preview th {
                    background: #f8f8f8;
                    font-weight: bold;
                }

                .wechat-editor-notification {
                    position: fixed;
                    top: 20px;
                    right: 20px;
                    background: #27ae60;
                    color: white;
                    padding: 12px 20px;
                    border-radius: 4px;
                    box-shadow: 0 2px 10px rgba(0,0,0,0.2);
                    z-index: 100001;
                    font-family: Arial, sans-serif;
                    font-size: 14px;
                }

                .wechat-editor-notification.error {
                    background: #e74c3c;
                }
            `);

            // 创建主面板
            const panel = document.createElement('div');
            panel.id = 'wechat-editor-panel';
            
            panel.innerHTML = `
                <div id="wechat-editor-panel-header">
                    <div id="wechat-editor-panel-title">微信公众号文章编辑器</div>
                    <button id="wechat-editor-close-btn">×</button>
                </div>
                <div id="wechat-editor-content">
                    <div id="wechat-editor-input-area">
                        <div id="wechat-editor-toolbar">
                            <button class="wechat-editor-tool-btn" data-action="heading">标题</button>
                            <button class="wechat-editor-tool-btn" data-action="bold">粗体</button>
                            <button class="wechat-editor-tool-btn" data-action="italic">斜体</button>
                            <button class="wechat-editor-tool-btn" data-action="link">链接</button>
                            <button class="wechat-editor-tool-btn" data-action="code">代码</button>
                            <button class="wechat-editor-tool-btn" data-action="quote">引用</button>
                            <button class="wechat-editor-tool-btn" data-action="ul">无序列表</button>
                            <button class="wechat-editor-tool-btn" data-action="ol">有序列表</button>
                        </div>
                        <textarea id="wechat-editor-textarea" placeholder="在此粘贴或输入您的Markdown内容..."></textarea>
                    </div>
                    <div id="wechat-editor-preview-area">
                        <div id="wechat-editor-preview-content" class="wechat-editor-preview"></div>
                    </div>
                </div>
                <div id="wechat-editor-footer">
                    <button id="wechat-editor-reset-btn" class="wechat-editor-action-btn">重置</button>
                    <button id="wechat-editor-copy-btn" class="wechat-editor-action-btn">复制到微信</button>
                </div>
            `;
            
            document.body.appendChild(panel);
            
            // 创建切换按钮
            const toggleBtn = document.createElement('button');
            toggleBtn.id = 'wechat-editor-toggle-btn';
            toggleBtn.innerHTML = '📝';
            document.body.appendChild(toggleBtn);
        }

        // 绑定事件
        bindEvents() {
            // 切换面板显示
            document.getElementById('wechat-editor-toggle-btn').addEventListener('click', () => {
                const panel = document.getElementById('wechat-editor-panel');
                panel.style.display = panel.style.display === 'none' ? 'flex' : 'none';
            });
            
            // 关闭面板
            document.getElementById('wechat-editor-close-btn').addEventListener('click', () => {
                document.getElementById('wechat-editor-panel').style.display = 'none';
            });
            
            // 文本域输入事件
            document.getElementById('wechat-editor-textarea').addEventListener('input', () => {
                this.updatePreview();
            });
            
            // 工具栏按钮事件
            document.getElementById('wechat-editor-toolbar').addEventListener('click', (e) => {
                if (e.target.classList.contains('wechat-editor-tool-btn')) {
                    const action = e.target.dataset.action;
                    this.handleToolbarAction(action);
                }
            });
            
            // 复制按钮事件
            document.getElementById('wechat-editor-copy-btn').addEventListener('click', () => {
                this.copyToWeChat();
            });
            
            // 重置按钮事件
            document.getElementById('wechat-editor-reset-btn').addEventListener('click', () => {
                this.resetEditor();
            });
        }

        // 处理工具栏动作
        handleToolbarAction(action) {
            const textarea = document.getElementById('wechat-editor-textarea');
            const start = textarea.selectionStart;
            const end = textarea.selectionEnd;
            const selectedText = textarea.value.substring(start, end);
            let newText = '';
            let newCursorPos = start;
            
            switch(action) {
                case 'heading':
                    newText = `# ${selectedText || '标题'}`;
                    newCursorPos = start + 2;
                    break;
                case 'bold':
                    newText = `**${selectedText || '粗体文本'}**`;
                    newCursorPos = start + 2;
                    break;
                case 'italic':
                    newText = `*${selectedText || '斜体文本'}*`;
                    newCursorPos = start + 1;
                    break;
                case 'link':
                    newText = `[${selectedText || '链接文本'}](http://example.com)`;
                    newCursorPos = start + selectedText.length + 3;
                    break;
                case 'code':
                    newText = `\`${selectedText || '代码'}\``;
                    newCursorPos = start + 1;
                    break;
                case 'quote':
                    newText = `> ${selectedText || '引用内容'}`;
                    newCursorPos = start + 2;
                    break;
                case 'ul':
                    newText = `- ${selectedText || '列表项'}`;
                    newCursorPos = start + 2;
                    break;
                case 'ol':
                    newText = `1. ${selectedText || '列表项'}`;
                    newCursorPos = start + 3;
                    break;
            }
            
            textarea.value = textarea.value.substring(0, start) + newText + textarea.value.substring(end);
            textarea.focus();
            textarea.setSelectionRange(newCursorPos, newCursorPos + newText.length - (action === 'heading' ? 2 : action === 'bold' ? 4 : action === 'italic' ? 2 : action === 'code' ? 2 : action === 'quote' ? 2 : action === 'ul' ? 2 : action === 'ol' ? 3 : 0));
            this.updatePreview();
        }

        // 更新预览
        updatePreview() {
            const content = document.getElementById('wechat-editor-textarea').value;
            const preview = document.getElementById('wechat-editor-preview-content');
            preview.innerHTML = this.markdownToHTML(content);
        }

        // Markdown转HTML
        markdownToHTML(markdown) {
            // 简单的Markdown解析器
            let html = markdown;
            
            // 代码块
            html = html.replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>');
            
            // 行内代码
            html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
            
            // 引用
            html = html.replace(/^> (.+)$/gm, '<blockquote>$1</blockquote>');
            
            // 无序列表
            html = html.replace(/^\s*[-*+]\s+(.+)$/gm, '<li>$1</li>');
            html = html.replace(/(<li>.*<\/li>)/gs, '<ul>$1</ul>');
            
            // 有序列表
            html = html.replace(/^\s*\d+\.\s+(.+)$/gm, '<li>$1</li>');
            html = html.replace(/(<li>.*<\/li>)/gs, '<ol>$1</ol>');
            
            // 链接
            html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
            
            // 图片
            html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1">');
            
            // 粗体
            html = html.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
            
            // 斜体
            html = html.replace(/\*(.*?)\*/g, '<em>$1</em>');
            
            // 标题
            html = html.replace(/^###### (.*$)/gm, '<h6>$1</h6>');
            html = html.replace(/^##### (.*$)/gm, '<h5>$1</h5>');
            html = html.replace(/^#### (.*$)/gm, '<h4>$1</h4>');
            html = html.replace(/^### (.*$)/gm, '<h3>$1</h3>');
            html = html.replace(/^## (.*$)/gm, '<h2>$1</h2>');
            html = html.replace(/^# (.*$)/gm, '<h1>$1</h1>');
            
            // 段落
            html = html.replace(/^\s*([^\n<]+?)\s*$/gm, '<p>$1</p>');
            
            // 处理空行
            html = html.replace(/<p>\s*<\/p>/g, '');
            
            return html;
        }

        // 复制到微信
        copyToWeChat() {
            const content = document.getElementById('wechat-editor-preview-content').innerHTML;
            
            try {
                GM_setClipboard(content, 'text/html');
                this.showNotification('✅ 已复制到剪贴板,可粘贴到微信公众号编辑器');
            } catch (error) {
                console.error('复制失败:', error);
                this.showNotification('❌ 复制失败,请重试', true);
            }
        }

        // 重置编辑器
        resetEditor() {
            document.getElementById('wechat-editor-textarea').value = '';
            document.getElementById('wechat-editor-preview-content').innerHTML = '';
        }

        // 显示通知
        showNotification(message, isError = false) {
            // 移除现有的通知
            const existingNotification = document.querySelector('.wechat-editor-notification');
            if (existingNotification) {
                existingNotification.remove();
            }
            
            // 创建通知元素
            const notification = document.createElement('div');
            notification.className = 'wechat-editor-notification';
            if (isError) {
                notification.classList.add('error');
            }
            notification.innerHTML = message;
            
            document.body.appendChild(notification);
            
            // 3秒后移除通知
            setTimeout(() => {
                if (notification.parentNode) {
                    notification.parentNode.removeChild(notification);
                }
            }, 3000);
        }
    }

    // 初始化插件
    new WeChatArticleEditor();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址