diff --git a/css/edit.css b/css/edit.css index 7b41f19..bfb171a 100644 --- a/css/edit.css +++ b/css/edit.css @@ -86,7 +86,7 @@ padding-left: 25px; position: sticky; top: 0; - z-index: 10; + z-index: 1; } #edit .edit-container #editor—wrapper .editor-toolbar .w-e-panel-content-emotion { width: 490px; @@ -118,7 +118,6 @@ color: #000000; line-height: 23px; margin-right: 40px; - position: relative; padding: 0; } #edit .edit-container #editor—wrapper .editor-toolbar .toolbar-item .icon { diff --git a/css/edit.less b/css/edit.less index 804a918..c9e541f 100644 --- a/css/edit.less +++ b/css/edit.less @@ -96,7 +96,8 @@ padding-left: 25px; position: sticky; top: 0; - z-index: 10; + // z-index: 10; + z-index: 1; .w-e-panel-content-emotion { width: 490px; } @@ -139,7 +140,7 @@ color: #000000; line-height: 23px; margin-right: 40px; - position: relative; + // position: relative; padding: 0; > button { diff --git a/edit.html b/edit.html index 98c764a..0c0e4fb 100644 --- a/edit.html +++ b/edit.html @@ -34,10 +34,11 @@
- +
{{ info?.title?.length ? titleLength - info?.title?.length : titleLength }}
- +
@@ -89,11 +90,12 @@
{{ emoji }}
--> + -
+
diff --git a/js/edit.js b/js/edit.js index 5934fe5..5c566e7 100644 --- a/js/edit.js +++ b/js/edit.js @@ -1,9 +1,54 @@ // 简单版本的论坛编辑器,确保图片插入功能正常 const { createApp, ref, computed, onMounted, nextTick, onUnmounted } = Vue; import { headTop } from "../component/head-top/head-top.js"; -const { createEditor, createToolbar } = window.wangEditor; +const { createEditor, createToolbar, SlateTransforms, Boot, SlateEditor } = window.wangEditor; console.log("createEditor", createEditor); + +class MyButtonMenu { // JS 语法 + constructor() { + this.title = '居中' // 自定义菜单标题 + // this.iconSvg = '...' // 可选 + this.tag = 'button' + } + + // 获取菜单执行时的 value ,用不到则返回空 字符串或 false + getValue(editor) { + // console.log("getValue", editor); + + // TS 语法 + // getValue(editor) { // JS 语法 + return ' hello ' + } + + // 菜单是否需要激活(如选中加粗文本,“加粗”菜单会激活),用不到则返回 false + isActive(editor) { + console.log("isActive", editor.getFragment()?.[0]); + if (editor.getFragment()?.[0]?.textAlign == 'center') return true + return false + } + + // 菜单是否需要禁用(如选中 H1 ,“引用”菜单被禁用),用不到则返回 false + isDisabled(editor) { + // TS 语法 + // isDisabled(editor) { // JS 语法 + return false + } + + // 点击菜单时触发的函数 + exec(editor, value) { + // center + let align = this.isActive(editor) ? 'left' : 'center' + console.log("align", this.isActive(editor)); + + SlateTransforms.setNodes(editor, { + textAlign: align + },) + } +} + + + const editApp = createApp({ setup() { let titleLength = ref(200); @@ -160,15 +205,6 @@ const editApp = createApp({ if (!src) { return; } - - // let config = uConfigData; - // // 1. 构造 FormData(包含你的接口所需字段) - // const formData = new FormData(); - // formData.append(config.requestName, file); // 文件数据 - // formData.append("name", file.name); // 文件名 - // formData.append("type", "image"); // 文件名 - // formData.append("data", config.params.data); // 文件名 - await setTimeout(() => { console.log("1111"); return true; @@ -189,47 +225,26 @@ const editApp = createApp({ // 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息 } - // 【新增】判断节点的对齐方式 - const getNodeAlign = (node) => { - if (!node) return "left"; // 默认居左 - // 获取节点的text-align样式(优先内联样式,再取CSS计算样式) - const inlineAlign = node.style.textAlign; - if (inlineAlign) return inlineAlign; + // // 自定义转换视频 + // const customParseVideoSrc = (src) => { + // console.log("customParseVideoSrc", this); - const computedStyle = window.getComputedStyle(node); - return computedStyle.textAlign || "left"; - }; + // // TS 语法 + // // function customParseVideoSrc(src) { // JS 语法 + // if (src.includes('.bilibili.com')) { + // // 转换 bilibili url 为 iframe (仅作为示例,不保证代码正确和完整) + // const arr = location.pathname.split('/') + // const vid = arr[arr.length - 1] + // return `` + // } + // // return src + // return `` - // 【新增】切换对齐方式(居中 ↔ 居左) - const toggleAlign = () => { - const editorInst = editor.value; - if (!editorInst) return; - - // 禁用编辑器默认的居中命令 - editorInst.off("clickToolbar", "justifyCenter"); - - // 获取当前选中的节点(优先段落/块级节点) - const selectedNode = getSelectedNode(editorInst); - const blockNode = DomEditor.getClosestBlock(selectedNode); // 获取块级节点(p/div等) - if (!blockNode) return; - - // 判断当前对齐方式 - const currentAlign = getNodeAlign(blockNode); - - // 切换对齐:居中 → 居左;其他 → 居中 - const newAlign = currentAlign === "center" ? "left" : "center"; - - // 设置节点对齐样式 - editorInst.restoreSelection(); // 恢复选区 - blockNode.style.textAlign = newAlign; - - // 触发编辑器更新 - editorInst.change(); - editorInst.focus(); // 保持焦点 - }; + // // return ``; + // } const editorConfig = { - placeholder: "Type here...", + placeholder: "输入正文", enabledMenus: [], MENU_CONF: { ["emotion"]: { @@ -293,7 +308,7 @@ const editApp = createApp({ ajax(config.url, formData).then((res) => { const data = res.data; console.log("上传成功:", data); - insertFn(data.url); // 传入图片的可访问 URL + insertFn(`${data.url}?aid=${data.aid}`); // 传入图片的可访问 URL }); } catch (err) { console.error("上传出错:", err); @@ -301,6 +316,19 @@ const editApp = createApp({ }, }, + ['insertVideo']: { + onInsertedVideo(videoNode) { + // TS 语法 + // onInsertedVideo(videoNode) { // JS 语法 + if (videoNode == null) return + + const { src } = videoNode + console.log('inserted video', src) + }, + // checkVideo: customCheckVideoFn, // 也支持 async 函数 + // parseVideoSrc: (src) => customParseVideoSrc(src), // 也支持 async 函数 + }, + ["uploadVideo"]: { server: uConfigData.url, @@ -343,26 +371,14 @@ const editApp = createApp({ // 步骤3:再上传第一帧封面(type 传 'cover',按后端要求调整) const coverUploadRes = await uploading(coverFile, coverFile.name, "image"); console.log("封面上传成功", coverUploadRes); + console.log(insertFn); - insertFn(videoUploadRes.url, coverUploadRes.url); + insertFn(`${videoUploadRes.url}?aid=${videoUploadRes.aid}`, `${coverUploadRes.url}?aid=${coverUploadRes.aid}`); } catch (err) { console.error("上传出错:", err); } }, }, - - ["justifyCenter"]: { - onClick: (editor) => { - console.log("editor", editor); - toggleAlign(); // 替换为自定义切换逻辑 - }, - // 【可选】自定义居中按钮的激活状态(选中时高亮) - isActive: (editor) => { - const selectedNode = getSelectedNode(editor); - const blockNode = DomEditor.getClosestBlock(selectedNode); - return blockNode && getNodeAlign(blockNode) === "center"; - }, - }, }, onChange(editor) { @@ -404,16 +420,34 @@ const editApp = createApp({ // "uploadVideo", // 插入视频 "insertLink", // 插入链接 "bold", // 粗体 - "justifyCenter", + // "justifyCenter", ], }; + const menu1Conf = { + key: 'customCenter', // 定义 menu key :要保证唯一、不重复(重要) + factory() { + return new MyButtonMenu() // 把 `YourMenuClass` 替换为你菜单的 class + }, + } + Boot.registerMenu(menu1Conf) + console.log(toolbarConfig, "toolbarConfig"); + + toolbarConfig.insertKeys = { + index: 7, // 插入的位置,基于当前的 toolbarKeys + keys: ['customCenter'], + } const toolbar = createToolbar({ editor, selector: "#toolbar-container", config: toolbarConfig, mode: "default", }); + + + + + console.log("editor.commands", editor); nextTick(() => { @@ -447,10 +481,10 @@ const editApp = createApp({ boldItem.classList.add("toolbar-item", "flexacenter"); bold.innerHTML = '粗体 粗体'; - const justifyCenter = toolbarRef.value.querySelector('[data-menu-key="justifyCenter"]'); - const justifyCenterItem = justifyCenter.parentElement; - justifyCenterItem.classList.add("toolbar-item", "flexacenter"); - justifyCenter.innerHTML = '居中 居中'; + const customCenter = toolbarRef.value.querySelector('[data-menu-key="customCenter"]'); + const customCenterItem = customCenter.parentElement; + customCenterItem.classList.add("toolbar-item", "flexacenter"); + customCenter.innerHTML = '居中 居中'; }); }; @@ -549,7 +583,7 @@ const editApp = createApp({ try { const DomEditor = window.wangEditor && window.wangEditor.DomEditor; if (DomEditor && editor) node = DomEditor.getSelectionNode(editor); - } catch (e) {} + } catch (e) { } if (!node) { const sel = window.getSelection(); if (sel && sel.rangeCount) node = sel.getRangeAt(0).commonAncestorContainer; @@ -844,7 +878,7 @@ const editApp = createApp({ let format = ref(""); const submit = (status) => { const infoTarget = { ...info.value } || {}; - let content = editorRef.value.innerHTML; + let content = editor.getHtml() const images = extractImages(editorRef.value); const videos = extractVideos(editorRef.value); @@ -925,14 +959,20 @@ const editApp = createApp({ const imgElements = dom.querySelectorAll("img"); imgElements.forEach((imgEl) => { - const url = imgEl.getAttribute("src")?.trim() || ""; - const aid = imgEl.dataset.aid?.trim() || ""; // 用 dataset 简化自定义属性读取 + let url = imgEl.getAttribute("src")?.trim() || ""; + const urlObj = new URL(url); + const aid = urlObj.searchParams.get('aid'); + const queryIndex = url.indexOf('?'); + const cleanUrl = queryIndex !== -1 ? url.substring(0, queryIndex) : url; images.push({ - url, + url: cleanUrl, aid: Number(aid), }); }); + + console.log("提取完成的图片列表:", images); + return images; }; @@ -943,16 +983,27 @@ const editApp = createApp({ // 2. 遍历每个 video 节点,直接获取属性 videoElements.forEach((videoEl) => { - const url = videoEl.getAttribute("src")?.trim() || ""; // 视频地址 - const posterurl = videoEl.getAttribute("poster")?.trim() || ""; // 封面图 - const aid = videoEl.getAttribute("aid")?.trim() || ""; // 视频 ID(自定义属性) - const posterid = videoEl.getAttribute("posterid")?.trim() || ""; // 封面 ID(自定义属性) + const posterurl = videoEl.getAttribute("poster")?.trim() || ""; // 视频地址 + // 1. 用 URL 构造函数解析链接(自动处理查询参数) + const urlObj = new URL(posterurl); + // 2. 获取 aid 参数(get 方法找不到时返回 null) + const posterid = urlObj.searchParams.get('aid'); + const sourceEl = videoEl.querySelector('source'); + + const url = sourceEl.getAttribute('src') || null; + const obj = new URL(url); + // 2. 获取 aid 参数(get 方法找不到时返回 null) + const aid = obj.searchParams.get('aid'); + const queryIndex = url.indexOf('?'); + const cleanUrl = queryIndex !== -1 ? url.substring(0, queryIndex) : url; + const queryIndex2 = posterurl.indexOf('?'); + const cleanPosterurl = queryIndex2 !== -1 ? posterurl.substring(0, queryIndex2) : posterurl; result.push({ aid: Number(aid), posterid: Number(posterid), - url, - posterurl, + url: cleanUrl, + posterurl: cleanPosterurl, }); }); @@ -1094,14 +1145,21 @@ const editApp = createApp({ }); }; - const linkClick = () => {}; + const linkClick = () => { }; const overstriking = () => { console.log("加粗"); - editor.addMark("bold", true); // 加粗 + // editor.addMark("bold", true); // 加粗 // editor.addMark("color", "#999"); // 文本颜色 - console.log("editor", editor.addMark); + // console.log("editor", editor.addMark); + + // editor.addMark('justifyCenter', true) // 加粗 + console.log(SlateTransforms.setNodes, editor); + + SlateTransforms.setNodes(editor, { + textAlign: 'right' + },) }; return { toolbarRef, overstriking, isH1, linkClick, insertVideo, insertLink, linkUrl, linkText, linkState, openLink, closeLink, handleClick, uniqid, userInfoWin, titleLength, submit, emojiState, openEmoji, closeEmoji, selectEmoji, optionEmoji, isPTitle, onEditorInput, onEditorFocus, onEditorBlur, paragraphTitle, info, tagList, token, cutAnonymity, editorRef, insertImage, judgeIsEmpty, isEmpty };