Greasy Fork

Greasy Fork is available in English.

微信公众号文章编辑器

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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();
})();