@MaximPatrushev

Как узнать координаты элемента в iframe?

В целом задача состоит в том, что бы сделать вывод реактивного оглавления для содержимого WYSIWYG редактора.

Я работаю с React и интегрирую ckeditor в качестве редактора. Задача - сделать так, что бы при заполнении редактора контентом, все заголовки парсились и реактивно выводились в виде оглавления рядом с окном редактора. При этом пункты в этом оглавлении должны быть кликабельны - по клику должно происходить прокручивание окна редактора до соответствующего якоря(заголовка). Имеющиеся плагины позволяют только выводить таблицу с оглавлением, но не делать ее элементы кликабельными.

Я решил "вручную" достать заголовки из содержимого редактора, вывести их, и навесить на них ссылки на якоря внутри редактора. Но это не сработало, переход по якорям внутри iframe или не возможен, или я не смог найти способа это сделать. Тогда я решил на эти выведенные заголовки навесить обработчики и методом scrollTo имитировать переход по якорям.

Здесь возникла проблема с получением координат заголовков в тексте редактора (внутри iframe). headerObj.offsetTop все время возвращается равным 0.

Буду рад за помощь в решении проблемы любым из путей)

import React, { useState } from 'react';
import CKEditor from 'ckeditor4-react';

const App = () => {

  const [headers, setHeaders] = useState([]);

  const handleChange = e => {
    const content = e.editor.getData();
    const contentObject = document.createElement('div');
    contentObject.innerHTML = content;
    const headersArray = [...contentObject.getElementsByTagName('h2')];
    setHeaders(headersArray);
  };

  const goToAnchor = headerObj => {
    const frame = document.getElementsByTagName('iframe')[0];
    const top = headerObj.offsetTop + frame.contentWindow.scrollY;

    frame.contentWindow.scrollTo({
      top: top,
      behavior: "smooth"
    })
  };


  return (
    <div className="App">
      <h2>Using CKEditor 4 in React</h2>
      <CKEditor
        data="<h2>1. Заголовок 1</h2><h2>2. Заголовок 2</h2><h2>3. Заголовок 3</h2>"
        onChange={e => handleChange(e)}
      />
      <div>
        <h2>Содержание</h2>
        {headers.map((header, index) => {
          return (
            <h2
              key={index}
              dangerouslySetInnerHTML={{__html: header.innerHTML}}
              onClick={() => goToAnchor(header)}
            />
          );
        })}
      </div>
    </div>
  );
};

export default App;
  • Вопрос задан
  • 255 просмотров
Решения вопроса 1
0xD34F
@0xD34F Куратор тега React
headerObj.offsetTop

Бессмысленная операция. Этот headerObj - совсем не тот, что в iframe'е. Лучше при клике в списке получайте индекс кликнутого элемента, и берите в iframe'е заголовок с таким же индексом.

const frame = document.getElementsByTagName('iframe')[0];

Вот такого не надо. Используйте useRef - получаете ссылку на экземпляр своего редактора, у него там свойство document есть, нужного вам iframe'а.

UPD. https://codesandbox.io/s/j3oy0q1219
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы