如何用jQuery获取选中元素X/Y坐标,实现CKEditor5弹窗吸附目标元素
问题背景
我需要开发一个内嵌编辑器的弹窗,希望它要么行内展示,要么吸附到触发它打开的目标元素上,但目前这个弹窗是通过template.ejs渲染的,当前样式表现为模态框。
请问有没有方法可以获取目标元素的X/Y坐标来调整弹窗位置,或是有更优的实现方案?
目前我通过this.$el获取元素并加入编辑器,希望编辑器能固定在触发打开的元素位置。
现有核心代码(editor.js)
render: function (options) { var that = this; // get x, y position from options of editElement and set top left of cke5-dialog this.options = $.extend(this.options, options); this.preRender(); console.log(' Ckeditor5EditView rendered'); let $el = this.$el; $el.show(); let $editConatiner = $el.find('div.editable-container'); let $toolConatiner = $el.find('div.toolbar-container'); $editConatiner.html(this.options.htmlElm); $toolConatiner.html(""); // $(this.options.editingElm).after(this.$el); // $(this.options.editingElm).hide(); DecoupledEditor.create($editConatiner[0]).then(editor => { window.editor = editor; $toolConatiner[0].appendChild(editor.ui.view.toolbar.element); that.htmlEditor = editor; }).catch(error => { console.error('There was a problem initializing the editor.', error); }); },
参考样例代码
JS代码
const sampleData = ` <p style="font:10pt Times New Roman, Times, Serif;margin:0pt 0;text-align:justify;text-indent:0.25in;"> In 2015, the Bangladesh subsidiary entered into agreements to rent office facilities under <p> `; DecoupledEditor.create(sampleData) .then((editor) => { window.editor = editor; document .querySelector(".toolbar-container") .appendChild(editor.ui.view.toolbar.element); document .querySelector(".editable-container") .appendChild(editor.ui.view.editable.element); }) .catch((error) => { console.error( "There was a problem initializing the editor.", error ); });
CSS代码
.cke5-dialog { position: absolute; top: 30%; width: calc(72% - 4px); left: 25px; display: none; } .cke5-header { background-color: gray; width: 100%; padding: 5px; height: 35px; } .cke5-button-pane { float: right; } .cke5-dialog-content { width: 100%; height: 100%; } .cke5-editor-pane { width: 100%; } .cke5-dialog .toolbar-container { position: relative; border: 1px solid #ddd; background: #eee; padding: 3px; } .cke5-dialog .editable-container { position: relative; border: 1px solid gray !important; background: #eee; } .cke5-dialog p { margin-top: 0px; margin-bottom: 0px; } .cke5-dialog .editable-container { padding: 10px!important; min-height: 130px; max-height: 600px; } .cke5-dialog .editable-container .document-editor__editable.ck-editor__editable { min-height: 21cm; padding: 2em; border: 1px #D3D3D3 solid; border-radius: var(--ck-border-radius); background: white; box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); }
HTML代码
<body> <p style="font:10pt Times New Roman, Times, Serif;margin:0pt 0;text-align:justify;text-indent:0.25in;" xvid="774e1b176687ef278ec0984ac7cfb438"> In 2015, the Bangladesh subsidiary entered into agreements to rent office facilities under <p> <div class='cke5-dialog-content'> <div class='cke5-header'> <div class="cke5-button-pane"> <button type="button" class="btn btn-cancel-html btn-xs cursor-pointer margin-right-5" data-rel="tooltip"> <i class="fa fa-times"></i> </button> <button type="button" class="btn btn-update-html btn-xs cursor-pointer" data-rel="tooltip"> <i class="far fa-save"></i> </button> </div> </div> <div class='cke5-editor-pane'> <div class="toolbar-container"></div> <div class="editable-container"></div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/@ckeditor/ckeditor5-build-decoupled-document@30.0.0/build/ckeditor.min.js"></script> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet" /> </body>
更新需求
需要获取打开编辑器的目标元素的X/Y坐标,该元素可通过$(this.options.editingElm)获取,拿到坐标后要将编辑器定位到该元素位置。
解决方案
- 坐标获取直接用jQuery内置的
offset()方法即可,该方法返回元素相对于整个文档的top、left坐标值。如果你的弹窗父元素存在非static的定位规则,可替换为position()方法获取相对于父级的坐标。 - 在原render方法的
$el.show()后新增定位逻辑即可,修改后的代码如下:
render: function (options) { var that = this; this.options = $.extend(this.options, options); this.preRender(); console.log(' Ckeditor5EditView rendered'); let $el = this.$el; $el.show(); // 新增定位逻辑开始 const $triggerEl = $(this.options.editingElm); const triggerPos = $triggerEl.offset(); // 这里的10是偏移量,可根据需求调整,避免弹窗完全挡住触发元素 let dialogTop = triggerPos.top + $triggerEl.outerHeight() + 10; let dialogLeft = triggerPos.left; // 可选:增加边界判断,避免弹窗超出可视区域 const dialogWidth = $el.outerWidth(); const dialogHeight = $el.outerHeight(); const viewportWidth = $(window).width(); const viewportHeight = $(window).height(); const scrollTop = $(window).scrollTop(); if (dialogLeft + dialogWidth > viewportWidth) { dialogLeft = viewportWidth - dialogWidth - 10; } if (dialogTop + dialogHeight > viewportHeight + scrollTop) { dialogTop = triggerPos.top - dialogHeight - 10; } $el.css({ top: dialogTop + 'px', left: dialogLeft + 'px' }); // 新增定位逻辑结束 let $editConatiner = $el.find('div.editable-container'); let $toolConatiner = $el.find('div.toolbar-container'); $editConatiner.html(this.options.htmlElm); $toolConatiner.html(""); // 如果你需要更稳定的行内吸附效果,可把下面两行注释打开,将弹窗插入到触发元素同级,定位逻辑可以更简单 // $(this.options.editingElm).after(this.$el); // $(this.options.editingElm).hide(); DecoupledEditor.create($editConatiner[0]).then(editor => { window.editor = editor; $toolConatiner[0].appendChild(editor.ui.view.toolbar.element); that.htmlEditor = editor; }).catch(error => { console.error('There was a problem initializing the editor.', error); }); },
内容的提问来源于stack exchange,提问作者user13424765
相关产品推荐
相关产品推荐

