feat:用shadow dom隔离html样式
This commit is contained in:
1
apps/web-antd/src/components/shadow-container/index.ts
Normal file
1
apps/web-antd/src/components/shadow-container/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export { default as ShadowContainer } from './shadow-container.vue';
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
// 可以传递样式字符串来自定义内部样式
|
||||||
|
styles: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const shadowHost = ref(null);
|
||||||
|
|
||||||
|
const initShadow = () => {
|
||||||
|
if (shadowHost.value && !shadowHost.value.shadowRoot) {
|
||||||
|
const shadowRoot = shadowHost.value.attachShadow({ mode: 'open' });
|
||||||
|
|
||||||
|
shadowRoot.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
all: initial;
|
||||||
|
display: block;
|
||||||
|
contain: content;
|
||||||
|
|
||||||
|
${props.styles}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<div class="shadow-content">${props.content}</div>
|
||||||
|
`;
|
||||||
|
} else if (shadowHost.value && shadowHost.value.shadowRoot) {
|
||||||
|
shadowHost.value.shadowRoot.querySelector('.shadow-content').innerHTML =
|
||||||
|
props.content;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(initShadow);
|
||||||
|
watch(() => props.content, initShadow);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div ref="shadowHost"></div>
|
||||||
|
</template>
|
||||||
@@ -10,6 +10,7 @@ import dayjs from 'dayjs';
|
|||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
|
|
||||||
import { deleteComment } from '#/api/license/comment';
|
import { deleteComment } from '#/api/license/comment';
|
||||||
|
import { ShadowContainer } from '#/components/shadow-container';
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import CreateComment from './create-comment.vue';
|
import CreateComment from './create-comment.vue';
|
||||||
@@ -104,7 +105,11 @@ const formatContent = computed(() => {
|
|||||||
<template #content>
|
<template #content>
|
||||||
<div>
|
<div>
|
||||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
<span class="rich-text-comment-content" v-html="formatContent"></span>
|
<!-- <span class="rich-text-comment-content" v-html="formatContent"></span> -->
|
||||||
|
<ShadowContainer
|
||||||
|
:content="formatContent"
|
||||||
|
styles="font-family: Helvetica,Arial,sans-serif; font-size:16px;"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -194,6 +199,11 @@ const formatContent = computed(() => {
|
|||||||
</template>
|
</template>
|
||||||
<style>
|
<style>
|
||||||
:where(.css-dev-only-do-not-override-14589v).ant-comment .ant-comment-actions {
|
:where(.css-dev-only-do-not-override-14589v).ant-comment .ant-comment-actions {
|
||||||
margin-top: 16px;
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.css-dev-only-do-not-override-14589v).ant-comment
|
||||||
|
.ant-comment-content-author {
|
||||||
|
margin-bottom: -2px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -149,12 +149,13 @@ export function useProjectGridColumns(): VxeTableGridOptions<ProgressApi.Progres
|
|||||||
{
|
{
|
||||||
field: 'content',
|
field: 'content',
|
||||||
title: '进展记录',
|
title: '进展记录',
|
||||||
type: 'html',
|
// type: 'html',
|
||||||
className: 'rich-text-comment-content-table',
|
// className: 'rich-text-comment-content-table',
|
||||||
showOverflow: false,
|
showOverflow: false,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
// headerAlign: 'center',
|
// headerAlign: 'center',
|
||||||
minWidth: 600,
|
minWidth: 600,
|
||||||
|
slots: { default: 'contentDefault' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'updateTime',
|
field: 'updateTime',
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import dayjs from 'dayjs';
|
|||||||
|
|
||||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||||
import { exportProject, getProgressByProjectPage } from '#/api/report/progress';
|
import { exportProject, getProgressByProjectPage } from '#/api/report/progress';
|
||||||
|
import { ShadowContainer } from '#/components/shadow-container';
|
||||||
|
|
||||||
import { useProjectGridColumns, useProjectGridFormSchema } from '../data';
|
import { useProjectGridColumns, useProjectGridFormSchema } from '../data';
|
||||||
|
|
||||||
@@ -149,5 +150,15 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Grid table-title="项目进展" />
|
<Grid table-title="项目进展">
|
||||||
|
<template #contentDefault="{ row }">
|
||||||
|
<!-- <div v-html="row.content" style="white-space: pre-wrap"></div> -->
|
||||||
|
<ShadowContainer
|
||||||
|
:content="row.content"
|
||||||
|
styles="font-family: -apple-system, blinkmacsystemfont, 'Segoe UI', roboto, 'Helvetica Neue',
|
||||||
|
arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
||||||
|
'Segoe UI Symbol', 'Noto Color Emoji';"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Grid>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user