Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在渲染时,大纲点击不跳转 #1516

Closed
dlpuzcl opened this issue Dec 13, 2023 · 4 comments
Closed

在渲染时,大纲点击不跳转 #1516

dlpuzcl opened this issue Dec 13, 2023 · 4 comments

Comments

@dlpuzcl
Copy link

dlpuzcl commented Dec 13, 2023

编辑模式

  • wysiwyg 所见即所得模式

描述问题

参考了render.js 里的代码
在vue3中 使用下面代码正常渲染成功。大纲也显示正确,但是始终点击大纲没反应,求助大佬看看, render的demo点击是好用的

<template>

  <div id="previewWrap">
    <div id="preview" ref="viewerRef" class="preview">
    </div>
  </div>
  <div id="outline"></div>


</template>

<script lang="js" setup>
  import { onBeforeUnmount, onDeactivated, ref, unref, watch } from 'vue';
  import Vditor from 'vditor';
  import { onMountedOrActivated } from '@vben/hooks';
  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
  import { getTheme } from './getTheme';
  import {PageWrapper} from "@/components/Page";
  import {useGlobSetting} from "@/hooks/setting";
  const globSetting = useGlobSetting();

  const props = defineProps({
    value: { type: String },
    class: { type: String },
  });
  const viewerRef = ref(null);
  const outlineRef = ref(null);

  const vditorPreviewRef = ref(null);
  const { getDarkMode } = useRootSetting();


  function init() {
    const outlineElement = document.getElementById('outline')
    const previewElement = document.getElementById('preview')
    vditorPreviewRef.value = Vditor.preview(previewElement, props.value, {
      markdown: {
        toc: true,
      },
      speech: {
        enable: true,
      },
      anchor: 1,
      after: () => {
        if (window.innerWidth <= 768) {
          return
        }

        Vditor.outlineRender(previewElement, outlineElement)
        if (outlineElement.innerText.trim() !== '') {
          outlineElement.style.display = 'block'
        }
      },
      lazyLoadImage: `http://localhost:3000/static/vditor/dist/images/img-loading.svg`, renderers: {
        renderHeading: (node, entering) => {
          const id = Lute.GetHeadingID(node)
          if (entering) {
            return [`<h${node.__internal_object__.HeadingLevel} id="${id}" class="vditor__heading"><span class="prefix"></span><span>`, Lute.WalkContinue]
          } else {
            return [`</span><a id="vditorAnchor-${id}" class="vditor-anchor" href="#${id}"><svg viewBox="0 0 16 16" version="1.1" width="16" height="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h${node.__internal_object__.HeadingLevel}>`, Lute.WalkContinue]
          }
        },
      },

    });
  }
  watch(
    () => getDarkMode.value,
    (val) => {
      Vditor.setContentTheme(getTheme(val, 'content'));
      Vditor.setCodeTheme(getTheme(val, 'code'));
      init();
    },
  );

  watch(
    () => props.value,
    (v, oldValue) => {
      v !== oldValue && init();
    },
  );

  function destroy() {
    const vditorInstance = unref(vditorPreviewRef);
    if (!vditorInstance) return;
    try {
      vditorInstance?.destroy?.();
    } catch (error) {
      //
    }
    vditorPreviewRef.value = null;
  }

  onMountedOrActivated(init);

  onBeforeUnmount(destroy);
  onDeactivated(destroy);
</script>

渲染图片

image

截屏或录像

版本信息

  • 版本:3.9.6
  • 操作系统:win10
  • 浏览器:Chrome

其他信息

@Vanessa219
Copy link
Owner

参照本地运行的 http://127.0.0.1:9000/render.html 界面,是可以点击滚动的。

@grandsong
Copy link

我也遇到了同样的问题。
我是参照 demo 的代码,调用了一个选项参数最简单的实例。
其它功能都很正常,只有大纲点击无效。

@grandsong
Copy link

grandsong commented Jan 17, 2024

我查看了一下源代码。

在文件 'src\ts\markdown\outlineRender.ts' 中,找到小标题元素 idElement 后,要滚动到它。

这个工作,按理说,用一行代码即可实现:

idElement.scrollIntoView()

不知为何(也许是为了兼容古老的浏览器?),源代码中的实现非常复杂。

可能就是在其中发生了错误。

相关部分如下。

if (target.classList.contains("vditor-outline__action")) {
  ...
} else if (target.getAttribute("data-target-id")) {
    event.preventDefault();
    event.stopPropagation();
    const idElement = document.getElementById(target.getAttribute("data-target-id"));
    if (!idElement) {
        return;
    }
    if (vditor) {
        if (vditor.options.height === "auto") {
            let windowScrollY = idElement.offsetTop + vditor.element.offsetTop;
            if (!vditor.options.toolbarConfig.pin) {
                windowScrollY += vditor.toolbar.element.offsetHeight;
            }
            window.scrollTo(window.scrollX, windowScrollY);
        } else {
            if (vditor.element.offsetTop < window.scrollY) {
                window.scrollTo(window.scrollX, vditor.element.offsetTop);
            }
            if (vditor.preview.element.contains(contentElement)) {
                contentElement.parentElement.scrollTop = idElement.offsetTop;
            } else {
                contentElement.scrollTop = idElement.offsetTop;
            }
        }
    } else {
        window.scrollTo(window.scrollX, idElement.offsetTop);
    }
    break;
}

@grandsong
Copy link

我打了一个外部的补丁,成功实现了预期的功能。

我采用了 vue ,在编辑器的元素上,监听事件 @pointerdown="clickEditor"

clickEditor(ev: PointerEvent) {
  const el = ev.target as HTMLElement
  const el_outline_item = findThisOrAncestor(el, '[data-target-id]')
  // warn('el_outline_item', el_outline_item)
  if (el_outline_item) {
    const outline_item_target_id = el_outline_item.getAttribute('data-target-id')!
    const el_target = document.getElementById(outline_item_target_id)!
    el_target.scrollIntoView()
  }
},
/**
 * 从`el`开始向上(祖先元素)遍历,返回匹配`selector`的第一个元素
 */
export function findThisOrAncestor(el: HTMLElement | null, selector: string) {
  while (el) {
    if (el.matches(selector)) {
      return el
    }
    else {
      el = el.parentElement
    }
  }
  return null
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants