Skip to content

fix: 修复微信公众号同步内容因未进行富文本预处理导致的样式丢失问题 #592

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/components/CodemirrorEditor/EditorHeader/PostInfo.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
<script setup lang="ts">
import type { Post, PostAccount } from '@/types'
import { useCopyContent } from '@/composables/useCopyContent'
import { useStore } from '@/stores'
import { Check, Info } from 'lucide-vue-next'
import { CheckboxIndicator, CheckboxRoot, Primitive } from 'radix-vue'

const store = useStore()
const { output, editor } = storeToRefs(store)
const { editor } = storeToRefs(store)

const dialogVisible = ref(false)
const extensionInstalled = ref(false)
const allAccounts = ref<PostAccount[]>([])
const postTaskDialogVisible = ref(false)
const { handleCopyContent } = useCopyContent()

const form = ref<Post>({
title: ``,
Expand All @@ -37,15 +39,26 @@ async function prePost() {
accounts: [],
}
const accounts = allAccounts.value.filter(a => ![`ipfs`].includes(a.type))

/**
* 获取标题、内容、封面,描述
* 内容为 #output 中渲染的 html
* 标题为 #output 中第一个 h1-h6 的内容
* 封面为 #output 中第一个 img 的 src
* 描述为 #output 中第一个 p 的内容
*/
try {
// 调用父组件的 handleCopyContent 方法,获取渲染后的内容,并赋值给 content
const content = await handleCopyContent(`html`, false)

auto = {
thumb: document.querySelector<HTMLImageElement>(`#output img`)?.src ?? ``,
title: [1, 2, 3, 4, 5, 6]
.map(h => document.querySelector(`#output h${h}`)!)
.find(h => h)
?.textContent ?? ``,
desc: document.querySelector(`#output p`)?.textContent?.trim() ?? ``,
content: output.value,
content,
markdown: editor.value?.getValue() ?? ``,
accounts,
}
Expand Down
63 changes: 7 additions & 56 deletions src/components/CodemirrorEditor/EditorHeader/index.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { Toaster } from '@/components/ui/sonner'
import { useCopyContent } from '@/composables/useCopyContent'
import {
altSign,
ctrlKey,
Expand All @@ -8,11 +9,8 @@ import {
} from '@/config'

import { useStore } from '@/stores'
import { addPrefix, processClipboardContent } from '@/utils'
import { ChevronDownIcon, Moon, PanelLeftClose, PanelLeftOpen, Settings, Sun } from 'lucide-vue-next'

const emit = defineEmits([`addFormat`, `formatContent`, `startCopy`, `endCopy`])

const formatItems = [
{
label: `加粗`,
Expand Down Expand Up @@ -48,58 +46,11 @@ const formatItems = [

const store = useStore()

const { isDark, isCiteStatus, isCountStatus, output, primaryColor, isOpenPostSlider } = storeToRefs(store)

const { toggleDark, editorRefresh, citeStatusChanged, countStatusChanged } = store

const copyMode = useStorage(addPrefix(`copyMode`), `txt`)
const source = ref(``)
const { copy: copyContent } = useClipboard({ source })

// 复制到微信公众号
function copy() {
emit(`startCopy`)
setTimeout(() => {
// 如果是深色模式,复制之前需要先切换到白天模式
const isBeforeDark = isDark.value
if (isBeforeDark) {
toggleDark()
}

nextTick(async () => {
processClipboardContent(primaryColor.value)
const clipboardDiv = document.getElementById(`output`)!
clipboardDiv.focus()
window.getSelection()!.removeAllRanges()
const temp = clipboardDiv.innerHTML
if (copyMode.value === `txt`) {
const range = document.createRange()
range.setStartBefore(clipboardDiv.firstChild!)
range.setEndAfter(clipboardDiv.lastChild!)
window.getSelection()!.addRange(range)
document.execCommand(`copy`)
window.getSelection()!.removeAllRanges()
}
clipboardDiv.innerHTML = output.value
if (isBeforeDark) {
nextTick(() => toggleDark())
}
if (copyMode.value === `html`) {
await copyContent(temp)
}

// 输出提示
toast.success(
copyMode.value === `html`
? `已复制 HTML 源码,请进行下一步操作。`
: `已复制渲染后的内容到剪贴板,可直接到公众号后台粘贴。`,
)

editorRefresh()
emit(`endCopy`)
})
}, 350)
}
const { isDark, isCiteStatus, isCountStatus, isOpenPostSlider } = storeToRefs(store)

const { toggleDark, citeStatusChanged, countStatusChanged } = store

const { copyMode, handleCopyContent } = useCopyContent()
</script>

<template>
Expand Down Expand Up @@ -168,7 +119,7 @@ function copy() {

<!-- 复制按钮组 -->
<div class="space-x-1 bg-background text-background-foreground mx-2 flex items-center border rounded-md">
<Button variant="ghost" class="shadow-none" @click="copy">
<Button variant="ghost" class="shadow-none" @click="() => handleCopyContent(copyMode)">
复制
</Button>
<Separator orientation="vertical" class="h-5" />
Expand Down
74 changes: 74 additions & 0 deletions src/composables/useCopyContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useStore } from '@/stores'
import { addPrefix, processClipboardContent } from '@/utils'
import { useClipboard } from '@vueuse/core'

export function useCopyContent() {
const store = useStore()
const { isDark, output, primaryColor } = storeToRefs(store)
const { toggleDark, editorRefresh } = store

const copyMode = useStorage(addPrefix(`copyMode`), `txt`)
const source = ref(`")`)
const { copy } = useClipboard({ source })

// 复制内容
async function handleCopyContent(mode = `html`, showTips = true) {
let clipboardContent = ``

await new Promise(resolve => setTimeout(resolve, 350))

// 如果是深色模式,复制之前需要先切换到白天模式
const isBeforeDark = isDark.value
if (isBeforeDark) {
toggleDark()
}

await nextTick()
processClipboardContent(primaryColor.value)
const clipboardDiv = document.getElementById(`output`)!
clipboardDiv.focus()
window.getSelection()!.removeAllRanges()
const temp = clipboardDiv.innerHTML

try {
// 复制模式是 txt(微信公众号格式),使用 document.createRange() 创建 Range 对象并复制内容
if (mode === `txt`) {
const range = document.createRange()
range.setStartBefore(clipboardDiv.firstChild!)
range.setEndAfter(clipboardDiv.lastChild!)
window.getSelection()!.addRange(range)
document.execCommand(`copy`)
window.getSelection()!.removeAllRanges()
clipboardContent = temp
}
clipboardDiv.innerHTML = output.value

// html 模式,使用 @vueuse 的 Clipboard 模块复制内容
if (mode === `html`) {
await copy(temp)
clipboardContent = temp
}

// 输出提示
showTips && toast.success(
mode === `html`
? `已复制 HTML 源码,请进行下一步操作。`
: `已复制渲染后的内容到剪贴板,可直接到公众号后台粘贴。`,
)
}
finally {
if (isBeforeDark) {
await nextTick()
toggleDark()
}
editorRefresh()
}

return clipboardContent
}

return {
copyMode,
handleCopyContent,
}
}
3 changes: 2 additions & 1 deletion src/stores/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export const useStore = defineStore(`store`, () => {

const isOpenPostSlider = useStorage(addPrefix(`is_open_post_slider`), false)
// 内容列表
// 使用 @vueuse 的 Storage 模块存储本地数据,存储格式为 { title: string, content: string }[]
const posts = useStorage(addPrefix(`posts`), [
{
title: `内容1`,
Expand Down Expand Up @@ -181,7 +182,7 @@ export const useStore = defineStore(`store`, () => {
}
}

// 自义定 CSS 编辑器
// 自定义 CSS 编辑器
const cssEditor = ref<CodeMirror.EditorFromTextArea | null>(null)
const setCssEditorValue = (content: string) => {
cssEditor.value!.setValue(content)
Expand Down