diff --git a/README.md b/README.md index afc17c5..af7b93a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,9 @@ - - ## DDD领域驱动设计的微服务前端案例 > 持续开发中,及时拉取代码,文档还不够完善,先凑合看!!目前只是demo,代码还会进行大规模封装细化和改造! 搭建的一套**基于DDD领域驱动设计的微服务前端**,适用于大型企业,开发大型复杂且拓展灵活的前端应用的架构方案。 - 项目大致技术栈: - [DDD领域驱动设计](https://zh.wikipedia.org/zh-cn/%E9%A0%98%E5%9F%9F%E9%A9%85%E5%8B%95%E8%A8%AD%E8%A8%88) @@ -27,10 +24,127 @@ - [x] 基于DDD理念改造 - [x] 基于 vite-plugin-federation 拆分领域模块为联邦模块,实现微前端 -- [x] 基于Vue3+OOP+JSX改造项目代码,让项目更适合开发和维护 +- [x] 基于Vue3+OOP+JSX改造项目代码, - [ ] 领域模块实现 docker 自动化构建部署上线 - [ ] Deno集成GraphQL +## 代码风格 + +OOP面向对象 + TypeScript + JSX,让项目更适合开发和维护,获得更好更极致的编码体验。 + +```tsx +// 首页 页面 +import { Autobind, Component, Link, Mut, VueComponent } from 'vue3-oop' +import Header from '@/components/Header' + +interface ListItemType { + id: number + title: string +} + +@Component() +export default class Home extends VueComponent { + + @Mut() + count: number = 1 + + @Mut() + text: string = "Home props 传给 Header 的字符串" + + @Mut() + newList: ListItemType[] = [ + { id: 1, title: '新闻1' }, + { id: 2, title: '新闻2' }, + { id: 3, title: '新闻3' }, + ] + + @Link() H1?: HTMLDivElement + + @Autobind() + async addCount() { + this.count++ + this.text = "22222" + console.log(this.H1) + } + + render() { + return ( +
+

首页

+

count响应式变量(点我):{ this.count }

+
父到子 default 插槽
, + haveName: () =>
父到子 具名 插槽
, + item: (val) =>
  • { val.title }
  • + } } + list={ this.newList } + text={ this.text }> +
    +
    + ) + } +} +``` + +```tsx +// 头部组件 +import { Component, ComponentProps, Hook, useProps, VueComponent } from 'vue3-oop' +import { JSX } from "vue/jsx-runtime"; +import { VNodeChild } from "vue"; + +interface ListItemType { + id: number + title: string +} + +interface HeaderProps { + text?: string; + list: ListItemType[] + slots: { + default: () => JSX.Element; + haveName: () => JSX.Element; + item: (val: ListItemType) => VNodeChild; + } +} + +@Component() +export default class Header extends VueComponent { + + // required 的 true or false 需要和 类型中 text的? 对应 + static defaultProps: ComponentProps = { + text: { default: '默认数值', required: true }, + list: { default: () => [] } + }; + + @Hook('Mounted') + mounted() { + console.log("this: ", this); + console.log('Header 组件的 mounted 生命周期...') + } + + render() { + const { text, list } = useProps(); + return ( +
    + 头部组件 +

    { text }

    + { this.context.slots.default?.() } + { this.context.slots.haveName?.() } +
      + { + list.map( + item => + this.context.slots.item?.(item) + ) + } +
    +
    + ) + } +} +``` + ## 文件夹结构 **根目录:** @@ -93,19 +207,16 @@ src/ └── index.html # 主HTML文件 ``` - -## 问 & 答 +## 问 & 答 **问: 为什么vue项目要抛弃SFC写法而尝试jsx/tsx方式来编码?** 答:https://juejin.cn/post/6911175470255964174 - **问:不会 vue3 jsx 语法,怎么办?** 答:https://juejin.cn/post/7141674726434439176 - **问:vue3 jsx defineComponent 语法,实际项目中 setup 代码太长,怎么办?** 答:使用组合式函数 (Composables) @@ -114,33 +225,33 @@ src/ ```jsx // composables/useUserData.js -import { ref, onMounted } from 'vue' +import {ref, onMounted} from 'vue' import api from '@/api' export function useUserData(userId) { - const user = ref(null) - const loading = ref(false) - const error = ref(null) + const user = ref(null) + const loading = ref(false) + const error = ref(null) - const fetchUser = async () => { - loading.value = true - try { - user.value = await api.getUser(userId) - } catch (err) { - error.value = err.message - } finally { - loading.value = false + const fetchUser = async () => { + loading.value = true + try { + user.value = await api.getUser(userId) + } catch (err) { + error.value = err.message + } finally { + loading.value = false + } } - } - onMounted(fetchUser) + onMounted(fetchUser) - return { - user, - loading, - error, - refetch: fetchUser - } + return { + user, + loading, + error, + refetch: fetchUser + } } ``` @@ -148,34 +259,34 @@ export function useUserData(userId) { ```jsx // UserProfile.jsx -import { defineComponent } from 'vue' -import { useUserData } from '@/composables/useUserData' +import {defineComponent} from 'vue' +import {useUserData} from '@/composables/useUserData' export default defineComponent({ - name: 'UserProfile', - - props: { - userId: { - type: String, - required: true + name: 'UserProfile', + + props: { + userId: { + type: String, + required: true + } + }, + + setup(props) { + const {user, loading, error, refetch} = useUserData(props.userId) + + return () => ( +
    + {loading.value &&
    Loading...
    } + {error.value &&
    Error: {error.value}
    } + {user.value && ( +
    +

    {user.value.name}

    +

    {user.value.email}

    +
    + )} +
    + ) } - }, - - setup(props) { - const { user, loading, error, refetch } = useUserData(props.userId) - - return () => ( -
    - {loading.value &&
    Loading...
    } - {error.value &&
    Error: {error.value}
    } - {user.value && ( -
    -

    {user.value.name}

    -

    {user.value.email}

    -
    - )} -
    - ) - } }) ``` \ No newline at end of file diff --git a/front-end/main-app/src/app/components/Header.tsx b/front-end/main-app/src/app/components/Header.tsx index 9f8504e..c865606 100644 --- a/front-end/main-app/src/app/components/Header.tsx +++ b/front-end/main-app/src/app/components/Header.tsx @@ -34,7 +34,6 @@ export default class Header extends VueComponent { render() { const { text, list } = useProps(); - return (
    头部组件 diff --git a/front-end/main-app/src/app/views/Home.tsx b/front-end/main-app/src/app/views/Home.tsx index 47bc300..6414056 100644 --- a/front-end/main-app/src/app/views/Home.tsx +++ b/front-end/main-app/src/app/views/Home.tsx @@ -1,7 +1,6 @@ import { Autobind, Component, Link, Mut, VueComponent } from 'vue3-oop' import Header from '@/components/Header' - interface ListItemType { id: number title: string @@ -45,7 +44,6 @@ export default class Home extends VueComponent { } } list={ this.newList } text={ this.text }> -
    )