You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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)获取,拿到坐标后要将编辑器定位到该元素位置。

解决方案
  1. 坐标获取直接用jQuery内置的offset()方法即可,该方法返回元素相对于整个文档的top、left坐标值。如果你的弹窗父元素存在非static的定位规则,可替换为position()方法获取相对于父级的坐标。
  2. 在原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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 13:06:00