chore(config): 添加项目配置文件和隐私协议
- 添加 .editorconfig 文件统一代码风格 - 添加 .env.development 和 .env.example 环境配置文件 - 添加 .eslintignore 和 .eslintrc.js 代码检查配置 - 添加 .gitignore 版本控制忽略文件配置 - 添加 .prettierignore 格式化忽略配置 - 添加隐私协议HTML文件 - 添加API密钥管理组件基础结构
This commit is contained in:
93
src/components/ByteMdViewer/index.vue
Normal file
93
src/components/ByteMdViewer/index.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<!-- markdown 解析 -->
|
||||
<template>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<div
|
||||
ref="rootRef"
|
||||
v-html="content"
|
||||
class="markdown-body"
|
||||
@click="handleClick"
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
||||
import type { BytemdPlugin } from 'bytemd';
|
||||
import { getProcessor } from 'bytemd';
|
||||
|
||||
const props = defineProps<{
|
||||
value: string;
|
||||
plugins?: BytemdPlugin[];
|
||||
sanitize?: (schema: any) => any;
|
||||
}>();
|
||||
|
||||
const rootRef = ref<HTMLElement | null>(null);
|
||||
const content = ref<any | null>(null);
|
||||
const cbs = ref<(void | (() => void))[]>([]);
|
||||
|
||||
const on = () => {
|
||||
if (props.plugins && rootRef.value && content.value) {
|
||||
cbs.value = props.plugins.map(({ viewerEffect }) => {
|
||||
return (
|
||||
viewerEffect &&
|
||||
viewerEffect({
|
||||
markdownBody: rootRef.value as HTMLElement,
|
||||
file: content.value
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const off = () => {
|
||||
if (cbs.value) {
|
||||
cbs.value.forEach((cb) => cb && cb());
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = (e: MouseEvent) => {
|
||||
const $ = e.target as HTMLElement;
|
||||
if ($.tagName !== 'A') {
|
||||
return;
|
||||
}
|
||||
|
||||
const href = $.getAttribute('href');
|
||||
if (!href || !href.startsWith('#')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dest = rootRef.value?.querySelector('#user-content-' + href.slice(1));
|
||||
if (dest) {
|
||||
dest.scrollIntoView();
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
[() => props.value, () => props.plugins, () => props.sanitize],
|
||||
() => {
|
||||
try {
|
||||
content.value = getProcessor({
|
||||
plugins: props.plugins,
|
||||
sanitize: props.sanitize
|
||||
}).processSync(props.value);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
off();
|
||||
nextTick(() => {
|
||||
on();
|
||||
});
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
on();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
off();
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user