Skip to content

Commit 2cd73e3

Browse files
author
李颜余
committed
fix: 修复微信公众号同步内容因未进行富文本预处理导致的样式丢失问题
1 parent ecb9267 commit 2cd73e3

File tree

4 files changed

+100
-59
lines changed

4 files changed

+100
-59
lines changed

src/components/CodemirrorEditor/EditorHeader/PostInfo.vue

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
<script setup lang="ts">
22
import type { Post, PostAccount } from '@/types'
3+
import { useCopyContent } from '@/composables/useCopyContent'
34
import { useStore } from '@/stores'
45
import { Check, Info } from 'lucide-vue-next'
56
import { CheckboxIndicator, CheckboxRoot, Primitive } from 'radix-vue'
67
78
const store = useStore()
8-
const { output, editor } = storeToRefs(store)
9+
const { editor } = storeToRefs(store)
910
1011
const dialogVisible = ref(false)
1112
const extensionInstalled = ref(false)
1213
const allAccounts = ref<PostAccount[]>([])
1314
const postTaskDialogVisible = ref(false)
15+
const { handleCopyContent } = useCopyContent()
1416
1517
const form = ref<Post>({
1618
title: ``,
@@ -37,14 +39,26 @@ async function prePost() {
3739
accounts: [],
3840
}
3941
const accounts = allAccounts.value.filter(a => ![`ipfs`].includes(a.type))
42+
43+
/**
44+
* 获取标题、内容、封面,描述
45+
* 内容为 #output 中渲染的 html
46+
* 标题为 #output 中第一个 h1-h6 的内容
47+
* 封面为 #output 中第一个 img 的 src
48+
* 描述为 #output 中第一个 p 的内容
49+
*/
4050
try {
51+
// 调用父组件的 handleCopyContent 方法,获取渲染后的内容,并赋值给 content
52+
const content = await handleCopyContent(`html`, false)
53+
4154
auto = {
4255
thumb: document.querySelector<HTMLImageElement>(`#output img`)?.src ?? ``,
4356
title: [1, 2, 3, 4, 5, 6]
4457
.map(h => document.querySelector(`#output h${h}`)!)
45-
.find(h => h)?.textContent ?? ``,
58+
.find(h => h)
59+
?.textContent ?? ``,
4660
desc: document.querySelector(`#output p`)?.textContent?.trim() ?? ``,
47-
content: output.value,
61+
content,
4862
markdown: editor.value?.getValue() ?? ``,
4963
accounts,
5064
}

src/components/CodemirrorEditor/EditorHeader/index.vue

+5-53
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import { Toaster } from '@/components/ui/sonner'
3+
import { useCopyContent } from '@/composables/useCopyContent'
34
import {
45
altSign,
56
ctrlKey,
@@ -10,8 +11,6 @@ import { useStore } from '@/stores'
1011
import { addPrefix, processClipboardContent } from '@/utils'
1112
import { ChevronDownIcon, Moon, PanelLeftClose, PanelLeftOpen, Settings, Sun } from 'lucide-vue-next'
1213
13-
const emit = defineEmits([`addFormat`, `formatContent`, `startCopy`, `endCopy`])
14-
1514
const formatItems = [
1615
{
1716
label: `加粗`,
@@ -47,58 +46,11 @@ const formatItems = [
4746
4847
const store = useStore()
4948
50-
const { isDark, isCiteStatus, isCountStatus, output, primaryColor, isOpenPostSlider } = storeToRefs(store)
51-
52-
const { toggleDark, editorRefresh, citeStatusChanged, countStatusChanged } = store
53-
54-
const copyMode = useStorage(addPrefix(`copyMode`), `txt`)
55-
const source = ref(``)
56-
const { copy: copyContent } = useClipboard({ source })
49+
const { isDark, isCiteStatus, isCountStatus, isOpenPostSlider } = storeToRefs(store)
5750
58-
// 复制到微信公众号
59-
function copy() {
60-
emit(`startCopy`)
61-
setTimeout(() => {
62-
// 如果是深色模式,复制之前需要先切换到白天模式
63-
const isBeforeDark = isDark.value
64-
if (isBeforeDark) {
65-
toggleDark()
66-
}
51+
const { toggleDark, citeStatusChanged, countStatusChanged } = store
6752
68-
nextTick(async () => {
69-
processClipboardContent(primaryColor.value)
70-
const clipboardDiv = document.getElementById(`output`)!
71-
clipboardDiv.focus()
72-
window.getSelection()!.removeAllRanges()
73-
const temp = clipboardDiv.innerHTML
74-
if (copyMode.value === `txt`) {
75-
const range = document.createRange()
76-
range.setStartBefore(clipboardDiv.firstChild!)
77-
range.setEndAfter(clipboardDiv.lastChild!)
78-
window.getSelection()!.addRange(range)
79-
document.execCommand(`copy`)
80-
window.getSelection()!.removeAllRanges()
81-
}
82-
clipboardDiv.innerHTML = output.value
83-
if (isBeforeDark) {
84-
nextTick(() => toggleDark())
85-
}
86-
if (copyMode.value === `html`) {
87-
await copyContent(temp)
88-
}
89-
90-
// 输出提示
91-
toast.success(
92-
copyMode.value === `html`
93-
? `已复制 HTML 源码,请进行下一步操作。`
94-
: `已复制渲染后的内容到剪贴板,可直接到公众号后台粘贴。`,
95-
)
96-
97-
editorRefresh()
98-
emit(`endCopy`)
99-
})
100-
}, 350)
101-
}
53+
const { copyMode, handleCopyContent } = useCopyContent()
10254
</script>
10355

10456
<template>
@@ -161,7 +113,7 @@ function copy() {
161113
</Button>
162114

163115
<div class="space-x-1 bg-background text-background-foreground mx-2 flex items-center border rounded-md">
164-
<Button variant="ghost" class="shadow-none" @click="copy">
116+
<Button variant="ghost" class="shadow-none" @click="() => handleCopyContent(copyMode)">
165117
复制
166118
</Button>
167119
<Separator orientation="vertical" class="h-5" />

src/composables/useCopyContent.ts

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { useStore } from '@/stores'
2+
import { addPrefix, processClipboardContent } from '@/utils'
3+
import { useClipboard } from '@vueuse/core'
4+
5+
export function useCopyContent() {
6+
const store = useStore()
7+
const { isDark, output, primaryColor } = storeToRefs(store)
8+
const { toggleDark, editorRefresh } = store
9+
10+
const copyMode = useStorage(addPrefix(`copyMode`), `txt`)
11+
const source = ref(`")`)
12+
const { copy } = useClipboard({ source })
13+
14+
// 复制内容
15+
async function handleCopyContent(mode = `html`, showTips = true) {
16+
let clipboardContent = ``
17+
18+
await new Promise(resolve => setTimeout(resolve, 350))
19+
20+
// 如果是深色模式,复制之前需要先切换到白天模式
21+
const isBeforeDark = isDark.value
22+
if (isBeforeDark) {
23+
toggleDark()
24+
}
25+
26+
await nextTick()
27+
processClipboardContent(primaryColor.value)
28+
const clipboardDiv = document.getElementById(`output`)!
29+
clipboardDiv.focus()
30+
window.getSelection()!.removeAllRanges()
31+
const temp = clipboardDiv.innerHTML
32+
33+
try {
34+
// 复制模式是 txt(微信公众号格式),使用 document.createRange() 创建 Range 对象并复制内容
35+
if (mode === `txt`) {
36+
const range = document.createRange()
37+
range.setStartBefore(clipboardDiv.firstChild!)
38+
range.setEndAfter(clipboardDiv.lastChild!)
39+
window.getSelection()!.addRange(range)
40+
document.execCommand(`copy`)
41+
window.getSelection()!.removeAllRanges()
42+
clipboardContent = temp
43+
}
44+
clipboardDiv.innerHTML = output.value
45+
46+
// html 模式,使用 @vueuse 的 Clipboard 模块复制内容
47+
if (mode === `html`) {
48+
await copy(temp)
49+
clipboardContent = temp
50+
}
51+
52+
// 输出提示
53+
showTips && toast.success(
54+
mode === `html`
55+
? `已复制 HTML 源码,请进行下一步操作。`
56+
: `已复制渲染后的内容到剪贴板,可直接到公众号后台粘贴。`,
57+
)
58+
}
59+
finally {
60+
if (isBeforeDark) {
61+
await nextTick()
62+
toggleDark()
63+
}
64+
editorRefresh()
65+
}
66+
67+
return clipboardContent
68+
}
69+
70+
return {
71+
copyMode,
72+
handleCopyContent,
73+
}
74+
}

src/stores/index.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export const useStore = defineStore(`store`, () => {
9090

9191
const isOpenPostSlider = useStorage(addPrefix(`is_open_post_slider`), false)
9292
// 内容列表
93+
// 使用 @vueuse 的 Storage 模块存储本地数据,存储格式为 { title: string, content: string }[]
9394
const posts = useStorage(addPrefix(`posts`), [
9495
{
9596
title: `内容1`,
@@ -153,7 +154,7 @@ export const useStore = defineStore(`store`, () => {
153154
}
154155
}
155156

156-
// 自义定 CSS 编辑器
157+
// 自定义 CSS 编辑器
157158
const cssEditor = ref<CodeMirror.EditorFromTextArea | null>(null)
158159
const setCssEditorValue = (content: string) => {
159160
cssEditor.value!.setValue(content)
@@ -249,7 +250,7 @@ export const useStore = defineStore(`store`, () => {
249250
let outputTemp = marked.parse(markdownContent) as string
250251

251252
// 提取标题
252-
const div = document.createElement('div')
253+
const div = document.createElement(`div`)
253254
div.innerHTML = outputTemp
254255
const list = div.querySelectorAll<HTMLElement>(`[data-heading]`)
255256

@@ -260,7 +261,7 @@ export const useStore = defineStore(`store`, () => {
260261
titleList.value.push({
261262
url: `#${i}`,
262263
title: `${item.innerText}`,
263-
level: Number(item.tagName.slice(1))
264+
level: Number(item.tagName.slice(1)),
264265
})
265266
i++
266267
}

0 commit comments

Comments
 (0)