Closed de1ck closed 2 years ago
我这边改进了一下代码,加了个线程锁,避免覆盖问题
<template>
<div ref="viewerRef" @click.prevent="clickView" />
</template>
<script lang="ts" setup>
import {
ref, onMounted, defineProps, withDefaults, watch,
} from 'vue';
import Vditor from 'vditor';
import 'vditor/dist/index.css';
import '@/style/vditor.scss';
import { VDITOR_CDN } from '@/utils/consts';
const props = withDefaults(defineProps<{
mode?: 'dark' | 'light',
text?: string;
after?(): void;
}>(), {
mode: 'light',
});
const viewerRef = ref();
// 是否开始初始化标志
let initial = false;
// 是否有后续内容改动标志 防止一个事件环节内重复preview => 导致后面的数据被前面的覆盖
let atferPool = false;
function init() {
// 在初始化中,设置标志
if (initial) {
atferPool = true;
return;
}
// 开始初始化
initial = true;
const previewElement = viewerRef.value;
Vditor.preview(previewElement!, props.text ?? '', {
mode: 'light',
cdn: VDITOR_CDN,
theme: {
current: 'light',
path: `${VDITOR_CDN}/dist/css/content-theme`,
},
// markdown: {
// toc: true,
// listStyle: true,
// },
// anchor: 1,
async after() {
await props.after?.();
// 初始化结束
initial = false;
// 发现有后续改动,重新初始化
if (atferPool) {
atferPool = false;
init();
}
},
});
}
function clickView(event) {
if (event.target?.tagName === 'A' && event.target?.href) {
// 对捕获到的 a 标签进行处理,需要先禁止它的跳转行为
window.open(event.target.href, '_blank');
}
}
onMounted(() => {
init();
watch(() => props.text, () => {
init();
});
});
</script>
previewRender 方法本身支持 await 的,没太明白。如果是代码修改的话,欢迎直接 PR。
previewRender 方法本身支持 await 的,没太明白。如果是代码修改的话,欢迎直接 PR。
当连续异步更新数据后,然后多次连续调用previewRender,可能会导致后面的数据,被前面的数据覆盖。
比如:初始数据为空,调用Vditor.preview,然后异步更新数据 'abc', 接着调用Vditor.preview, 最后渲染的数据还是空
单纯使用 await 不能避免这种问题。需要代码里面规避这种情况。
<template>
<div>
<div ref="viewerRef"></div>
<el-input v-model="text"></el-input>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, watch } from 'vue';
import Vditor from 'vditor';
import { VDITOR_CDN } from '@/utils/consts';
// const draftContent = localStorage.getItem('vditor-test');
const text = ref('');
const viewerRef = ref();
function init() {
const previewElement = viewerRef.value;
const v = text.value;
Vditor.preview(previewElement!, text.value ?? '', {
mode: 'light',
cdn: VDITOR_CDN,
theme: {
current: 'light',
path: `${VDITOR_CDN}/dist/css/content-theme`,
},
// markdown: {
// toc: true,
// listStyle: true,
// },
// anchor: 1,
async after() {
console.log('after', v);
},
});
}
onMounted(() => {
init();
setTimeout(() => {
text.value = '123';
});
});
watch(text, () => {
init();
});
</script>
外部多次调用的时候需要进行 await
连续 previewRender 有概率会导致后面赋值的 text,被前面的覆盖
previewRender => md2Html 需要异步加载,所以首次渲染可能没有第二次快