refactor(front): 优化状态管理和组件逻辑,简化GlobalDrawer和Tiptap组件的实现

This commit is contained in:
keven
2025-07-19 22:29:48 +08:00
parent e62f329d53
commit cf2d81bf9a
5 changed files with 69 additions and 80 deletions

View File

@@ -1,19 +1,19 @@
<!-- app.vue -->
<script setup lang="ts">
import { defineRule } from 'vee-validate';
import { all } from '@vee-validate/rules';
import { defineRule } from 'vee-validate'
import { all } from '@vee-validate/rules'
Object.entries(all).forEach(([name, rule]) => {
defineRule(name, rule);
});
defineRule(name, rule)
})
// @ts-check
const { $serwist } = useNuxtApp();
$serwist?.addEventListener("installed", () => {
console.log("Serwist installed!");
});
void $serwist?.register({ immediate: true });
// const { $serwist } = useNuxtApp();
// $serwist?.addEventListener("installed", () => {
// console.log("Serwist installed!");
// });
// void $serwist?.register({ immediate: true });
</script>
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>

View File

@@ -3,24 +3,25 @@ import { Drawer, DrawerContent } from '@/components/ui/drawer'
import { createVNode } from 'vue'
import useStore from '@/composables/useStore'
const store = useStore('drawer')
const drawer = computed(() => store?._get('drawer'))
const currentDrawer = computed(() => drawer?.value?.[drawer?.value?.length - 1])
const store = useStore()
const currentDrawer = computed(() => store.drawer?.[store.drawer?.length - 1])
const render = computed<() => Component>(() => currentDrawer?.value?.render)
const hide = computed<() => void>(() => currentDrawer?.value?.onClose)
const render = computed(() => currentDrawer?.value?.render)
const hide = computed(() => currentDrawer?.value?.onClose)
const Children = () =>
createVNode(render.value, {
hide: hide?.value,
})
render.value
? createVNode(render.value, {
hide: hide?.value,
})
: null
</script>
<template>
<Drawer
:open="!!drawer?.[drawer?.length - 1]"
:open="!!store.drawer?.[store.drawer?.length - 1]"
@update:open="
(open) => {
if (!open && drawer?.length > 0) {
if (!open && store?.drawer?.length && hide) {
hide()
}
}

View File

@@ -1,40 +1,48 @@
<script setup lang="ts">
import { Editor, EditorContent } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'
import { Markdown } from 'tiptap-markdown';
import { Markdown } from 'tiptap-markdown'
import Placeholder from '@tiptap/extension-placeholder'
const props = defineProps<{
modelValue: string
placeholder?: string
modelValue?: string
placeholder?: string
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: string): void
(e: 'update:modelValue', value: string): void
}>()
const editor = ref<Editor | undefined>(undefined)
onMounted(() => {
editor.value = new Editor({
content: props.modelValue,
extensions: [StarterKit, Markdown.configure({
transformPastedText: true,
transformCopiedText: true
}), Placeholder.configure({
placeholder: props.placeholder ?? ''
})],
onUpdate: () => {
// HTML
emit('update:modelValue', editor.value?.storage?.markdown?.getMarkdown() ?? '')
editor.value = new Editor({
content: props.modelValue,
extensions: [
StarterKit,
Markdown.configure({
transformPastedText: true,
transformCopiedText: true,
}),
Placeholder.configure({
placeholder: props.placeholder ?? '',
}),
// CommandsPlugin,
],
onUpdate: () => {
emit('update:modelValue', editor.value?.storage?.markdown?.getMarkdown() ?? '')
},
})
})
watch(
() => props.modelValue,
(value) => {
if (value !== editor.value?.storage?.markdown?.getMarkdown()) {
editor.value?.commands.setContent(value ?? '')
}
}
})
})
watch(() => props.modelValue, (value) => {
editor.value?.commands.setContent(value)
})
)
onUnmounted(() => {
editor.value?.destroy()
editor.value?.destroy()
})
</script>
<template>
<editor-content :editor="editor" class="prose prose-sm bg-white/50 rounded-md p-2 [&>*]:outline-none prose-p:my-1" />
</template>
<editor-content :editor="editor" class="prose prose-sm bg-white/50 rounded-md p-2 [&>*]:outline-none prose-p:my-1" />
</template>

View File

@@ -1,34 +1,17 @@
import { defineStore } from 'pinia'
import { cloneDeep, get, isEmpty, isUndefined, set, isString } from 'lodash-es'
type StoreType = Record<string, any>
type renderComponent = Component | ((props: { hide: () => null }) => VNode)
const initState: StoreType = {}
// 做了一点小小的改进可以传入key会自动初始化如果不初始化的话容易导致不存在值而丢失响应式
const useStore = (key?: string) => {
const store = defineStore('store', {
state: () => ({
...initState,
}),
actions: {
_get(path?: string) {
if (isEmpty(path) || isUndefined(path)) {
return this.$state
}
return get(this.$state, path)
},
_set(path: string, value: any) {
const newState = cloneDeep(this.$state)
set(newState, path, value)
this.$patch(newState)
},
},
})()
if (!isEmpty(key) && isString(key) && isUndefined(store?._get(key))) {
// console.log('reset', key, store?._get(key))
store?._set(key, null)
}
return store
type StoreProps = {
tiptapCommandsView?: any
drawer?: { render?: renderComponent; onClose: (data?: any) => void; key: string }[]
}
const useStore = defineStore<any, StoreProps>('store', () => {
return {
tiptapCommandsView: null,
drawer: [],
}
})
export default useStore

View File

@@ -7,14 +7,11 @@ const showDrawer = (props: DrawerProps) => {
return new Promise<void>((res) => {
const { render } = props || {}
const onClose = (data?: any) => {
store._set(
'drawer',
(store._get('drawer')?.value ?? [])?.filter((item: any) => item.key !== key)
)
store.drawer = (store.drawer ?? [])?.filter((item: any) => item.key !== key)
res(data)
}
const store = useStore()
store._set('drawer', [...(store._get('drawer')?.value || []), { render, onClose, key }])
store.drawer = [...(store.drawer || []), { render, onClose, key }]
})
}