受欢迎的博客标签

TinyMCE「左侧导航栏 + 右侧编辑区」知乎编辑器

Published

可落地的方案,把 TinyMCE 改造成「左侧导航栏 + 右侧编辑区」,效果和知乎编辑器非常接近,并且适用于 .NET(ASP.NET / ASP.NET Core)

一、最终结构(知乎式布局

┌──────────────────────────────────────┐
│  顶部工具栏(TinyMCE toolbar)        │
├──────────────┬───────────────────────┤
│ 左侧导航栏   │  右侧编辑器正文区     │
│(大纲/模块) │  TinyMCE content     │
│              │                       │
└──────────────┴───────────────────────┘

 

左侧:

文章大纲(H1 / H2 / H3)

H1 标题
 ├─ H2 小节
 │   ├─ H3 子节
 │   │   └─ H4 说明
 └─ H2 另一个小节
     └─ H3 …



右侧:

原生 TinyMCE 编辑体验

二、思路

TinyMCE 本身不负责布局,我们需要用外层 HTML + CSS 控制布局,。TinyMCE 只作为「右侧编辑器」

三、HTML 布局(左栏 + 编辑器)

<div class="editor-page">
    <!-- 左侧导航 -->
    <div class="editor-sidebar">
        <div class="sidebar-title">文章大纲</div>
        <ul id="outlineList"></ul>
    </div>

    <!-- 右侧编辑器 -->
    <div class="editor-main">
        <textarea id="editor"></textarea>
    </div>
</div>

四、CSS(知乎式视觉)

.editor-page {
    display: flex;
    height: calc(100vh - 60px);
    background: #f6f7f8;
}

.editor-sidebar {
    width: 240px;
    background: #fff;
    border-right: 1px solid #e5e6eb;
    padding: 12px;
    overflow-y: auto;
}

.sidebar-title {
    font-weight: bold;
    margin-bottom: 10px;
}

.editor-sidebar ul {
    list-style: none;
    padding: 0;
}

.editor-sidebar li {
    cursor: pointer;
    padding: 4px 0;
    color: #555;
}

.editor-sidebar li:hover {
    color: #1772f6;
}

.editor-main {
    flex: 1;
    padding: 12px;
}

/* TinyMCE 占满 */
.tox-tinymce {
    height: 100% !important;
}

 

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>知乎风编辑器</title>

   @*  <script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/6/tinymce.min.js"></script> *@

    <script src="//unpkg.com/[email protected]/tinymce.min.js"></script>

    <style>
        body {
            margin: 0;
            font-family: -apple-system,BlinkMacSystemFont;
        }

        .editor-page {
            display: flex;
            height: 100vh;
        }

        .editor-sidebar {
            width: 240px;
            border-right: 1px solid #e5e6eb;
            padding: 12px;
            background: #fff;
            overflow-y: auto;
        }

        .editor-main {
            flex: 1;
            padding: 12px;
        }

        .editor-sidebar li {
            cursor: pointer;
            padding: 4px 0;
        }

        .tox-tinymce {
            height: 100% !important;
        }
    </style>
</head>

<body>
    <form method="post" asp-action="Save">

        <div class="editor-page">
            <div class="editor-sidebar">
                <strong>文章大纲</strong>
                <ul id="outlineList"></ul>
            </div>

            <div class="editor-main">
                <textarea id="editor" name="content"></textarea>
                <button type="submit">保存</button>
            </div>
        </div>

    </form>

    <script>
        tinymce.init({
            selector: '#editor',
            height: '100%',
            menubar: false,
            plugins: 'lists link image code',
            toolbar: 'undo redo | h1 h2 h3 | bold italic | bullist numlist | code',

            setup: function (editor) {
                editor.on('Change KeyUp', function () {
                    updateOutline(editor);
                });
            }
        });

        function updateOutline(editor) {
            const outline = document.getElementById('outlineList');
            outline.innerHTML = '';

            editor.getBody().querySelectorAll('h1,h2,h3').forEach(h => {
                const li = document.createElement('li');
                li.innerText = h.innerText;
                li.onclick = () => {
                    editor.selection.select(h);
                    editor.selection.scrollIntoView(h);
                };
                outline.appendChild(li);
            });
        }
    </script>

</body>
</html>