From 46e8f61a88ee038f3b49a75b84f2bb855a69a964 Mon Sep 17 00:00:00 2001 From: Meow Date: Thu, 25 Sep 2025 20:26:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=AE=98=E7=BD=91=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/website-next/.gitignore | 52 + packages/website-next/README.md | 166 ++ packages/website-next/components.json | 21 + packages/website-next/eslint.config.mjs | 16 + packages/website-next/index.d.ts | 461 +++++ packages/website-next/next.config.ts | 22 + packages/website-next/openInula/README.md | 4 + packages/website-next/openInula/index.html | 12 + packages/website-next/openInula/package.json | 28 + .../openInula/pnpm-workspace.yaml | 2 + .../openInula/src/components/HomePage.jsx | 32 + .../src/components/PlaygroundPage.jsx | 79 + packages/website-next/openInula/src/index.css | 3 + packages/website-next/openInula/src/index.jsx | 19 + .../website-next/openInula/src/lib/code.ts | 199 ++ .../website-next/openInula/vite.config.js | 58 + packages/website-next/package.json | 51 + packages/website-next/postcss.config.mjs | 7 + .../website-next/public/ContactUsPage/img.png | Bin 0 -> 32169 bytes .../public/ContactUsPage/logo.normal.png | Bin 0 -> 9719 bytes .../website-next/public/ContactUsPage/map.png | Bin 0 -> 84604 bytes packages/website-next/public/favicon.ico | Bin 0 -> 7412 bytes packages/website-next/public/file.svg | 1 + .../public/font/geist-v3-latin-regular.woff2 | Bin 0 -> 12512 bytes .../public/footerIcon.bilibili.png | Bin 0 -> 1053 bytes .../website-next/public/footerIcon.gitee.png | Bin 0 -> 1182 bytes .../website-next/public/footerIcon.qrcode.png | Bin 0 -> 504 bytes packages/website-next/public/globe.svg | 1 + packages/website-next/public/navlogo.png | Bin 0 -> 9731 bytes packages/website-next/public/navlogowhite.png | Bin 0 -> 9872 bytes packages/website-next/public/next.svg | 1 + packages/website-next/public/qrcode.inula.jpg | Bin 0 -> 8152 bytes packages/website-next/public/vercel.svg | 1 + packages/website-next/public/window.svg | 1 + .../website-next/src/app/api/core/page.mdx | 1804 +++++++++++++++++ .../website-next/src/app/api/intl/page.mdx | 899 ++++++++ .../website-next/src/app/api/inulax/page.mdx | 482 +++++ packages/website-next/src/app/api/layout.tsx | 66 + packages/website-next/src/app/api/page.mdx | 24 + .../website-next/src/app/api/request/page.mdx | 1302 ++++++++++++ .../website-next/src/app/api/router/page.mdx | 713 +++++++ .../website-next/src/app/blog/[slug]/page.tsx | 108 + .../src/app/blog/components/BlogCard.tsx | 57 + .../src/app/blog/components/BlogFilterBar.tsx | 55 + .../src/app/blog/components/BlogList.tsx | 27 + .../app/blog/components/BlogPagination.tsx | 31 + packages/website-next/src/app/blog/page.tsx | 138 ++ .../website-next/src/app/contact/page.tsx | 196 ++ .../contribute/components/Contributors.tsx | 123 ++ .../contribute/components/DocumentSidebar.tsx | 125 ++ .../website-next/src/app/contribute/page.tsx | 53 + .../src/app/docs/components/Dynamic/page.mdx | 63 + .../docs/components/ErrorBoundary/page.mdx | 54 + .../src/app/docs/components/Fragment/page.mdx | 68 + .../src/app/docs/components/Portal/page.mdx | 64 + .../src/app/docs/components/Suspense/page.mdx | 54 + .../app/docs/components/composition/page.mdx | 120 ++ .../src/app/docs/components/context/page.mdx | 90 + .../src/app/docs/components/props/page.mdx | 125 ++ .../docs/conventional/CodeOfConduct/page.mdx | 53 + .../conventional/ContributingGuide/page.mdx | 142 ++ .../src/app/docs/conventional/FAQ/page.mdx | 35 + .../app/docs/conventional/QuickStart/page.mdx | 94 + .../docs/conventional/ReleaseNotes/page.mdx | 24 + .../docs/conventional/SwitchingGuide/page.mdx | 180 ++ .../conventional/UserInstruction/figure.png | Bin 0 -> 155820 bytes .../conventional/UserInstruction/page.mdx | 745 +++++++ .../src/app/docs/introduction/page.mdx | 41 + packages/website-next/src/app/docs/layout.tsx | 233 +++ .../src/app/docs/lifecycle/cleanup/page.mdx | 59 + .../src/app/docs/lifecycle/mounting/page.mdx | 49 + .../app/docs/lifecycle/unmounting/page.mdx | 43 + packages/website-next/src/app/docs/page.mdx | 110 + .../src/app/docs/quick-start/page.mdx | 141 ++ .../src/app/docs/reactivity/computed/page.mdx | 79 + .../src/app/docs/reactivity/state/page.mdx | 293 +++ .../src/app/docs/reactivity/untrack/page.mdx | 124 ++ .../src/app/docs/reactivity/watch/page.mdx | 114 ++ .../docs/template-system/conditional/page.mdx | 208 ++ .../template-system/event-handling/page.mdx | 304 +++ .../template-system/list-rendering/page.mdx | 257 +++ packages/website-next/src/app/error.tsx | 16 + .../website-next/src/app/examples/page.tsx | 34 + packages/website-next/src/app/globals.css | 721 +++++++ .../src/app/information/LoadMoreSection.tsx | 45 + .../app/information/activity/[slug]/page.tsx | 48 + .../src/app/information/news/[slug]/page.tsx | 48 + .../website-next/src/app/information/page.tsx | 101 + packages/website-next/src/app/laws/page.tsx | 7 + packages/website-next/src/app/layout.tsx | 41 + packages/website-next/src/app/loading.tsx | 102 + packages/website-next/src/app/not-found.tsx | 28 + packages/website-next/src/app/page.tsx | 23 + .../src/app/playground/[slug]/page.tsx | 51 + .../app/playground/components/CodeCard.tsx | 29 + .../app/playground/components/CodeSection.tsx | 94 + .../components/PlaygroundContent.tsx | 89 + .../components/PlaygroundSidebar.tsx | 180 ++ .../playground/components/TeachContent.tsx | 126 ++ .../playground/components/tutorials/Basic.tsx | 64 + .../components/tutorials/Component.tsx | 90 + .../components/tutorials/Computed.tsx | 306 +++ .../components/tutorials/Conditional.tsx | 357 ++++ .../components/tutorials/Lifecycle.tsx | 257 +++ .../playground/components/tutorials/Lists.tsx | 392 ++++ .../playground/components/tutorials/State.tsx | 265 +++ .../playground/components/tutorials/Watch.tsx | 290 +++ .../components/tutorials/eventHandling.tsx | 159 ++ .../src/app/playground/data/playgroundData.ts | 75 + .../website-next/src/app/playground/page.tsx | 6 + .../website-next/src/app/privacy/page.tsx | 7 + .../src/app/project/[slug]/page.tsx | 226 +++ .../website-next/src/app/project/page.tsx | 179 ++ .../HomePage/ActivityArea/Activity.tsx | 161 ++ .../src/components/HomePage/ApiComparison.tsx | 87 + .../src/components/HomePage/FeatureCard.tsx | 24 + .../src/components/HomePage/Footer.tsx | 163 ++ .../HomePageButton/WhyOpenInulaButton.tsx | 16 + .../HomePageButton/WhyOpenInulaModal.tsx | 36 + .../src/components/HomePage/Main.tsx | 119 ++ .../src/components/HomePage/Nav.tsx | 142 ++ .../HomePage/NavComponents/CustomSearch.tsx | 18 + .../HomePage/NavComponents/DropdownMenu.tsx | 78 + .../HomePage/NavComponents/SearchBar.tsx | 49 + .../NavComponents/ThemeSwitch/ThemeScript.tsx | 27 + .../NavComponents/ThemeSwitch/ThemeToggle.tsx | 76 + .../HomePage/PerformanceComparison.tsx | 165 ++ .../src/components/MDXDetailPage.tsx | 29 + .../src/components/MarkdownPage.tsx | 65 + .../src/components/magicui/aurora-text.tsx | 43 + .../components/magicui/code-comparison.tsx | 156 ++ .../src/components/magicui/magic-card.tsx | 108 + .../src/components/magicui/meteors.tsx | 60 + packages/website-next/src/lib/utils.ts | 6 + packages/website-next/src/mdx-components.tsx | 14 + packages/website-next/tsconfig.json | 35 + 136 files changed, 17539 insertions(+) create mode 100644 packages/website-next/.gitignore create mode 100644 packages/website-next/README.md create mode 100644 packages/website-next/components.json create mode 100644 packages/website-next/eslint.config.mjs create mode 100644 packages/website-next/index.d.ts create mode 100644 packages/website-next/next.config.ts create mode 100644 packages/website-next/openInula/README.md create mode 100644 packages/website-next/openInula/index.html create mode 100644 packages/website-next/openInula/package.json create mode 100644 packages/website-next/openInula/pnpm-workspace.yaml create mode 100644 packages/website-next/openInula/src/components/HomePage.jsx create mode 100644 packages/website-next/openInula/src/components/PlaygroundPage.jsx create mode 100644 packages/website-next/openInula/src/index.css create mode 100644 packages/website-next/openInula/src/index.jsx create mode 100644 packages/website-next/openInula/src/lib/code.ts create mode 100644 packages/website-next/openInula/vite.config.js create mode 100644 packages/website-next/package.json create mode 100644 packages/website-next/postcss.config.mjs create mode 100644 packages/website-next/public/ContactUsPage/img.png create mode 100644 packages/website-next/public/ContactUsPage/logo.normal.png create mode 100644 packages/website-next/public/ContactUsPage/map.png create mode 100644 packages/website-next/public/favicon.ico create mode 100644 packages/website-next/public/file.svg create mode 100644 packages/website-next/public/font/geist-v3-latin-regular.woff2 create mode 100644 packages/website-next/public/footerIcon.bilibili.png create mode 100644 packages/website-next/public/footerIcon.gitee.png create mode 100644 packages/website-next/public/footerIcon.qrcode.png create mode 100644 packages/website-next/public/globe.svg create mode 100644 packages/website-next/public/navlogo.png create mode 100644 packages/website-next/public/navlogowhite.png create mode 100644 packages/website-next/public/next.svg create mode 100644 packages/website-next/public/qrcode.inula.jpg create mode 100644 packages/website-next/public/vercel.svg create mode 100644 packages/website-next/public/window.svg create mode 100644 packages/website-next/src/app/api/core/page.mdx create mode 100644 packages/website-next/src/app/api/intl/page.mdx create mode 100644 packages/website-next/src/app/api/inulax/page.mdx create mode 100644 packages/website-next/src/app/api/layout.tsx create mode 100644 packages/website-next/src/app/api/page.mdx create mode 100644 packages/website-next/src/app/api/request/page.mdx create mode 100644 packages/website-next/src/app/api/router/page.mdx create mode 100644 packages/website-next/src/app/blog/[slug]/page.tsx create mode 100644 packages/website-next/src/app/blog/components/BlogCard.tsx create mode 100644 packages/website-next/src/app/blog/components/BlogFilterBar.tsx create mode 100644 packages/website-next/src/app/blog/components/BlogList.tsx create mode 100644 packages/website-next/src/app/blog/components/BlogPagination.tsx create mode 100644 packages/website-next/src/app/blog/page.tsx create mode 100644 packages/website-next/src/app/contact/page.tsx create mode 100644 packages/website-next/src/app/contribute/components/Contributors.tsx create mode 100644 packages/website-next/src/app/contribute/components/DocumentSidebar.tsx create mode 100644 packages/website-next/src/app/contribute/page.tsx create mode 100644 packages/website-next/src/app/docs/components/Dynamic/page.mdx create mode 100644 packages/website-next/src/app/docs/components/ErrorBoundary/page.mdx create mode 100644 packages/website-next/src/app/docs/components/Fragment/page.mdx create mode 100644 packages/website-next/src/app/docs/components/Portal/page.mdx create mode 100644 packages/website-next/src/app/docs/components/Suspense/page.mdx create mode 100644 packages/website-next/src/app/docs/components/composition/page.mdx create mode 100644 packages/website-next/src/app/docs/components/context/page.mdx create mode 100644 packages/website-next/src/app/docs/components/props/page.mdx create mode 100644 packages/website-next/src/app/docs/conventional/CodeOfConduct/page.mdx create mode 100644 packages/website-next/src/app/docs/conventional/ContributingGuide/page.mdx create mode 100644 packages/website-next/src/app/docs/conventional/FAQ/page.mdx create mode 100644 packages/website-next/src/app/docs/conventional/QuickStart/page.mdx create mode 100644 packages/website-next/src/app/docs/conventional/ReleaseNotes/page.mdx create mode 100644 packages/website-next/src/app/docs/conventional/SwitchingGuide/page.mdx create mode 100644 packages/website-next/src/app/docs/conventional/UserInstruction/figure.png create mode 100644 packages/website-next/src/app/docs/conventional/UserInstruction/page.mdx create mode 100644 packages/website-next/src/app/docs/introduction/page.mdx create mode 100644 packages/website-next/src/app/docs/layout.tsx create mode 100644 packages/website-next/src/app/docs/lifecycle/cleanup/page.mdx create mode 100644 packages/website-next/src/app/docs/lifecycle/mounting/page.mdx create mode 100644 packages/website-next/src/app/docs/lifecycle/unmounting/page.mdx create mode 100644 packages/website-next/src/app/docs/page.mdx create mode 100644 packages/website-next/src/app/docs/quick-start/page.mdx create mode 100644 packages/website-next/src/app/docs/reactivity/computed/page.mdx create mode 100644 packages/website-next/src/app/docs/reactivity/state/page.mdx create mode 100644 packages/website-next/src/app/docs/reactivity/untrack/page.mdx create mode 100644 packages/website-next/src/app/docs/reactivity/watch/page.mdx create mode 100644 packages/website-next/src/app/docs/template-system/conditional/page.mdx create mode 100644 packages/website-next/src/app/docs/template-system/event-handling/page.mdx create mode 100644 packages/website-next/src/app/docs/template-system/list-rendering/page.mdx create mode 100644 packages/website-next/src/app/error.tsx create mode 100644 packages/website-next/src/app/examples/page.tsx create mode 100644 packages/website-next/src/app/globals.css create mode 100644 packages/website-next/src/app/information/LoadMoreSection.tsx create mode 100644 packages/website-next/src/app/information/activity/[slug]/page.tsx create mode 100644 packages/website-next/src/app/information/news/[slug]/page.tsx create mode 100644 packages/website-next/src/app/information/page.tsx create mode 100644 packages/website-next/src/app/laws/page.tsx create mode 100644 packages/website-next/src/app/layout.tsx create mode 100644 packages/website-next/src/app/loading.tsx create mode 100644 packages/website-next/src/app/not-found.tsx create mode 100644 packages/website-next/src/app/page.tsx create mode 100644 packages/website-next/src/app/playground/[slug]/page.tsx create mode 100644 packages/website-next/src/app/playground/components/CodeCard.tsx create mode 100644 packages/website-next/src/app/playground/components/CodeSection.tsx create mode 100644 packages/website-next/src/app/playground/components/PlaygroundContent.tsx create mode 100644 packages/website-next/src/app/playground/components/PlaygroundSidebar.tsx create mode 100644 packages/website-next/src/app/playground/components/TeachContent.tsx create mode 100644 packages/website-next/src/app/playground/components/tutorials/Basic.tsx create mode 100644 packages/website-next/src/app/playground/components/tutorials/Component.tsx create mode 100644 packages/website-next/src/app/playground/components/tutorials/Computed.tsx create mode 100644 packages/website-next/src/app/playground/components/tutorials/Conditional.tsx create mode 100644 packages/website-next/src/app/playground/components/tutorials/Lifecycle.tsx create mode 100644 packages/website-next/src/app/playground/components/tutorials/Lists.tsx create mode 100644 packages/website-next/src/app/playground/components/tutorials/State.tsx create mode 100644 packages/website-next/src/app/playground/components/tutorials/Watch.tsx create mode 100644 packages/website-next/src/app/playground/components/tutorials/eventHandling.tsx create mode 100644 packages/website-next/src/app/playground/data/playgroundData.ts create mode 100644 packages/website-next/src/app/playground/page.tsx create mode 100644 packages/website-next/src/app/privacy/page.tsx create mode 100644 packages/website-next/src/app/project/[slug]/page.tsx create mode 100644 packages/website-next/src/app/project/page.tsx create mode 100644 packages/website-next/src/components/HomePage/ActivityArea/Activity.tsx create mode 100644 packages/website-next/src/components/HomePage/ApiComparison.tsx create mode 100644 packages/website-next/src/components/HomePage/FeatureCard.tsx create mode 100644 packages/website-next/src/components/HomePage/Footer.tsx create mode 100644 packages/website-next/src/components/HomePage/HomePageButton/WhyOpenInulaButton.tsx create mode 100644 packages/website-next/src/components/HomePage/HomePageButton/WhyOpenInulaModal.tsx create mode 100644 packages/website-next/src/components/HomePage/Main.tsx create mode 100644 packages/website-next/src/components/HomePage/Nav.tsx create mode 100644 packages/website-next/src/components/HomePage/NavComponents/CustomSearch.tsx create mode 100644 packages/website-next/src/components/HomePage/NavComponents/DropdownMenu.tsx create mode 100644 packages/website-next/src/components/HomePage/NavComponents/SearchBar.tsx create mode 100644 packages/website-next/src/components/HomePage/NavComponents/ThemeSwitch/ThemeScript.tsx create mode 100644 packages/website-next/src/components/HomePage/NavComponents/ThemeSwitch/ThemeToggle.tsx create mode 100644 packages/website-next/src/components/HomePage/PerformanceComparison.tsx create mode 100644 packages/website-next/src/components/MDXDetailPage.tsx create mode 100644 packages/website-next/src/components/MarkdownPage.tsx create mode 100644 packages/website-next/src/components/magicui/aurora-text.tsx create mode 100644 packages/website-next/src/components/magicui/code-comparison.tsx create mode 100644 packages/website-next/src/components/magicui/magic-card.tsx create mode 100644 packages/website-next/src/components/magicui/meteors.tsx create mode 100644 packages/website-next/src/lib/utils.ts create mode 100644 packages/website-next/src/mdx-components.tsx create mode 100644 packages/website-next/tsconfig.json diff --git a/packages/website-next/.gitignore b/packages/website-next/.gitignore new file mode 100644 index 00000000..b967fc61 --- /dev/null +++ b/packages/website-next/.gitignore @@ -0,0 +1,52 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/openInula/node_modules +/openInula/dist +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +#IDE +.idea/ + +package-lock.json +yarn.lock +pnpm-lock.yaml + +_pagefind/ \ No newline at end of file diff --git a/packages/website-next/README.md b/packages/website-next/README.md new file mode 100644 index 00000000..af819872 --- /dev/null +++ b/packages/website-next/README.md @@ -0,0 +1,166 @@ +# OpenInula 官网(Next.js 版) + +## 项目简介 + +OpenInula 是一个现代化的 JavaScript UI 框架,致力于提供极致性能和开发体验。本仓库为 OpenInula 新一代官网,基于 Next.js 13+(App Router)与 Tailwind CSS 构建,提供文档、教程、示例与 Playground 等站点能力。 + +--- + +## 核心特性 + +- **编译优先**:在编译期完成大部分工作,缩短运行时开销 +- **细粒度响应式**:自动追踪依赖,减少不必要重渲染 +- **API 兼容性**:与 React 生态高度契合,平滑迁移 +- **模板增强**:内置 if/for 等模板指令 +- **站点体验**:深色模式、搜索、高亮、课程与示例、交互动效 + +--- + +## 环境要求 + +- Node.js ≥ 18 +- 包管理器:推荐 pnpm(也可使用 yarn/npm) +- 由于本仓库包含 `openInula` 子项目(Vite 应用),其 Vite 插件要求 Node ≥ 18 + +--- + +## 安装与启动 + +1. 安装依赖(根项目): + +```bash +pnpm install +``` + +2. 安装依赖(可选,openInula 子项目用于 Playground REPL 示例): + +```bash +cd openInula && pnpm install +``` + +3. 本地开发: + +```bash +# 在根目录启动 Next.js 开发服务器 +pnpm dev + +# 如需同时启动 openInula 子项目(可选) +cd openInula && pnpm dev +``` +4. 启用文档搜索 +```bash +#首先构建项目 +pnpm build --no-lint + +#然后运行 postbuild 生成搜索索引 +pnpm postbuild +``` +--- + +## 构建与部署 + +- 根站点构建: +首先将openInula文件夹移到其他地方,不要在项目根目录。同时,也需要进入openInula文件夹进行一次pnpm build构建 + +```bash +pnpm build --no-lint +pnpm postbuild +``` + +- 站点启动(生产): + +```bash +pnpm start +``` + +- 构建后搜索索引:构建完成会自动执行 `postbuild`,用 Pagefind 生成到 `public/_pagefind`。 + +- 注意事项(重要): + - 本仓库包含 `openInula/` 子目录(一个独立的 Vite 应用,仅供 REPL/Playground),默认情况下并不会影响 Next.js 的构建。但如果你的自定义流程将其纳入同一产物或分析,请避免把 `openInula` 误当作 Next.js 的子模块进行打包。 + +--- + +## 目录结构(节选) + +``` +website-next/ +├─ src/ +│ ├─ app/ # Next.js App Router 页面与路由 +│ │ ├─ docs/ # 文档(MDX)与文档页 +│ │ ├─ playground/ # 教学与 Playground 页面 +│ │ ├─ api/ # API 文档/说明页 +│ │ └─ ... +│ ├─ components/ # 站点通用组件(含 HomePage、UI 组件等) +│ └─ lib/ # 工具、hooks、性能与 utils +├─ public/ # 静态资源(含 Pagefind 索引输出 _pagefind) +├─ openInula/ # 独立 Vite 应用(用于 REPL/Playground 示例) +├─ package.json +└─ README.md +``` + +--- + +## 常用脚本 + +根目录 `package.json`: + +```json +{ + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", + "postbuild": "pagefind --site .next/server/app --output-path public/_pagefind" + } +} +``` + +- **dev**: 启动 Next.js 开发服务器 +- **build**: 生产构建(会为 App Router 产出 `.next`) +- **start**: 启动生产服务 +- **lint**: 运行 ESLint 检查 +- **postbuild**: 构建后生成 Pagefind 搜索索引 + +`openInula/package.json`(子项目): + +```json +{ + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + } +} +``` + +--- + +## FAQ / 故障排查 + +- **Pagefind 索引未生成或搜索无结果** + - 确认构建成功后已执行 `postbuild`。也可手动运行: + ```bash + pnpm build && pnpm exec pagefind --site .next/server/app --output-path public/_pagefind + ``` +- **本地开发页面加载缓慢或样式异常** + - 删除 `.next/` 与 `node_modules/` 重新安装依赖;检查 `tailwindcss` 版本与 PostCSS 配置是否匹配。 +- **Playground 示例不工作** + - `openInula/` 子项目需单独 `pnpm install` 与 `pnpm dev`;确保依赖 `openinula`、`inula-router` 正常安装。 + +--- + +## 贡献 + +欢迎任何形式的贡献! + +1. Fork 本仓库并克隆到本地 +2. 从 `main` 切出特性分支进行开发 +3. 发起 MR 并补充说明变更点与动机 + +详细流程与行为准则请参阅: + +- `src/app/docs/conventional/ContributingGuide/page.mdx` +- `src/app/docs/conventional/CodeOfConduct/page.mdx` + +--- \ No newline at end of file diff --git a/packages/website-next/components.json b/packages/website-next/components.json new file mode 100644 index 00000000..ffe928f5 --- /dev/null +++ b/packages/website-next/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/packages/website-next/eslint.config.mjs b/packages/website-next/eslint.config.mjs new file mode 100644 index 00000000..c85fb67c --- /dev/null +++ b/packages/website-next/eslint.config.mjs @@ -0,0 +1,16 @@ +import { dirname } from "path"; +import { fileURLToPath } from "url"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +const eslintConfig = [ + ...compat.extends("next/core-web-vitals", "next/typescript"), +]; + +export default eslintConfig; diff --git a/packages/website-next/index.d.ts b/packages/website-next/index.d.ts new file mode 100644 index 00000000..90103dee --- /dev/null +++ b/packages/website-next/index.d.ts @@ -0,0 +1,461 @@ +import { ReactNode } from "react"; + +// ==================== 通用类型 ==================== +export type Theme = "light" | "dark"; + +// ==================== 导航相关接口 ==================== +export interface DropdownItem { + name: string; + href: string; +} + +export interface DropdownMenuProps { + name: string; + href: string; + dropdown: DropdownItem[]; + isActive: boolean; + isHovered: boolean; + onMouseEnter: () => void; + onMouseLeave: () => void; +} + +export interface SearchBarProps { + placeholder?: string; + onSearch: (query: string) => void; +} + +export interface CustomSearchProps { + onSearch: (query: string) => void; +} + +// ==================== 首页相关接口 ==================== +export interface Partner { + name: string; + logo: string; + url: string; +} + +export interface FeatureCardProps { + title: string; + description: string; + icon: ReactNode; + className?: string; +} + +export interface ActivityProps { + tabItems?: string[]; +} + +export interface LoadMoreSectionProps { + title: string; + items: T[]; + renderItem: (item: T) => ReactNode; + initialCount?: number; + step?: number; +} + +// ==================== 活动、资讯组件相关接口 ==================== +export interface NewsItem { + key: number; + img: string; + title: string; + introduce: string; + time: string; +} + +export interface ActivityItem { + key: number; + img: string; + name: string; + introduce: string; + beginTime: string; + endTime: string; + type: string; +} + +// ==================== 博客相关接口 ==================== +export interface BlogItem { + key: number; + img?: string; + title: string; + time: string; + author: string; + type: string; + tags?: string[]; +} + +export interface BlogCardProps { + blog: BlogItem; + theme: string | undefined; +} + +export interface BlogListProps { + blogs: BlogItem[]; + theme: string | undefined; +} + +export interface BlogFilterBarProps { + onFilterChange: (filter: string) => void; + activeFilter: string; +} + +export interface BlogPaginationProps { + currentPage: number; + totalPages: number; + onPageChange: (page: number) => void; +} + +// ==================== 贡献者相关接口 ==================== +export interface Contributor { + name: string; + avatar: string; + role: string; + description: string; + github?: string; + email?: string; +} + +// ==================== 文档相关接口 ==================== +export interface DocumentItem { + id: string; + title: string; + url?: string; + description: string; +} + +export interface DocumentSidebarProps { + documents: DocumentItem[]; + defaultActiveId?: string; + title?: string; + onDocumentChange?: (docId: string) => void; + className?: string; + children?: (currentDoc: DocumentItem | undefined) => ReactNode; +} + +// ==================== Playground相关接口 ==================== +export interface PlaygroundItem { + id: number; + title: string; + description: string; + category: string; + subcategory?: string; + slug: string; + content?: string; + code?: string; +} + +export interface PlaygroundSidebarProps { + playgroundData: PlaygroundItem[]; + selectedItem: PlaygroundItem | null; + isCollapsed: boolean; + onToggleCollapse: () => void; +} + +export interface PlaygroundContentProps { + selectedItem: PlaygroundItem | null; +} + +// ==================== 项目相关接口 ==================== +export interface Course { + id: string; + title: string; + description: string; + image: string; + duration: string; + level: string; + tags: string[]; +} + +// ==================== 页面组件接口 ==================== +export interface MDXDetailPageProps { + children: ReactNode; +} + +export interface MarkdownPageProps { + title: string; + description?: string; + children: ReactNode; + className?: string; +} + +// ==================== MagicUI组件接口 ==================== +export interface AuroraTextProps { + children: ReactNode; + className?: string; +} + +export interface MeteorsProps { + number?: number; +} + +export interface MagicCardProps { + children: ReactNode; + className?: string; + gradientColor?: string; +} + +export interface CodeComparisonProps { + leftCode: string; + rightCode: string; + leftTitle?: string; + rightTitle?: string; + language?: string; +} + +// ==================== 主题相关接口 ==================== +export interface ThemeToggleProps { + className?: string; +} + +export interface ThemeScriptProps { + theme?: string; +} + +// ==================== 性能相关接口 ==================== +export interface PerformanceMetrics { + renderTime: number; + memoryUsage: number; + bundleSize: number; +} + +export interface PerformanceComparisonProps { + inulaMetrics: PerformanceMetrics; + reactMetrics: PerformanceMetrics; + vueMetrics: PerformanceMetrics; +} + +// ==================== API相关接口 ==================== +export interface ApiResponse { + success: boolean; + data?: T; + message?: string; + error?: string; +} + +export interface PaginationParams { + page: number; + limit: number; + total?: number; +} + +export interface SearchParams { + query: string; + filters?: Record; + sortBy?: string; + sortOrder?: "asc" | "desc"; +} + +// ==================== 表单相关接口 ==================== +export interface FormField { + name: string; + label: string; + type: + | "text" + | "email" + | "password" + | "textarea" + | "select" + | "checkbox" + | "radio"; + required?: boolean; + placeholder?: string; + options?: Array<{ value: string; label: string }>; + validation?: { + pattern?: RegExp; + message?: string; + minLength?: number; + maxLength?: number; + }; +} + +export interface FormProps { + fields: FormField[]; + onSubmit: (data: Record) => void; + submitText?: string; + className?: string; +} + +// ==================== 路由相关接口 ==================== +export interface RouteConfig { + path: string; + component: React.ComponentType; + exact?: boolean; + children?: RouteConfig[]; + meta?: { + title?: string; + requiresAuth?: boolean; + roles?: string[]; + }; +} + +// ==================== 国际化相关接口 ==================== +export interface LocaleConfig { + code: string; + name: string; + flag?: string; +} + +export interface I18nContextType { + locale: string; + setLocale: (locale: string) => void; + t: (key: string, params?: Record) => string; +} + +// ==================== 错误处理相关接口 ==================== +export interface ErrorBoundaryState { + hasError: boolean; + error?: Error; + errorInfo?: React.ErrorInfo; +} + +export interface ErrorBoundaryProps { + children: ReactNode; + fallback?: React.ComponentType<{ error: Error; resetError: () => void }>; +} + +// ==================== 动画相关接口 ==================== +export interface AnimationConfig { + duration: number; + easing: string; + delay?: number; + direction?: "normal" | "reverse" | "alternate" | "alternate-reverse"; + fillMode?: "none" | "forwards" | "backwards" | "both"; + iterationCount?: number | "infinite"; +} + +export interface AnimatedComponentProps { + animation: AnimationConfig; + children: ReactNode; + className?: string; + onAnimationEnd?: () => void; +} + +// ==================== 存储相关接口 ==================== +export interface StorageConfig { + key: string; + defaultValue?: any; + serializer?: { + serialize: (value: any) => string; + deserialize: (value: string) => any; + }; +} + +export interface UseStorageReturn { + value: T; + setValue: (value: T | ((prev: T) => T)) => void; + removeValue: () => void; +} + +// ==================== 网络请求相关接口 ==================== +export interface RequestConfig { + url: string; + method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH"; + headers?: Record; + body?: any; + timeout?: number; + retries?: number; + retryDelay?: number; +} + +export interface UseRequestReturn { + data: T | null; + loading: boolean; + error: Error | null; + execute: (config?: Partial) => Promise; + reset: () => void; +} + +// ==================== 工具函数类型 ==================== +export type DebounceFunction any> = ( + func: T, + delay: number +) => (...args: Parameters) => void; + +export type ThrottleFunction any> = ( + func: T, + delay: number +) => (...args: Parameters) => void; + +export type DeepPartial = { + [P in keyof T]?: T[P] extends object ? DeepPartial : T[P]; +}; + +export type Optional = Omit & Partial>; + +export type Required = T & Required>; + +export type ValueOf = T[keyof T]; + +export type ArrayElement = T extends Array ? U : never; + +// ==================== 事件相关接口 ==================== +export interface EventHandler { + (event: T): void; +} + +export interface KeyboardEvent { + key: string; + code: string; + ctrlKey: boolean; + shiftKey: boolean; + altKey: boolean; + metaKey: boolean; +} + +export interface MouseEvent { + x: number; + y: number; + button: number; + buttons: number; +} + +// ==================== 媒体相关接口 ==================== +export interface MediaQuery { + query: string; + matches: boolean; +} + +export interface UseMediaQueryReturn { + matches: boolean; + addListener: (callback: (matches: boolean) => void) => void; + removeListener: (callback: (callback: boolean) => void) => void; +} + +// ==================== 时间相关接口 ==================== +export interface TimeConfig { + format: string; + timezone?: string; + locale?: string; +} + +export interface UseTimerReturn { + time: Date; + start: () => void; + stop: () => void; + reset: () => void; + isRunning: boolean; +} + +// ==================== 验证相关接口 ==================== +export interface ValidationRule { + required?: boolean; + minLength?: number; + maxLength?: number; + pattern?: RegExp; + custom?: (value: any) => boolean | string; +} + +export interface ValidationResult { + isValid: boolean; + errors: string[]; +} + +export interface UseValidationReturn { + values: T; + errors: Partial>; + touched: Partial>; + handleChange: (field: keyof T, value: any) => void; + handleBlur: (field: keyof T) => void; + validate: () => ValidationResult; + reset: () => void; +} diff --git a/packages/website-next/next.config.ts b/packages/website-next/next.config.ts new file mode 100644 index 00000000..a24f1be8 --- /dev/null +++ b/packages/website-next/next.config.ts @@ -0,0 +1,22 @@ +import type { NextConfig } from "next"; +import nextra from 'nextra' + +const nextConfig: NextConfig = { + pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'], + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 'openinula-website.obs.ap-southeast-1.myhuaweicloud.com', + port: '', + pathname: '/img/**', + }, + ], + }, +}; + +const withNextra = nextra({ + defaultShowCopyCode: true, +}) + +export default withNextra(nextConfig) diff --git a/packages/website-next/openInula/README.md b/packages/website-next/openInula/README.md new file mode 100644 index 00000000..542c363a --- /dev/null +++ b/packages/website-next/openInula/README.md @@ -0,0 +1,4 @@ +# openinula + vite + +该模板提供了 `openinula` 工作在 `vite`的基础配置。 +> 请注意由于Vite插件有node版本限制,请使用`node -v`命令确认node版本大于等于node v18。 \ No newline at end of file diff --git a/packages/website-next/openInula/index.html b/packages/website-next/openInula/index.html new file mode 100644 index 00000000..36465750 --- /dev/null +++ b/packages/website-next/openInula/index.html @@ -0,0 +1,12 @@ + + + + + PlayGround + + + +
+ + + diff --git a/packages/website-next/openInula/package.json b/packages/website-next/openInula/package.json new file mode 100644 index 00000000..d558964e --- /dev/null +++ b/packages/website-next/openInula/package.json @@ -0,0 +1,28 @@ +{ + "name": "inula-vite-app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "keywords": [], + "author": "", + "license": "MulanPSL2", + "dependencies": { + "@babytian/openinula-repl-next": "^0.0.1", + "inula-router": "^1.0.16", + "openinula": "^0.1.1" + }, + "devDependencies": { + "@babel/core": "^7.21.4", + "@babel/preset-env": "^7.21.4", + "@babel/preset-react": "^7.18.6", + "@vitejs/plugin-react": "^3.1.0", + "@vitejs/plugin-react-refresh": "^1.3.6", + "babel-plugin-import": "^1.13.6", + "vite": "^4.2.1" + } +} diff --git a/packages/website-next/openInula/pnpm-workspace.yaml b/packages/website-next/openInula/pnpm-workspace.yaml new file mode 100644 index 00000000..44c7411c --- /dev/null +++ b/packages/website-next/openInula/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +overrides: + openinula-repl-next: link:../../repl diff --git a/packages/website-next/openInula/src/components/HomePage.jsx b/packages/website-next/openInula/src/components/HomePage.jsx new file mode 100644 index 00000000..b0ffdb49 --- /dev/null +++ b/packages/website-next/openInula/src/components/HomePage.jsx @@ -0,0 +1,32 @@ + +import Inula, {useMemo, useRef} from 'openinula'; +import { Repl, Editor, Viewer } from '@babytian/openinula-repl-next' + +export default function App() { + const coded = useMemo(() => ` +import { render } from '@openinula/next'; +function HelloWorld() { + return

Hello OpenInula_next!!

; +} + +render(HelloWorld(), document.getElementById('app')); +`, []); + + const editorRef = useRef(); + const viewerRef = useRef(); + return ( +
+ + +
+ +
+
+
+ ); +} \ No newline at end of file diff --git a/packages/website-next/openInula/src/components/PlaygroundPage.jsx b/packages/website-next/openInula/src/components/PlaygroundPage.jsx new file mode 100644 index 00000000..b6878492 --- /dev/null +++ b/packages/website-next/openInula/src/components/PlaygroundPage.jsx @@ -0,0 +1,79 @@ +import { useRef, useEffect, useState } from 'openinula'; +import { Repl, Editor, Viewer } from '@babytian/openinula-repl-next'; +import { getCodeById } from '../lib/code.ts'; + +function PlaygroundPage() { + // 从 URL 查询参数获取初始代码 ID,避免首屏回退到 HelloWorld + let initialId = 1; + try { + const params = new URLSearchParams(window.location.search); + const idParam = params.get('id'); + if (idParam) { + const parsed = Number(idParam); + if (!Number.isNaN(parsed)) initialId = parsed; + } + } catch (e) { + // 忽略解析错误,保持默认 id = 1 + } + + const initialCode = getCodeById(initialId) || getCodeById(1) || ''; + + const [code, setCode] = useState(initialCode); + + useEffect(() => { + const handler = (event) => { + const { type, payload } = event.data || {}; + + // 处理传统的代码字符串方式(向下兼容) + if (type === "SET_CODE" && payload) { + setCode(payload); + } + + // 处理新的代码ID方式 + if (type === "SET_CODE_BY_ID" && payload) { + const codeFromId = getCodeById(payload); + if (codeFromId) { + console.log('Setting new code for ID:', payload); + setCode(codeFromId); + } else { + console.warn(`未找到ID为 ${payload} 的代码示例`); + } + } + }; + + // 添加消息监听器 + window.addEventListener("message", handler); + + // 通知父窗口 iframe 已就绪,方便外部在需要时重发 + try { + window.parent?.postMessage({ type: 'IFRAME_READY' }, '*'); + } catch (e) {} + + return () => { + window.removeEventListener("message", handler); + }; + }, []); + + const editorRef = useRef(); + const viewerRef = useRef(); + const CustomEmptyMenu = () =>
; + + return ( +
+ + +
+ +
+
+
+ ); +} + +export default PlaygroundPage; diff --git a/packages/website-next/openInula/src/index.css b/packages/website-next/openInula/src/index.css new file mode 100644 index 00000000..be0ab6c6 --- /dev/null +++ b/packages/website-next/openInula/src/index.css @@ -0,0 +1,3 @@ +* { + box-sizing: border-box; +} \ No newline at end of file diff --git a/packages/website-next/openInula/src/index.jsx b/packages/website-next/openInula/src/index.jsx new file mode 100644 index 00000000..3dfd9119 --- /dev/null +++ b/packages/website-next/openInula/src/index.jsx @@ -0,0 +1,19 @@ +import { BrowserRouter, Route, Switch } from 'inula-router'; + +import HomePage from "./components/HomePage"; +import PlaygroundPage from "./components/PlaygroundPage"; +import Inula from "openinula"; + +function App() { + return ( + + + + + {/* 可以在这里添加更多路由 */} + + + ); +} + +Inula.render(, document.getElementById('root')); diff --git a/packages/website-next/openInula/src/lib/code.ts b/packages/website-next/openInula/src/lib/code.ts new file mode 100644 index 00000000..d34c813c --- /dev/null +++ b/packages/website-next/openInula/src/lib/code.ts @@ -0,0 +1,199 @@ +export const codeSamples = [ + { + id: 1, + title: "入门", + code: `import { render } from '@openinula/next'; + + function HelloWorld() { + return

Hello World!

; +} + +render(HelloWorld(), document.getElementById('app'));`, + }, + { + id: 2, + title: "组件", + code: `import { render } from '@openinula/next'; + + function App() { + return

This is my first component

; +} + +render(App(), document.getElementById('app'));`, + }, + { + id: 3, + title: "状态管理", + code: `import { render } from '@openinula/next'; + + function UserInput() { + let count = 0; + function incrementCount() { + count = count + 1; + } + + return ( + <> +

{count}

+ + + ); +} + +render(UserInput(), document.getElementById('app')); +`, + }, + { + id: 4, + title: "计算属性", + code: `import { render } from '@openinula/next'; + + function DoubleCounter() { + let count = 0; + // 计算值:double 会自动随着 count 变化 + const double = count * 2; + + return ( +
+

当前计数:{count}

+

双倍值:{double}

+ +
+ ); +} + +render(, document.getElementById('app'));`, + }, + { + id: 5, + title: "监听系统", + code: `import { render, watch} from '@openinula/next'; + + function MultiWatch() { + let a = 1; + let b = 2; + + watch(() => { + console.log('a 变化:' + a); + }); + watch(() => { + console.log('b 变化:' + b); + }); + + return ( +
+ + +
+ ); +} + +render(, document.getElementById('app'));`, + }, + { + id: 6, + title: "条件渲染", + code: `import { render } from '@openinula/next'; + +function TrafficLight() { + let lightIndex = 0; + + let light = lightIndex ? 'green' : 'red'; + + function nextLight() { + lightIndex = (lightIndex + 1) % 2; + } + + return ( + <> + +

Light is: {light}

+

+ You must: + + STOP + + + GO + +

+ + ); +} + +render(TrafficLight(), document.getElementById('app')); +`, + }, + { + id: 7, + title: "列表渲染", + code: `import { render } from '@openinula/next'; + +function FruitList() { + const fruits = ['苹果', '香蕉', '橙子']; + + return ( +
    + + {(fruit) =>
  • {fruit}
  • } +
    +
+ ); +} + +render(, document.getElementById('app'));`, + }, + { + id: 8, + title: "事件处理", + code: `import { render } from '@openinula/next'; + +function ClickCounter() { + let count = 0; + + function handleClick() { + count++; + } + + return ( + + ); +} + +render(, document.getElementById('app'));`, + }, + { + id: 9, + title: "生命周期", + code: `import { render } from '@openinula/next'; + +function PageTitle() { + let counts = 0; + didMount(() => { + counts = counts + 5; + }); + return

页面标题:{counts}

; +} + +render(, document.getElementById('app'));`, + }, +]; + +export const getCodeById = (id: number): string | null => { + console.log( + "getCodeById called with ID:", + id, + "Available samples:", + codeSamples.map((s) => ({ id: s.id, title: s.title })) + ); + const sample = codeSamples.find((sample) => sample.id === id); + if (sample) { + console.log("Found sample:", sample.title); + return sample.code; + } else { + console.warn("No sample found for ID:", id); + return null; + } +}; diff --git a/packages/website-next/openInula/vite.config.js b/packages/website-next/openInula/vite.config.js new file mode 100644 index 00000000..ae06c555 --- /dev/null +++ b/packages/website-next/openInula/vite.config.js @@ -0,0 +1,58 @@ +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vite"; + +let alias = { + react: "openinula", + "react-dom": "openinula", + "react/jsx-dev-runtime": "openinula/jsx-dev-runtime", + "react/jsx-runtime": "openinula/jsx-runtime", + "@openinula/next": "openinula", +}; + +export default defineConfig({ + plugins: [react()], + resolve: { + alias, + }, + + build: { + outDir: "dist", + assetsDir: "assets", + sourcemap: false, // 禁用 sourcemap 以避免混淆问题 + minify: false, + + rollupOptions: { + input: { + main: "./index.html", + }, + output: { + manualChunks: undefined, + globals: { + openinula: "Inula", + "inula-router": "InulaRouter", + }, + }, + }, + + target: "es2015", + cssCodeSplit: false, + chunkSizeWarningLimit: 1000, + lib: false, + ssr: false, + }, + + server: { + port: 5173, + open: true, + }, + + optimizeDeps: { + include: ["openinula", "inula-router", "@babytian/openinula-repl-next"], + force: true, + }, + + esbuild: { + keepNames: true, + legalComments: "none", + }, +}); diff --git a/packages/website-next/package.json b/packages/website-next/package.json new file mode 100644 index 00000000..5591dd20 --- /dev/null +++ b/packages/website-next/package.json @@ -0,0 +1,51 @@ +{ + "name": "website-next", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", + "postbuild": "pagefind --site .next/server/app --output-path public/_pagefind" + }, + "dependencies": { + "@ant-design/icons": "^6.0.0", + "@mdx-js/loader": "^3.1.0", + "@mdx-js/react": "^3.1.0", + "@next/mdx": "^15.3.5", + "@shikijs/transformers": "^3.7.0", + "@types/mdx": "^2.0.13", + "antd": "^5.26.5", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "gsap": "^3.13.0", + "highlight.js": "^11.11.1", + "lucide-react": "^0.525.0", + "motion": "^12.23.6", + "next": "15.4.1", + "next-themes": "^0.4.6", + "nextra": "^4.2.17", + "nextra-theme-docs": "^4.2.17", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-intersection-observer": "^9.16.0", + "react-markdown": "^10.1.0", + "shiki": "^3.7.0", + "tailwind-merge": "^3.3.1" + }, + "devDependencies": { + "@eslint/eslintrc": "^3.3.1", + "@tailwindcss/postcss": "^4.1.11", + "@tailwindcss/typography": "^0.5.16", + "@types/node": "^20.19.4", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "eslint": "^9.30.1", + "eslint-config-next": "15.3.4", + "pagefind": "^1.3.0", + "tailwindcss": "^4.1.11", + "tw-animate-css": "^1.3.5", + "typescript": "^5.8.3" + } +} diff --git a/packages/website-next/postcss.config.mjs b/packages/website-next/postcss.config.mjs new file mode 100644 index 00000000..61e36849 --- /dev/null +++ b/packages/website-next/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/packages/website-next/public/ContactUsPage/img.png b/packages/website-next/public/ContactUsPage/img.png new file mode 100644 index 0000000000000000000000000000000000000000..bd3cb3f338c83342008c0a5f389bdc0f765f3c6e GIT binary patch literal 32169 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 z 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μqij8yjs0-x_2bW?|L)kYZ+{d@yq6D- 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 literal 0 HcmV?d00001 diff --git a/packages/website-next/public/favicon.ico b/packages/website-next/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b1919800714d1ce2b1266ce7b76e42c8088b5bd9 GIT binary patch literal 7412 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 \ No newline at end of file diff --git a/packages/website-next/public/font/geist-v3-latin-regular.woff2 b/packages/website-next/public/font/geist-v3-latin-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..a190bc9f36ee8e3453fbe6324f940cd884c727bb GIT binary patch literal 12512 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 XENj=Q;LikP00000NkvXXu0mjfM*aE3 literal 0 HcmV?d00001 diff --git a/packages/website-next/public/footerIcon.gitee.png b/packages/website-next/public/footerIcon.gitee.png new file mode 100644 index 0000000000000000000000000000000000000000..773358b6e3efbbed23ff81dc102bca97567aa7fc GIT binary patch literal 1182 zcmV;P1Y!G$P)Px(SV=@dR9Hu~S6yfvWfVPkW;aWkW_DvDwl&pA6+uy~_9Z?DRjej8o5V;IDN6UJ z5upnDAV{rEsW0M#ps{YVn@~~2wQY8`H4qgwh=n4pz6dIn`rr5ycXu`kCc86NzKv5S zo0-gPh#&0B+;h)8d%vH1FTvwVr@2n6FLtuQ4-jx8KrH~bFqjGSCjjyLiiwUH7aPY1 z2B_qPn%qFIoys@)b=prr96*B`{$G2Mz()dp{ot<7W^E-OM*#;8u++L$+Y8`%08JhP zFNG2Q0`Oe4OF2wLY{y|M;LY)AWxnJeWAL4;3S8wxz(l}b?zhXvG69LP{1#cF2>@Hx zBDjU)JQMGTheH>vyh{X#{jSsL9Duep4sOz2SdjU)$L|Z}%nz3YBogeGuh1qzX#byr zo3x+lQ_6PpmRu5$%I2SCrWc%p)4N2*J4Q)A6Yp#O*{jG@w$QZ|{qee2*n+@{)XygBCtUI`u-k6wbSophM918z35MewP4(>F+A3dQpFUZ^h z;99SOh|vzh4jcTuGOsjIDx>u>@d8(~<5Xr>+JdzdaNeo#tY!;jA8C=UkfmgJN4*_`FLk84Xcd*CAB{NzVh_iNn67$_Ol>U8vAP^`3 zkg7q}3{+aQTeK&c5OfkDlk{;U+&F2qC$oh?F!tN{%qsKBWtC!-%H~IyX?HcqdJ8=K z^JS3XXvCn^Gto}9a~WR$)K;Ijg)8K_mjXlCXnope!S>0}!ruC9Dnb4HI{)*p{1oqCF4jbc%u7Yl~rzX5hnmf4R@oU}92KI-t5j z3`B?Qu8~J!zkz9Aw7W4?(`aTTA05ku3|SgvMzp5klxWBwm^<{yJsU*1cU-R1u_YsQ w#X#|1CVm)<>+QyK0={P8EqzLP-|Kk(4^07*qoM6N<$f*>v~6951J literal 0 HcmV?d00001 diff --git a/packages/website-next/public/footerIcon.qrcode.png b/packages/website-next/public/footerIcon.qrcode.png new file mode 100644 index 0000000000000000000000000000000000000000..ce5e89bec3fb384be089060f83a4a206a9968bce GIT binary patch literal 504 zcmVPx$vPnciR5(xNlsii#K@^40ZP7p$t1%T81Vs%*7t=)yOiZQ*3>IP6#Ogo{3=BjW z$6*JNjTfWpW->!(s?Eh;un#i@BY%KhBPu?ouk?bTO^>t6WL8%9@j;z?Pmy1<6%ghD zICy?;n7Qob-7Rfwi5RiUi|>BT7C|Tg=uFke46cxG>gKSR^{9uLCwxHVF$p66!aFvMS5YvZ%R>MA}ji?DP}7BcCgXl zy%t`kze@Iur`Dzb#+1s7X>IIR0!m7Xfgr4ZX6D0I);m^G3^xUac8>TTaHuW7O7+~m zcle_xdym=z)O!~r=!m~~Qk4D|nDu?N)bO=lZUv0i04im8xemr+;$`31pG1fka$;GV u`U)j$BZUmYXqMS2D%mrptI-5GbnpP5fKej4w?{1i0000 \ No newline at end of file diff --git a/packages/website-next/public/navlogo.png b/packages/website-next/public/navlogo.png new file mode 100644 index 0000000000000000000000000000000000000000..7009246c037aaefd6f28b924be92912d67f1b696 GIT binary patch literal 9731 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 R5rO~!002ovPDHLkV1oaQ=iC4Q literal 0 HcmV?d00001 diff --git a/packages/website-next/public/navlogowhite.png b/packages/website-next/public/navlogowhite.png new file mode 100644 index 0000000000000000000000000000000000000000..5f2c57b4d4410b7d0aea2790cb3f05f008650faa GIT binary patch literal 9872 zcmV;BCU4n^P) zd2}4ro$o)ldXZXNw{DHUG{V50PU;OaPUZD{Zns6IqfZN}^Z+*kW)IcJUobODg0JaE?TQdX@ zG;!OhPu|cnQTbf*(90fU5+w507q1CTRJsz0J5<$ z3r#eI@A8N9$>i<7+7LlsLTAd_Z|-Rj8udaG9z%cwd%tpJAfL1)63O|^WKM#FEy7#U z4;KD%R{(ebeavq&`b==h`;(xj*aG;z^;!Vf2HcvK{tp94vTrmk)E(m!jAF)_wa`zeU;rTh?v;eM2$nOC*w+&!lyMJ8!%>0{CV< zwX+`Z0>M+a+!)G;=FgIZugD@aK3kw|7Zc?qEN_fL3*Dw>3b*O=995vmCEZTLi_$oxY<6urxvNg(}T<&R%%5UOYp zx`WiP&}e$+3)hBoq@8VP-KcA?`SKh3WQi&~Mjn9|zf~77zf>ZToDXC*gRzHNJVK>e zXkts!oF(<%CN%uL*A^#&3xB!GX9()jgsF_s#Mba#{-#8n7295H78>_ulp!iq;oEob zhOk+>b>Du~Cp7Vfi5U)x{(jw_`>zNBtpCdE0ilU48TCVGw4;fJ*6*wd7E?!wL^3_G z6hK?s?%m+ecKzCK?(qtZ zhBN^T?ET7>VSuad|9ykd#I|G|tpzY4pbrX7H0}D{>d0i(S0a&|JCXt@-g?Xfv`P47sEnhsYw~`-gobYfYo(Ytozzt54v*(_c#PFnfJ2~Us`b95{YE`kT8U9 zCijL!*>D2^_w!GB5&<>OJlzc32W*@D2H*WlQ~SRl z`nul-fNcko2#2_89fobK32wlwdre(tGI*GE3ua`vX1!xnMsNp(Y`6uH&qrQiRp zpV6&4H~LL(N(5Z-ufMAox;SR##H&FA;)4t9d%?0pe z{S6_&v*6KP{$qb~eXy7cMTosj%gY(O(Sl+%5668oxhx&m#yc{Ig6~) zbptK6JD>Js%l!ENxIUOqAy;gB(VHVmh|!*Bq8Ll*)_!x3$M|eI>G7fEl|1y>3;5IZ zvnh2b#8nMdHR`LTY$SavEAlC-M3T;Cix3~I$(8?db7_f@-)?Z%}LH}3%TVN~TYy11F!^Y_VCX*gz zPK7Vtw1_X>yoj0#2XR#wJk=1scw9r(AfbULJBN#{ibNurW|($?LjzHM6+OYns^$^X zG*q;t_+`F(OUrn8)f%>+ILgnDAI(f^%dDq%hB`iaQ?pq<3m)C&5gLs`!>`-jiRQzf zzOE%BS`&Kft^R@^?e^}!XJgnbt+&2-O@s`=^?mELW`VdhGj84D3hv%GpUM(DaaBVA z0#F3Rg+K^UG*DFyRluQBLp;5w3t^VAL?W57SUN<#`^fKU8;B-_P9@bHPJE813FD{c zE@115Rm^reGn0B?_LDpP7TGkT+W{uJ29GcO*$bI*8_+jH_gjgd8Fk-&wE^AMFp0~d zaOb+Ye0I|UoHixZ+Eew`UR)*F1y+slp8hyr{*Sz~l}IEr2ulHs#7DUC;LH5H>qt`Q z65Zi=T6Z|rE!McOyn=sTc@b-?#tgT$%=yhT9+Pa$Oi~)t58mIhIdbssP4x#pvniBs zrPlnPSAAr(2Isq-d~VZ1E?-)yi(aPq#kDl?1675CCkDCe8}G{QuS9a5lGP=CG(N&# z9d6^ZhhC>EK9Ur{xCU|b@v@kfdXH%u4n^Vfilp9a+77_qKV|P2VU`zvC^Y% zVFeBA=QF3$K}^+%8N#Q(lN7|nn4hX?{H*mffAi1*`Ud0YqSz9NWD3Y@PmrD6r}6LG z&Es7s^p+E;S>aTxaP;`#4YOzS7mF5CYO^Jhshj)X&jd1(ZZ*j+GtMY3{Ne7vs{i{^ zLzXB((!}rj3#<9~>RH$oku?|U{`-C&X+4wcwn!wB8BX3V@w?+O zzH;Pk9zJo1&&*!J_3qheFJ8ps$4_#4a2R0A++RH#JoU*N0!Fg+ z=v~!%bgS^D_B+Q+f+V@%N4o<;?>29_=m#(H&KIr?q@Q2?;41-P%=nhr6>hm?Hp{AA z#zcoe0R$R~0L7T#P*s5{VBfKRe!cfB?;RP?ogK`KDUW(|>vUS5)fiD#hK(-fa9pK77U$7pCpp$Pknpau)-Z-HhzowS zyFqAd6RL;`4gWh|xHg%_rQiK+(zo9%my-{#s9}Dk6T47wDguX1!7lW7hazy;1P(>v zaK|7!L!BHrK3J$X7=YGiAHLLIXg!L=Luw6jJ`Nq8K%Yqu<(Ynvv9@aMq#mw%^gpeo zS<+}X@(kpeXF5&fSGTB9j;1`)^aC%Lg#Rt6v0|U`IhUQ@gXF*d+sfT~wtv?q(teL= zRFe|4dUAgUQFI}1$r1;w@6A?Yva+=$LWp7Mz#LbG}}Q%2yR<2k5!dPW8&ca$Di|H9_3@C zd>>P@o1o8l50Kw?;5OnlOj?PihBwf^gF+peEJa@m+maqw^saDcMuvIp%n2SleUkN+ z)m&Ls&5}}A+N6SET&!tqnpJ~KvC-Dq?KTSHAC=e+uMc>G9p2lxBizCcuLtmRM>tvN z_dd6AR0S@1=w+`!v;cUkU0k!+jm;SE6KKiL3WCnwVfKc5IdGz%!C_5r(ansmF6a;P zwj!>-pH%m5JcP;pqswFqdaI=|M?4?ncTrYnTr@zCKzeDnSN>^j>)=g6?$`bwK1S?#Xms#*`g z<^_-LY95uq9pMmqwM9(HxNqSvcQuT<_>OQhcZ4IxQ6uo6A&h1; z19hurm2=tL3Vk+LgMpaJfsO&5dAE~oubyD{!3bx1vwE954bBfe*(R%k&N&FdO6MR3+VL-jAFv%>uQ3Lg5WmMUD%}*=`mdzTBE5dRo97O85<1bt z@$R8>QI&H^gGG1~*=KemShr9%Q@HcV?O2Oaf(ESram~uoXc4zLM?N8RA;>3>T(ptB zUJtd7 zOwUtpXZc(gE9bdbIp4*F3tX&PIR1J~Fg~nXf6aMZAH@30uP?AH0dm`wMX+uW`3opR zAZKaJ^Ko0`V?{gJCr=WD3P^LZ$k+TPWD)L}sDjKuS}el-mR;b*4i|qjYb9%4Zfb2# zhBcL8Rb@y`yzBOUiR19V06ilk92*>@FBa!;-vHesF?xryFC|;aiDNhO#zNqBc6h(W z9pNzg0~sdqW$N8t9{@YNO;w_=3gAoSKbdv=@c+)5etC(FDyNOvs@$b^h1yaFo)QPMTn=WJJ1KYA zaVol?l^8--qNEzWnx?H-M95($YAS#?SI(tUu`{HN?pm6ewVQ`& z$#)HyQ&K{;-N{I)-g4X@?WMhU5P%yA&CR%cGqBk(eF>mf&dh2YfJ)Kd)vJ|PSC!aV zJHLt&A#mDklqdqbBG5N}A3G7Em&|;EL^G+^CpXkig#dai!ovlm5iGhCg%Qd#p4TGW zO>yGvFXCFs%)o;_-rPWuJ3JON3v4DAx#n0C=S5n?m}a#?XcSw>WBR^FE339Dm&j7M zY_r2=XQs$2jCU$BJx6$_x&V?HNj+J%xF{4;0emEKl)Gz|;uNW_V!9|KMGZlst&|WO zVT22zzjuucb82vio{>1G`-kWri4luwNdbBW->LPyo7oD?iykdCSM=KI88@Z^cw}UN z_4|YTN!21YRm@_AvmA#=+0^NuQmwdy{e8qVjU)X7^u^lzp#(jOz7=ER}WX~SLOV6nRdn<7|N_R6N88B)&bkGUh?P1 zVi?V`3)~%#v8}V6Ku5c&H<)y9DM~`vGQ6eaBN)f2ne_^*SkJq8#2(GJ`u^uI83JfV z?@*k+L6s9-L!b#>+uxnl%ZsTun5i+S4m0xv&}R|ensFR1@OsGyn?}sLz1fWB(=ipm zb7}~kz@Z4L94YO+NBniPo5F1GzSIAyXt!4G27UI|<*?jFHhZv}kRmwM`16S4;oQ3f8xJ0< z6O$r<%gf4GQ|@L(Ss6A>VZ`thtqBcP2wso$@LqS{m~piz(TpMNLoqBq({xP&--sKHozDi{?x^M@IEtDiDVT*7p z2Nnsu=znTO+2NU_Ii736S~8)_bbi=&7Y#u^F!MHAdnps?hh{uqlGw zXF561Gg|!YiohWhhGP26@(HbGRzUs8tpC(*&|UMZVy?bVM|yn0&~R!d`fy~B-oZFG zuBgQ>bP=>EpeTY1W|wivyb5l*xQ4fm_p|q4H<7*>v)fw}=058ZjzH@%e*hXW7Z(`c zzqTjKIWO6N3{4i{0a6>^XR?iyE38PCynX0mSx?Giwj_VT=zoZ2-$4sw|71NBwk1O$ z)MLGuNw$VSy-BzSy^NNNC}08v@RIUMHdWSeRaFhc#@-+!s){BcE_9E~ss=-v%5P4b z=6L_mnEBLeW>-_D*m<+FhZDWoy}494ZCp9WjSay|?GfVfln8bW#CUdpC;nyC%q@3f zQv^04uqgsXfYV{)>g82zTIuFU=P<9l7v=3E{l(sb$tHmQ12^kh)&YmmJ%EJL!W*!j zJ#J%sW+smt*S3(_Y{rZJ1F6UQ$M7K5-R%ha18nt>-es}? z^F;@Bq}Jqz(C_zTEujS6MO7F2_w8Y{_y#dA8w1?sIvMFE=-D2ia^92XbO zE2D2P&dyLLuf2E9m$?-}J=Q+yKz|6#{P1NGr8p;^brja+$wzFP(1kSHs-Ml|_rt44 z3gCDMV154+OB1c`|5nWZz`R-VYq7W{K_V|7sXx9Ztjn0|`LJr?7CsBSw%pBkm#^X5 z%U4rZ?#3nrcA>Yh?8(piyG_8^;bFG5AK}c<@R+ndRO?}7Wf@LI7sXQpqg#I~s>-;u zrgBu+Kul#|B#uK7)VdsOSX@0O-JzJuFWOGA|4hGL7DX35+b9v#yU4W_4z_Hb$2b3M zIU6pT=obBi5kdbqv~q2g4++0_;i5}ZSbmW_;x?cgvKGr`KG<%b#!C>rrCum^WBmu` z&2n9c{LHX?X`jRBVp}MQ=gEb_@ujL0Td|Y1cMnM-68=xRe#81%H-Oay; z+Zj^F&cd#$DrZe~B@RWwp(ta-51`iNz-bfAaydtZpXeRZ#{q2$^D9cYW{JnN%sbyX z%Zmphsjjfm9kv-FnE0#+m|f-I^Eb@r!FyJ4$&zW~4=|lD`WHE#hhQuD8H-K?Q6oPe zg?T1vK>tCF*FLcw-37X2d^D2(pHMscb^!t7I698}>hrkHn{nJkVbA}AH`1m z+?Curdzs-AP@l<7bZ>1!pb5}W(1eOzK)6-|r50)6p}`T_2i{ z%b{Rb62hm8wW0`YHht}~O%crTIN5rqmzUn`=Eplv(l;=zOlTtL4?#1jfq$!}e=B-d zBf!MCNZOA6Ku%_U0a9b0e&c1;?QbXLG&e|YanD?dLLS!?d%f8;xrkU?7d{8qH=y7D zM$Cs)o*?xdrxReT0edJ%ULjJGT=k6YqPAM3(L`$U%+J{8qYeFeXl8VspI~h7Ae41u zbdTcXiDg%FK}iK8nwk{A5mjYGOS~s0J~T!&l@o(Qd^h|)NBc828aI}ddF)QMEM0_M z2;y;l$GGm{7(YL7eAKeEy6Q^S)K-B8hav;KdOR{}nc9b!)UeE5hRqmjv?2KKeP=ix z88Y3_-DS72<*NCtnp{?o&}e{66%ZH#V(&v*|N znNARMk-Lu36A}Kj{31o>nF|l87G-FX^OB_SklL>~at`wHGQRKEN6LwEL0EQyJvIkV zuegRaE;ouubazE^%+F?o*@cn}d#S6FuO4`ZBZKDNlS^$1pIWkj3cC%bqUerF6@?>x zW8+tqIE?dxIc3f<=a2Rb;xGivVF=f)m&~EWZeFFq5taY<;xV3myK_`4&}NJU+KiT< zVvG|i3e2l^@SVS0&dP;3mm5z9LY!N12pX@*ImjzQeyu#o#1i4$e#fD4UK?VZW80Pj z_?Y)<>J0Hqw6JWW#`%=w=V4Xl8}0jf_{bspwZc!o*~xdGJ4&QKmK42&nM^_$m9$Bd z$}$^Y|LjsKT<6X5I*CMLU@CwESfqyM{;T9*K>Kzo5KC?}{2NyoD8|W8$<&2XGkf?j1ILd~czpiPEOeMxGqxKp zkw|7X3MT#Twt*MUn{A7)V2#Vo+XLOa-WTCFT_<^} z^Rzw-nx})%kI$XU>Z&T@szyxFu%QuC_3q^>9cN9isV;HgPy|BL{Z1ZbHlu;8jf>OKS_BC_(+3!x}RnF(%jPSxABh)RaVB;lju3S;c1q)pqI6lZP zTh9t|yLRdA5%Jbz&15W12@OQK{M{GEn3ELZ8F@}g33o19h(l2j zs3@u+rf4W=#5LG^*4z$qQF$pPilRH+H%w?MEPVXEak7V-SI(x^PvyVf_YdJd{&=V_ACJ(J;Za2*k(@&m0PWJ-o0yoTNTc}kMT>Ad>^Ov=L`igM z^{(pP&Io5smd629I_<_jzNy!eO6xJbUGI15o0=OFAt`%4!ChBopA{Y_QNaJ~!gip+wYfOBkW`3QDfZoR{Nj({_5~VBsfj+qr2?!ky?({h!jA{dB~V) zQg!w1k@%Y18qk+Mjb|+*m3BMzbLXX6eL_i^y^N?T+YTMEy!IkbdCFGMmfiwXD9^I- z(Qgk&=pKwE1u!{_Y*UzDRl>3yW-(ca0$X2bzRdglcQ0!hZz2+jWcp!gClar_Eg19F z`x%Faj&<(p)DpGiiVt1X{_Dtb`eN3rMTB7^SYn7@Vl2?92$s3Ci`b9$9!sw6&0ODm z&5CguGH(aG!3Wkfjpt&CL^8d}X(%^xd3^xAJCyhM;OdG>oI>CfiLpOjh~Dn*;jyD9 za~7z?mY6KjUk*bM6_I@g`t8$w?A(7g+4@V0piOs+UjVJZb*nn)oRN+gn* zLtgH%hOf9a0yLHG`Bebj%}iGB!^ejPaVQFkreV`GVw%Rmo?iaxkLJ6*rE^)0?jsOD zGdx5KbT2iw90CaN`r5=5J(9%2c&W_XU@9Q&GehA+0>*w>Y|AC%Z_9b%wcB9*y7{5!*1UqdC zE35Ns#eM0?1ME4{opfzA64!WUUuU*Ul1@Bd`i2xgiR6QV&=Sq8aZvHnuN%-rv!de0 z#9!Vuo@!79uXT1M{pn%it1sm@P_Sj?LjK}{g?a|b7NFkp`{S8j{vr78D8GOSUxTP* z_yL3qXO&awuyf#aKYfF0GJj=sIi3(Ijj#O6<>6v(q(mZ_c@(uPT<^7?2vqF;O$!#= z&%M&srHfP{1rmD8PfObdGa-ZyrI3_h|C#=5D_Giq##g^~d9a{FB@)SbL($t}_HO)m z1Zb)XJ{dq?8dlV{c{XDf7%i!LfG&oE@d)fKeg=<)uc)Y@TN>gBL0yw}xNXffJ>>t6rIb^hOfNs6CDA{k9lv%vW>`^lX? zp^0XpvN_i*uu$QpPp)TSc}d0?px{G4d4-;#SU$7BQK8b*_V-sePkQAf63L8Z(prG& zocY*Iq0=9~(GT249^-?L9y+NTF{iy+4xFNUIJX@k#_}~OeiDf!7w4n}n901BXPbm3 z8igv{W-UOW2_E@~kE`Z-0NB^r$6Zgh(K8qy-SQjV0&EqUXnga&^`UcKA&EpXBbgEb z1epK$b6%l}CZVy#OaM_~b#*0G4m+x z7aC3PeBs*gRF_*Kk<47CjQ|2H`L7o|LZwk?;(iMOY!w \ No newline at end of file diff --git a/packages/website-next/public/qrcode.inula.jpg b/packages/website-next/public/qrcode.inula.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f853b30799af1b418553713b3e6db076657450d0 GIT binary patch literal 8152 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 YfYlM9UJh-?H@O#+eE+{}vVzzD1 \ No newline at end of file diff --git a/packages/website-next/public/window.svg b/packages/website-next/public/window.svg new file mode 100644 index 00000000..b2b2a44f --- /dev/null +++ b/packages/website-next/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/website-next/src/app/api/core/page.mdx b/packages/website-next/src/app/api/core/page.mdx new file mode 100644 index 00000000..6a69239f --- /dev/null +++ b/packages/website-next/src/app/api/core/page.mdx @@ -0,0 +1,1804 @@ +# Inula + +## 组件 + +组件是构建用户界面(UI)的基础,是可重用和独立的代码单元。开发者可以将相关功能、状态以及模板封装在组件中,提高可复用性,使得程序开发具备模块化和可维护特性。 + +### Component + +**功能介绍** + +`Component` 是类组件的基础形式,可以通过继承 `Component` 组件来定义一个类组件,并且使用类的特性,如构造函数、生命周期以及内部状态。 + +**组件定义** + +```jsx +class Component { + props: P; + context: C; + state: S | null; + refs: any; + forceUpdate: any; + isReactComponent: boolean; + constructor(props: P, context: C); + setState(state: S, callback?: Callback): void; +} +``` + +- `props`:组件接收的输入属性; +- `context`:组件的上下文对象; +- `state`:组件内部的状态; +- `refs`:用于引用组件中的 DOM 元素或其他组件; +- `forceUpdate`:用于强制重新渲染组件; +- `isReactComponent`:用于标识当前类是否是 React 组件类; +- `constructor(props: p, context: c)`:构造函数用于初始化组件的状态和属性; +- `setState(state: S, callback?: Callback): void`:用于更新组件的状态,并触发重新渲染。 + +**示例** + +```jsx +import * as Inula from 'openinula'; + +class Counter extends Inula.Component { + constructor(props) { + super(props); + this.state = { + counter: 0 + }; + console.log('Constructor'); + } + + componentDidMount() { + console.log('Component Did Mount'); + } + + componentDidUpdate() { + console.log('Component Did Update'); + } + + componentWillUnmount() { + console.log('Component Will Unmount'); + } + + handleIncrement = () => { + this.setState(prevState => ({ + counter: prevState.counter + 1 + })); + }; + + render() { + console.log('Render'); + return ( +
+

Counter: {this.state.counter}

+ +
+ ); + } +} + +Inula.render( + , + document.getElementById('root') +); +``` + +在上述示例中,基于 `Component` 组件类创建了一个 `Component` 组件以实现计数器功能,并在组件内部测试了一些声明周期的钩子函数。 + +### PureComponent + +**功能介绍** + +`PureComponent` 类继承自 `Component`,但是它内置了 `shouldComponentUpdate` 方法,会自动比较 `props` 和 `state` 的变化,如果没有变化则不会重新渲染组件,从而提高性能。 + +**组件定义** + +```jsx +class PureComponent extends Component { + constructor(props: P, context: C); +} +``` + +**示例** + +```jsx +import Inula, { PureComponent } from 'openinula'; + +// 创建一个继承自PureComponent的组件 +class App extends PureComponent { + render() { + console.log('Render PureDemo'); + return
{this.props.value}
; + } +} +``` + +上述示例中,基于 `PureComponent` 类创建了一个 `App` 组件,其使用上与 `Component` 类组件类似,但是其内置了 `shouldComponentUpdate` 方法,可以直接使用。 + +> 提示:在实际开发中,可以根据其优缺点,选择使用 `Component` 和 `PureComponent` 两种常用组件类 + +| 组件 | 优点 | 缺点 | +| ------------- |----------------------------------|--------------------------------------------------------| +| `PureComponent` | 1.自带浅比较,提高性能
2.适用于大多数情况 | 1.复杂的数据结构可能产生错误或者性能问题
2.对简单组件来说内置方法可能会存在额外开销 | +| `Component` | 1.较为灵活,没有内置方法,可以细粒度控制
2.适用于多控制场景 | 需要手动编写 `shouldComponentUpdate` 方法 | + +### memo + +**功能介绍** + +`memo` 是一个高阶组件(HOC),用于封装函数组件,以使其仅在其 `props` 发生更改时重新渲染。 + +**组件定义** + +```jsx +const MemoizedComponent = memo(type, compare?: Function); +``` + +- `type`:表示需要被优化的函数式组件; +- `compare`:可选参数,用于比较前后两次渲染的属性和状态是否相同的比较函数。如果未提供该函数,默认使用浅层比较。 + +**示例** + + +```jsx +import { memo, useState, render } from 'openinula'; + +const ExpensiveComponent = ({ value }) => { + // 模拟一个昂贵的计算 + const expensiveCalculation = () => { + console.log("Calculating..."); + let result = 0; + for (let i = 0; i < value * 1000000; i++) { + result += i; + } + return result; + }; + + const result = expensiveCalculation(); + + return
Result: {result}
; +}; + +const MemoizedExpensiveComponent = memo(ExpensiveComponent); + +function App() { + const [count1, setCount1] = useState(1); + const [count2, setCount2] = useState(1); + + return ( +
+ + + +
+ ); +} +render( + , + document.getElementById('root') +); +``` + + +在上述示例中,`` 是一个昂贵的计算组件,它在每次渲染时都会执行昂贵的计算操作。通过使用 `memo`,可以对 `` 进行优化,避免在 `count1` 没有变化时重新渲染。`memo` 会对前后两次渲染的属性和状态进行浅层比较,如果相同则不会重新渲染。 + +### Fragment + +**功能介绍** + +`` 是一个虚拟组件,用于包裹一组元素而不添加额外的 DOM 元素,可以提高渲染性能并减少不必要的包装元素。它可以用来解决在渲染多个元素时产生的包裹元素问题。在一些情况下,如果你不使用 ``,可能会出现额外的 DOM 层次结构,从而可能影响性能和样式。 + +**示例** + + +```jsx +import Inula, { Fragment, render } from 'openinula'; + +function App() { + return ( +
+ {/* 使用 Fragment */} + +
Element 4
+
Element 5
+
Element 6
+
+ + {/* 或者使用简化形式,使用空尖括号 */} + <> +
Element 7
+
Element 8
+
Element 9
+ +
+ ); +} +render( + , + document.getElementById('root') +); +``` + + +在上面的示例中,你可以看到 `` 的用法。当需要在组件中渲染多个元素时,使用 `` 可以避免添加额外的 DOM 元素。除了使用完整的 `` 标签外,你还可以使用空尖括号的简化形式 `<>` 和 ``。 + +### Children + +**功能介绍** + +`Children` 用于处理组件的子元素。它允许开发者在组件中访问和操作传递给组件的子元素,无论子元素是什么类型(单个元素、多个元素、文本等)。`Children` 提供了一些方法来遍历、映射和操作子元素,使得操作子元素变得更加方便。 + +**示例** + +```jsx +import Inula, { Children, cloneElement, render } from 'openinula'; + +// 示例 1: 遍历子元素并输出它们的类型 +function ElementList({ children }) { + const childArray = Children.toArray(children); + + const childTypes = childArray.map((child, index) => ( +

Child {index + 1} is of type: {child.type.name}

+ )); + + return
{childTypes}
; +} + +// 示例 2: 映射子元素并添加额外的 props +function AddPropsToChildren({ children }) { + const enhancedChildren = Children.map(children, (child) => { + return cloneElement(child, { isHighlighted: true }); + }); + + return
{enhancedChildren}
; +} + +// 示例 3: 只渲染特定类型的子元素 +function OnlyRenderCertainChildren({ children }) { + const filteredChildren = Children.toArray(children).filter(child => { + return child.type === 'p'; + }); + + return
{filteredChildren}
; +} + +function App() { + return ( +
+ +

Heading

+

Paragraph 1

+

Paragraph 2

+
Div element
+
+ + + Child 1 + Child 2 + + + +

Paragraph 1

+
Div element
+

Paragraph 2

+
+
+ ); +} +render( + , + document.getElementById('root') +); +``` + +上述展示了的示例包含以下方法: + +- `Children.map(children, fn, thisArg?)` +- `Children.forEach(children, fn, thisArg?)` +- `Children.only(children)` +- `Children.toArray(children)`。 + +在上面的示例中,展示了如何使用 `Children` 对子元素进行遍历、映射和筛选。`Children.toArray` 方法用于将子元素转换为数组,从而可以使用数组的方法。`Children.map` 方法可以映射子元素并为其添加额外的 `props`。同时还演示了如何通过 `child.type` 来识别子元素的类型,从而选择性地渲染特定类型的子元素。 + +### Suspense + +**功能介绍** + +``是一个组件,用于在异步加载数据时展示一个 fallback 视图 + +**接口定义** + +```tsx +}> + + +``` + +- `fallback`: 用于定义在组件加载期间显示的 fallback 视图; +- ``: 表示需要异步加载的组件。 + +**示例** + + +```jsx +import Inula, { lazy, Suspense } from 'openinula'; + +// 异步加载组件 +const AsyncComponent = lazy(() => import('./AsyncComponent')); + +const App = () => ( +
+ {/* 在加载异步组件时显示fallback元素 */} + Loading...
}> + +
+ +); + +// 组件可以是一个普通的函数式组件或类组件 +export default AsyncComponent = () => { + // 随意模拟一个异步加载的操作 + setTimeout(() => { + console.log('AsyncComponent is loaded.'); + }, 2000); + + return
Async Component
; +}; +``` + +在上面的示例中,使用 [lazy](#lazy) 函数来异步加载一个组件 ``。然后,使用 `` 组件来包裹异步组件,并在加载组件时显示 fallback 元素。在这个示例中,“fallback ...” 文本。 + +## 钩子函数 + +在 openInula 中,可以使用钩子函数来在函数组件中添加状态和其他特性函数,从而允许我们在函数组件中使用类组件拥有的功能。通过使用钩子函数,我们可以更方便地编写和管理React组件的状态和行为,使代码更简洁、可读性更高。 + +钩子函数可以让我们在函数组件中使用状态管理、生命周期方法、副作用等功能。常用的钩子函数包括 `useState`、`useEffect`、`useContext`、`useReducer` 等。 + +> 注意: +> 1. 只能在组件的顶层或自己的 Hook 中调用钩子函数。 +> 2. 不能在循环语句或条件语句中调用钩子函数。 + +### useState + +**功能介绍** + +`useState` 是一个用于在函数组件中添加状态( `state` )的钩子函数。使用 `useState` 可以让函数组件拥有类组件的状态管理能力。 + +**接口定义** + +```jsx +const [state, setState] = useState(initialState); +``` + +- `initialState`:状态的初始值,在组件挂载时使用。 + +`useState` 的返回值: + +- `state`:表示当前状态的值; +- `setState`:用于更新状态的函数,可以传递新的状态值或一个函数来计算新的状态值。 + +**示例** + +```jsx +import Inula, { useState, render } from "openinula"; + +function Counter() { + const [count, setCount] = useState(0); + + const increment = () => { + setCount(prevCount => prevCount + 1); + }; + + const decrement = () => { + setCount(prevCount => prevCount - 1); + }; + + return ( +
+

Count: {count}

+ + +
+ ); +} +render( + , + document.getElementById('root') +); +``` + +### useCallback + +**功能介绍** + +`useCallback` 是一个用于优化性能的钩子函数,它可以用来缓存函数引用,避免在每次渲染时重新创建函数。这对于将函数作为 `props` 传递给子组件时特别有用,可以避免不必要的重新渲染。 + +**接口定义** + +```tsx +const cachedFn = useCallback(callback: T, deps: DependencyList) +``` + +- `callback`:要缓存的回调函数; +- `deps`:一个数组,包含了所有可以作为依赖项的值,当依赖项发生变化时,`callback` 函数会被重新创建。如果依赖项列表为空,那么每次渲染都会返回相同的缓存函数。 + +`useCallback`的返回值: + +- `cachedFn`:若是初次渲染,返回已传入的 `callback` 函数,当依赖项 `deps` 无变化时,返回上次渲染缓存的 `callback` 函数,当依赖项 `deps` 有变化时,则返回这次渲染传入的 `callback` 函数。 + +**示例** + +```jsx +import Inula, { useState, useCallback, render } from 'openinula'; + +function App() { + const [count, setCount] = useState(0); + + // 使用 useCallback 缓存 handleIncrement 函数 + const handleIncrement = useCallback(() => { + setCount(count + 1); + }, [count]); // 仅当 count 发生变化时,才会重新创建函数 + + return ( +
+

Count: {count}

+ +
+ ); +} +render( + , + document.getElementById('root') +); +``` + + +> 注意:使用 `useCallback`,可以确保每次渲染时都使用相同的函数引用,从而减少不必要的函数重新创建,提高性能。这在传递回调函数给子组件或在使用 `useEffect` 时尤为有用,因为它可以防止因为函数的重新创建而导致子组件的不必要重新渲染。 + +### useContext + +**功能介绍** + +`useContext` 用于在组件之间共享状态。通过使用 `useContext`,可以避免在组件树中手动传递 `props`,从而更方便地访问共享的数据。 + +**接口定义** + +```tsx +const value = useContext(context: Context) +``` + +- `context`:是 openInula 提供的上下文,可以通过 `createContext` 创建,`useContext` 接收上下文并返回该上下文当前值。 + +`useContext`的返回值: + +- `value`:其返回值是一个包含Provider的值,其中 `value.Provider` 是由最近的上层上下文提供,如果没有找到匹配的上层上下文,则会使用上下文对象的默认值。 + +**示例** + +```jsx +import Inula, { createContext, useContext, useState, render } from 'openinula'; + +// 创建一个上下文对象 +const Context = createContext(); + +// 组件A:向上下文中提供一个共享的数据 +const ComponentA = () => { + const [count, setCount] = useState(0); + + return ( + + + + + ); +} + +// 组件B:从上下文中获取共享的数据 +const ComponentB = () => { + const count = useContext(Context); + return
当前计数:{count}
; +} + +// 主组件 +const App = () => { + return ; +} +render( + , + document.getElementById('root') +); +``` + +在这个示例中,`` 创建了一个共享的数据 `count`,它使用 `useState` 来进行状态管理,并将数据存储在上下文对象` Context.Provider` 中。`` 使用 `useContext` 从 `Context` 中获取共享的数据 `count`。最后,`` 组件作为根组件渲染 ``,这样就能够在整个组件树中共享 `count` 数据。 + +> 说明:在函数组件中,`useContext` 代替了类组件中的 `Consumer`。 + +### useEffect + +**功能介绍** + +`useEffect` 是一个用于处理副作用(如数据获取、订阅、DOM 操作等)的钩子函数。它在组件的生命周期中执行,并且可以用于在组件渲染后执行一些操作,或在组件卸载前执行一些清理工作。 + +**接口定义** + +```tsx +useEffect(create: EffectCallBack, deps?: DependencyList): void +``` + +- `create`:一个函数,用于定义副作用操作。该函数在每次渲染后都会被调用; +- `deps`:一个数组,指定了哪些依赖项的变化会触发 `create` 的重新执行。如果不传递这个数组,那么 `create` 将在每次渲染后都被调用。如果依赖项列表为空,那么 `create` 将只在组件挂载和卸载时执行。 + +**示例** + +- 示例一 + +```jsx +import Inula, { useState, useEffect, render } from "openinula"; + +function App() { + const [count, setCount] = useState(0); + + useEffect(() => { + document.title = `点击次数:${count}`; + }, [count]); + + return ( +
+

点击次数: {count}

+ +
+ ); +} +render( + , + document.getElementById('root') +); +``` + +在上述示例中,`useEffect` 可以用于数据的获取,当点击 ` + + ); +} +render( + , + document.getElementById('root') +); +``` + +在示例二中,`useEffect` 可以用于设置和清理定时器。 + +- 示例三: + +```jsx +useEffect(() => { + // 更新元素样式 + document.getElementById('myElement').style.color = 'red'; + + // 添加元素 + const newElement = document.createElement('div'); + document.body.appendChild(newElement); + + // 移除元素 + return () => { + document.body.removeChild(newElement); + }; +}, []); +``` + +上述示例展示 `useEffect` 的DOM操作,可以在 `useEffect` 中进行DOM操作,比如更新元素的样式、添加/移除元素等。 + +- 示例四: + +根据依赖项的变化,`useEffect` 的行为会有所不同。在函数组件中,通常使用 `useEffect` 来模拟组件的生命周期。 + +```jsx +useEffect(() => { + // componentDidMount + console.log('Component mounted'); + + // componentDidUpdate + return () => { + // componentWillUnmount + console.log('Component unmounted'); + }; +}, []); + +useEffect(() => { + // componentDidUpdate + console.log('Component updated'); +}, [data]); +``` + +上述示例中,使用 `useEffect `来模拟组件的生命周期方法,比如 `componentDidMount`、`componentDidUpdate` 和 `componentWillUnmount`。 + +### useLayoutEffect + +**功能介绍** + +`useLayoutEffect` 是一个钩子函数,用于在 DOM 更新完成后同步执行副作用操作。与 `useEffect` 不同,`useLayoutEffect` 会在 DOM 更新之后、浏览器绘制之前同步执行,因此适用于需要立即操作 DOM 的情况。 + +**接口定义** + +```jsx +useLayoutEffect(create: EffectCallBack, deps?: DependencyList): void; +``` + +- `create`:一个函数,用于定义副作用操作。该函数会在 DOM 更新完成后、浏览器绘制之前立即执行; +- `deps`:一个数组,指定了哪些依赖项的变化会触发 `create` 的重新执行。如果不传递这个数组,那么 `create` 将在每次渲染后都被调用。如果依赖项列表为空,那么 `create` 将只在组件挂载和卸载时执行。 + +**示例** + +```jsx +import Inula, { useState, useLayoutEffect, render } from 'openinula'; + +function App() { + const [width, setWidth] = useState(0); + + useLayoutEffect(() => { + const handleResize = () => { + setWidth(window.innerWidth); + }; + + window.addEventListener('resize', handleResize); + handleResize(); // 初始渲染时执行一次 + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); // 仅在挂载和卸载时执行 + + return ( +
+

Window Width: {width}

+
+ ); +} +render( + , + document.getElementById('root') +); +``` +在上述示例中,`useLayoutEffect` 用于更新页面上窗口的宽度。它添加了一个 `resize` 事件监听器,在窗口大小变化时同步更新 `width` 状态。注意,这里使用了空数组作为依赖项,这意味着 `useLayoutEffect` 只在组件挂载和卸载时执行。 + +> 注意: +> `useEffect` 和 `useLayoutEffect` 都用于在组件渲染时执行副作用操作,但是主要区别与执行的时机。`useEffect` 会在组件渲染完成后异步执行,不会阻塞组件的渲染过程。而 `useLayoutEffect` 会在组件渲染完成后同步执行,会阻塞组件的渲染过程。因此,如果需要在组件渲染完成后立即执行某些操作,可以使用 `useLayoutEffect`,否则可以使用 `useEffect`。 + +```jsx +import Inula, { useState, useEffect, useLayoutEffect, render } from 'openinula'; + +const App = () => { + const [count, setCount] = useState(0); + + useEffect(() => { + console.log('useEffect'); + document.title = `Count: ${count}`; + }, [count]); + + useLayoutEffect(() => { + console.log('useLayoutEffect'); + document.title = `Count: ${count}`; + }, [count]); + + return ( +
+

Count: {count}

+ +
+ ); +}; +render( + , + document.getElementById('root') +); +``` + +在上面的例子中,若使用 `useEffect` 来更新页面标题,它会在组件渲染完成后执行,并且只有在 `count` 发生变化时才会执行。若使用 `useLayoutEffect` 来更新页面标题,它会在组件渲染完成后立即执行,并且只有在 `count` 发生变化时才会执行。 + +> 注意: +> 由于 `useLayoutEffect` 是同步执行的,如果操作的是 DOM,可能会影响页面性能。在大多数情况下,使用 `useEffect` 就足够了,因为它会在 DOM 更新完成后异步执行副作用,不会阻塞浏览器的渲染。只有在需要即时操作 DOM 以获取测量值等情况下,才考虑使用 `useLayoutEffect`。 + +### useMemo + +**功能介绍** + +`useMemo` 是一个用于性能优化的钩子函数,它用于在组件重新渲染时,缓存和返回一个计算结果,以避免不必要的重复计算。 + +**接口定义** + +```jsx +const cachedValue = useMemo(create, deps) +``` + +- `create`:一个函数,用于计算需要缓存的值; +- `deps`:一个数组,指定了哪些依赖项的变化会触发 `create` 的重新执行。当依赖项发生变化时,`create` 将会被重新执行,返回一个新的缓存值。如果依赖项列表为空,那么` create` 只在组件挂载时执行。 + +`useMemo` 的返回值: + +- `cachedValue`:要缓存计算值的函数,可以为任意类型,如果 `deps` 没有发生变化,会直接返回相同的值,如果 `deps` 发生变化,则调用 `create`,并返回新的结果,然后缓存这个结果。 + +**示例** + +```jsx +import Inula, { useState, useMemo, render } from 'openinula'; + +function ExpensiveComponent({ number }) { + // 模拟一个昂贵的计算 + const expensiveCalculation = () => { + console.log("Calculating..."); + let result = 0; + for (let i = 0; i < number * 1000000; i++) { + result += i; + } + return result; + }; + + // 使用 useMemo 缓存计算结果 + const memoizedValue = useMemo(() => expensiveCalculation(), [number]); + + return ( +
+

Number: {number}

+

Calculated Value: {memoizedValue}

+
+ ); +} + +function App() { + const [count, setCount] = useState(1); + + return ( +
+ + +
+ ); +} +render( + , + document.getElementById('root') +); +``` + +在这个示例中,`ExpensiveComponent` 组件包含一个昂贵的计算操作,该计算在每次渲染时都会执行。通过使用 `useMemo`,可以缓存计算结果,只有在 `number` 发生变化时才重新计算。这可以有效避免在每次渲染时都执行昂贵的计算,从而提高性能。 + +> 注意:`useMemo` 可以在性能优化方面发挥作用,但不应该被滥用。在某些情况下,过度使用 `useMemo` 可能会导致代码更难理解。只有在确实需要避免重复计算的情况下,才应该使用 `useMemo`。 + +### useReducer + +**功能介绍** + +`useReducer` 是一个用于管理状态的钩子函数,它结合了 `useState` 和自定义的状态更新逻辑,通常用于管理复杂的状态逻辑。 + +**接口定义** + +```jsx +const [state, dispatch] = useReducer(reducer, initialState, init?); +``` + +- `reducer`:一个函数,用于定义状态更新逻辑。它接收当前状态 state 和一个表示动作的对象 action,并返回新的状态; +- `initialState`:初始状态的值, 计算逻辑取决于 `init` 参数; +- `init`:可选参数,用于计算初始状态值的函数,如果存在,则使用 `init(initialState)` 的执行结果作为初始值,否则使用 `initialState`。 + +`useReducer` 有两个返回值: + +- `state`:当前状态的值; +- `dispatch`:一个函数,用于触发状态更新。它接收一个表示动作的对象,并将该对象传递给 `reducer`,从而更新状态 `state`。 + +**示例** + +```jsx +import Inula, { useReducer, render } from 'openinula'; + +// 定义 reducer 函数 +const counterReducer = (state, action) => { + switch (action.type) { + case 'INCREMENT': + return { count: state.count + 1 }; + case 'DECREMENT': + return { count: state.count - 1 }; + default: + return state; + } +}; + +function App() { + // 使用 useReducer 来管理状态 + const [state, dispatch] = useReducer(counterReducer, { count: 0 }); + return ( +
+

Count: {state.count}

+ + +
+ ); +} +render( + , + document.getElementById('root') +); +``` + +在上述示例中,使用了 `useReducer` 以允许通过 `dispatch` 函数触发 `state` 的更新。在需要更新状态时,可以向 `dispatch` 传递一个表示动作的对象(`action`),随后 `reducer` 函数,即 `counterReducer` 函数将根据动作类型 (`action.type`)为`INCREMENT` 还是 `DECREMENT` 更新状态 `state`。 + +> 注意:相比使用多个`useState`来管理状态,`useReducer` 适用于具有复杂状态逻辑的情况,它能够更好地组织和管理状态变化。 + +### useRef + +**功能介绍** + +`useRef` 用于创建一个引用对象,可以用来存储组件的引用或持久化的值。与 `useState` 不同,`useRef` 创建的引用对象在更新时不会触发组件重新渲染。 + +**接口定义** + +```jsx +const refContainer = useRef(initialValue); +``` + +- `initialValue`:引用对象的初始值,可以是任何值,通常设置为 `null`。 + +`useRef` 的返回值: + +- `refContainer`:一个引用对象,其中的 `current` 属性可以被用于存储和访问值。 + +**示例** + +```jsx +import Inula, { useRef, render } from 'openinula'; + +function RefDemo() { + const inputRef = useRef(null); + + const handleButtonClick = () => { + // 使用 ref 获取 input 元素的引用,并设置焦点 + inputRef.current.focus(); + }; + + return ( +
+ + +
+ ); +} +render( + , + document.getElementById('root') +); +``` + +上面的示例中,创建了一个函数组件 `RefDemo`,使用 `useRef` 钩子创建了一个名为 `inputRef` 的 `ref` 对象,并在 JSX 中将这个 `ref` 对象绑定到输入框元素上。 + +当按钮被点击时,`handleButtonClick` 函数会使用 `inputRef.current` 来获取输入框的 DOM 元素,并调用 `focus()` 方法来设置焦点。这样,点击按钮后,输入框就会自动获得焦点。 + +> 注意:`useRef` 不仅适用于获取 DOM 元素的引用,还可以在函数组件中存储和访问任意可变值。与 `state`一样,`ref` 可以指向任何东西:比如字符串、对象甚至函数。与 `state` 不同的是,`ref` 是一个带有当前属性的普通对象,可以读取和修改。 + +**存储变量** + +```jsx +import Inula, { useState, useRef, useCallback, render } from 'openinula' + +function ClickWatch() { + let ref = useRef(0); + + const handleClick = useCallback(() => { + ref.current = ref.current + 1; + alert('You clicked ' + ref.current + ' times!'); + }, []) + + return ( + + ); +} +render( + , + document.getElementById('root') +); +``` + +在上述示例中,将在每次点击后增加 `ref.current`。 + +> 注意:组件不会在每次递增时都触发重新渲染。 像 `state` 一样,`ref` 在重新渲染时被 openInula 保留。然而,`setState` 将会重新渲染组件,修改 `ref` 则不会。 + +### useImperativeHandle + +**功能介绍** + +`useImperativeHandle` 是一个用于定制在父组件中访问子组件实例方法的钩子函数。通常情况下,openInula 鼓励使用 `props` 和 `state` 来进行组件之间的通信,但在某些情况下,可能需要从父组件中直接调用子组件。 + +**接口定义** + +```jsx +useImperativeHandle(ref, createHandle, deps?):void; +``` + +- `ref`:一个 `ref` 引用对象,通常通过 `createRef()` 创建; +- `createHandle`:一个函数,用于创建子组件实例中需要暴露给父组件的方法或属性; +- `deps`:可选参数,一个依赖数组,当依赖项变化时,会重新计算 `createHandle`。通常在这里指定子组件的内部状态或其他信息,以确保暴露给父组件的方法在这些依赖项变化时得到更新。 + +**示例** + +```jsx +import Inula, { useRef, useImperativeHandle, forwardRef, render } from 'openinula'; + +// 子组件 +const ChildComponent = forwardRef((props, ref) => { + const inputRef = useRef(); + + // 暴露给父组件的方法 + useImperativeHandle(ref, () => ({ + focusInput: () => { + inputRef.current.focus(); + } + })); + + return ; +}); + +// 父组件 +function App() { + const childRef = useRef(); + + const handleFocusInput = () => { + childRef.current.focusInput(); + }; + + return ( +
+ + +
+ ); +} +render( + , + document.getElementById('root') +); +``` + +在这个例子中,`` 使用 `useImperativeHandle` 来创建一个名为 `focusInput` 的方法,父组件可以通过` ref` 调用这个方法来聚焦输入框。通过这种方式,你可以在需要时从父组件中控制子组件的行为。 + +> 注意:`useImperativeHandle` 应该避免过度使用,因为它破坏了组件之间的封装性,通常情况下应该优先考虑使用 `props` 和状态来实现组件之间的通信。 + +## APIs + +### render + +**功能介绍** + +在指定的 DOM 元素下渲染 openInula 组件。 + +**接口定义** + +```tsx +function render(children: any, container: Container, callback?: any): Element | Text | null +``` + +* `children`:需要渲染的 openInula 组件; +* `container`:DOM元素,`children` 将会渲染在该元素中; +* `callback`:挂载后的回调函数。 + +**示例** + +```tsx +import { render } from 'openinula'; + +function App() { + return

hello

; +} + +render(, document.getElementById('root')); +``` + + +上述示例展示在 DOM 元素 `
}> + + + +``` +- 外层和内层 Suspense 可分别控制不同异步内容的 loading 状态。 + +## 错误处理 + +- 异步加载失败时可结合 ErrorBoundary 捕获错误。 +- lazy 组件必须返回 Promise,resolve 时需有 default 导出。 + +## 注意事项 + +- Suspense 只对 lazy 组件生效。 +- fallback 必须为有效的 React 元素。 +- 支持多层嵌套,内层优先显示 fallback。 + +## 最佳实践 + +- 推荐为每个异步区域单独设置 Suspense,提升用户体验。 +- fallback UI 应简洁明了。 + +## 相关链接 + +- [React Suspense](https://react.dev/reference/react/Suspense) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/components/composition/page.mdx b/packages/website-next/src/app/docs/components/composition/page.mdx new file mode 100644 index 00000000..aff7a5dc --- /dev/null +++ b/packages/website-next/src/app/docs/components/composition/page.mdx @@ -0,0 +1,120 @@ +--- +id: composition +title: 组件组合 +sidebar_label: 组件组合 +--- + +# 组件组合 + +组件组合是构建复杂 UI 的基础。openInula 2支持多种组合模式,包括容器组件、复合组件、插槽(children)、高阶组件等。 + +## 容器组件与展示组件 + +将逻辑与展示分离,提升复用性。 + +```tsx filename="UserCardAndList.jsx" +// 展示组件 +function UserCard({ user }) { + return ( +
+

{user.name}

+

邮箱:{user.email}

+
+ ); +} + +// 容器组件 +function UserList({ users }) { + return ( +
+ + {(user) => } + +
+ ); +} +``` + +## 插槽(children) + +通过 `children` 实现灵活的内容插入。 + +```tsx filename="PanelWithSlot.jsx" +function Panel({ title, children }) { + return ( +
+

{title}

+
{children}
+
+ ); +} + +function App() { + return ( + +

这是插槽内容

+ +
+ ); +} +``` + +## 复合组件模式 + +将多个子组件组合为一个整体。 + +```tsx filename="TabsComponent.jsx" +function Tabs({ children }) { + // 省略 tab 切换逻辑 + return
{children}
; +} + +function Tab({ label, children }) { + return ( +
+

{label}

+
{children}
+
+ ); +} + +function App() { + return ( + + 内容A + 内容B + + ); +} +``` + +## 高阶组件(HOC) + +高阶组件用于复用逻辑或增强组件功能。 + +```tsx filename="HigherOrderComponent.jsx" +function withLogger(Component) { + return function Wrapper(props) { + console.log('props:', props); + return ; + }; +} + +const LoggedPanel = withLogger(Panel); +``` + +## 最佳实践 + +- 组件应职责单一,便于组合和复用 +- 善用 children 和 props 传递内容和行为 +- 复合组件可提升灵活性 + +## 注意事项 + +- 避免过度嵌套,保持结构清晰 +- 插槽内容建议通过 children 传递 + +## 相关链接 + +- [Props 传递](./props) +- [上下文](./context) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/components/context/page.mdx b/packages/website-next/src/app/docs/components/context/page.mdx new file mode 100644 index 00000000..e7e58765 --- /dev/null +++ b/packages/website-next/src/app/docs/components/context/page.mdx @@ -0,0 +1,90 @@ +--- +id: context +title: 上下文 +sidebar_label: 上下文 +--- + +# 上下文(Context) + +openInula 2(zouyu)支持类似 React 的 Context 机制,用于在组件树中跨层级传递数据,避免 props 层层传递。Context 机制包括 Provider(提供者)和 Consumer(消费者),并且支持响应式更新。 + +## 基本用法 + +### 1. 创建 Context + +```tsx filename="createContext.jsx" +import { createContext } from 'openinula'; + +const UserContext = createContext({ level: 0, path: '' }); +``` + +### 2. Provider(提供者) + +通过将 context 作为组件标签包裹子组件,并传递属性来提供数据: + +```tsx filename="ContextProvider.jsx" +function App() { + let level = 1; + let path = '/home'; + return ( + + + + ); +} +``` + +- context 属性可以是任意响应式变量,变化时会自动通知所有消费组件。 + +### 3. Consumer(消费者) + +在子组件中通过 `useContext` 获取 context 数据: + +```tsx filename="ContextConsumer.jsx" +import { useContext } from 'openinula'; + +function Child() { + const { level, path } = useContext(UserContext); + return
{level} - {path}
; +} +``` + +- 解构 useContext 返回的对象即可获得 context 的所有属性。 +- context 属性变化时,消费组件会自动响应更新。 + +## 响应式原理 + +- context 属性是响应式的,父组件更新属性,所有 useContext 的子组件会自动重新渲染。 +- 编译器会自动为每个属性生成依赖追踪和更新函数。 + +## 只消费部分属性 + +可以只消费 context 的部分属性,只有被消费的属性变化时才会触发更新。 + +```tsx filename="PartialContextConsumer.jsx" +function OnlyLevel() { + const { level } = useContext(UserContext); + return {level}; +} +``` + +## 多层嵌套与多 context + +可以嵌套多个 context,useContext 会自动查找最近的 Provider。 + +## 最佳实践 + +- 用于全局配置、用户信息、主题等场景 +- 避免频繁变化的小数据放入 context +- 推荐解构useContext返回值,帮助响应式系统能够只在对应 key 更新时,仅更新对应 value 的消费组件,提升性能 + +## 注意事项 + +- context 属性必须通过 Provider 传递,且应为响应式变量 +- useContext 只能在函数组件中调用 +- context 变化会导致所有消费组件重新渲染 + +## 相关链接 + +- [组件组合](../composition) +- [官方测试用例参考](https://github.com/openinula/openinula/blob/main/next-packages/compiler/babel-inula-next-core/test/e2e/context.test.tsx) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/components/props/page.mdx b/packages/website-next/src/app/docs/components/props/page.mdx new file mode 100644 index 00000000..f7c2de62 --- /dev/null +++ b/packages/website-next/src/app/docs/components/props/page.mdx @@ -0,0 +1,125 @@ +--- +id: props +title: Props 传递 +sidebar_label: Props 传递 +--- + +# Props 传递 + +在 openInula 2(zouyu)中,props 用于父组件向子组件传递数据和回调函数,语法与 React 类似,但更贴近原生 JS。 + +## 基本用法 + +```tsx filename="Welcome.jsx" +function Welcome({ name }) { + return

你好,{name}!

; +} + +function App() { + return ; +} +``` + +## 默认值与解构 + +可以为 props 设置默认值,并使用解构赋值: + +```tsx filename="UserProfile.jsx" +function UserProfile({ name = '匿名', age = 0 }) { + return ( +
+

姓名:{name}

+

年龄:{age}

+
+ ); +} +``` + +## 传递回调函数 + +父组件可以通过 props 向子组件传递事件处理函数,实现子组件向父组件通信: + +```tsx filename="CounterWithCallback.jsx" +function Counter({ onIncrement }) { + return ; +} + +function App() { + let count = 0; + function handleIncrement() { + count++; + } + return ( +
+

计数:{count}

+ +
+ ); +} +``` + +## 传递对象和数组 + +可以直接传递对象、数组等复杂数据类型: + +```tsx filename="TodoList.jsx" +function TodoList({ todos }) { + return ( +
    + + {(todo) =>
  • {todo.text}
  • } +
    +
+ ); +} + +function App() { + let todos = [ + { text: '学习 OpenInula' }, + { text: '写文档' } + ]; + return ; +} +``` + +## children 插槽 + +通过 `children` 实现插槽功能: + +```tsx filename="PanelWithChildren.jsx" +function Panel({ title, children }) { + return ( +
+

{title}

+
{children}
+
+ ); +} + +function App() { + return ( + +

这是插槽内容

+
+ ); +} +``` + +## 最佳实践 + +- 使用解构赋值提升代码可读性,并帮助响应式系统能够只在对应 props key 更新时,更新组件 +- 为 props 设置合理的默认值 +- 只传递必要的数据,避免 props 过多 +- 通过回调函数实现父子通信 + +## 注意事项 + +- props 是只读的,不要在子组件内部修改 props +- children 也是 props 的一部分 +- 复杂数据建议使用不可变数据结构 + +## 下一步 + +- 学习[组件组合](../composition)的高级用法 +- 了解[上下文](../context)的全局数据传递 +- 探索[生命周期](../lifecycle/mounting)的管理 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/conventional/CodeOfConduct/page.mdx b/packages/website-next/src/app/docs/conventional/CodeOfConduct/page.mdx new file mode 100644 index 00000000..ae57632e --- /dev/null +++ b/packages/website-next/src/app/docs/conventional/CodeOfConduct/page.mdx @@ -0,0 +1,53 @@ +--- +sidebar_position: 6 +--- + +我们有一份 openinula 代码贡献行为准则,希望所有的贡献者都能遵守,请花时间阅读一遍全文以确保你能明白哪些是可以做的,哪些是不可以做的。 + +openinula代码贡献行为准则遵守开源社区[《贡献者公约》](https://contributor-covenant.org/) V1.4 中规定的行为守则,请参考[V1.4版本](https://www.contributor-covenant.org/zh-cn/version/1/4/code-of-conduct.html) + +如需举报侮辱、骚扰或其他不可接受的行为,您可以发送邮件至[team@inulajs.org](mailto:team@inulajs.org),联系 openinula 项目部处理。 + +## 贡献者们的承诺 + +为建设开放友好的环境,我们贡献者和维护者承诺:不论年龄、体型、身体健全与否、民族、性征、性别认同与表征、经验水平、教育程度、社会地位、国籍、相貌、种族、信仰、性取向,我们项目和社区的参与者皆免于骚扰。 + +## 我们的准则 + +有助于创造积极环境的行为包括但不限于: + +* 措辞友好且包容 +* 尊重不同的观点和经验 +* 耐心接受有益批评 +* 关注对社区最有利的事情 +* 与社区其他成员友善相处 + +参与者不应采取的行为包括但不限于: + +* 发布与性有关的言论或图像、不受欢迎地献殷勤 +* 捣乱/煽动/造谣行为、侮辱/贬损的评论、人身及政治攻击 +* 公开或私下骚扰 +* 未经明确授权便发布他人的资料,如住址、电子邮箱等 +* 其他有理由认定为违反职业操守的不当行为 + +## 我们的义务 + +项目维护者有义务诠释何谓“妥当行为”,并妥善公正地纠正已发生的不当行为。 + +项目维护者有权利和义务去删除、编辑、拒绝违背本行为标准的评论(comments)、提交(commits)、代码、wiki 编辑、问题(issues)等贡献;项目维护者可暂时或永久地封禁任何他们认为行为不当、威胁、冒犯、有害的参与者。 + +## 适用范围 + +本行为标准适用于本项目。当有人代表本项目或本社区时,本标准亦适用于此人所处的公共平台。 + +代表本项目或本社区的情形包括但不限于:使用项目的官方电子邮件、通过官方媒体账号发布消息、作为指定代表参与在线或线下活动等。 + +代表本项目的行为可由项目维护者进一步定义及解释。 + +## 贯彻落实 + +可以致信[team@inulajs.org](mailto:team@inulajs.org),向项目团队举报滥用、骚扰及不当行为。 + +维护团队将审议并调查全部投诉,妥善地予以必要的回应。项目团队有义务保密举报者信息。具体执行方针或将另行发布。 + +未切实遵守或执行本行为标准的项目维护人员,经项目负责人或其他成员决议,可能被暂时或永久地剥夺参与本项目的资格。 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/conventional/ContributingGuide/page.mdx b/packages/website-next/src/app/docs/conventional/ContributingGuide/page.mdx new file mode 100644 index 00000000..132a2839 --- /dev/null +++ b/packages/website-next/src/app/docs/conventional/ContributingGuide/page.mdx @@ -0,0 +1,142 @@ +--- +sidebar_position: 7 +--- + +本指南会指导你如何为 openInula 贡献自己的一份力量,请你在提出 issue 或 pull request 前花费几分钟来了解 openInula 社区的贡献指南。 + +## 行为准则 + +我们有一份 openInula 代码贡献[行为准则](/docs/行为准则),希望所有的贡献者都能遵守,在参与社区贡献之前,请先阅读并遵守 openInula 的[行为准则](/docs/行为准则)。 + +## 参与贡献 + +贡献代码之前,您必须签署一份“openInula贡献者协议,然后才能参与代码贡献。根据您的参与身份,选择签署个人 CLA、员工 CLA 或企业 CLA,请点击**[这里](https://gitee.com/organizations/inula-js/cla/inula-js-contributor-protocol)**签署。 + +* 个人 CLA:以个人身份参与社区,请签署个人 CLA +* 企业 CLA: 以企业身份参与社区,请签署企业 CLA +* 员工 CLA: 以企业员工的身份参与社区,请签署员工 CLA + +#### 贡献流程 + +* 我们所有的工作都会放在 [Gitee](https://gitee.com/openInula) 上。 +* 针对Git的安装、环境配置及使用方法,请参考码云帮助中心的 Git 知识大全:[https://gitee.com/help/categories/43](https://gitee.com/help/categories/43) +* openInula 长期维护 master 分支。如果你要修复一个 Bug 或增加一个新的功能,那么请 Pull Request 到 master 分支上 + +#### 参与贡献 + +openInula 团队会关注所有 Pull Request,我们会经测试与评审后合入你的代码,也有可能要求你做一些修改或者告诉你我们为什么不能接受你的修改。 + +在你发送Pull Request之前,请确认你是按照下面的步骤来做的: + +1. 确保基于正确的分支进行修改。 +2. 在项目根目录下运行了 `npm install`。 +3. 如果你修复了一个bug或者新增了一个功能,请确保新增或完善了相应的测试,这很重要。 +4. 确认所有的测试都是通过的 `npm run test` +5. 确保你的代码通过了lint检查 `npm run lint`. + +#### 贡献流程 + +1. Fork 代码分支 + + 1. 找到并打开对应 Repository 的首页; + 2. 点击右上角的 **Forked** 按钮,按照指引,建立一个属于个人的分支。 + +2. 把 Fork 仓下载到本地 + + 1. 创建本地工作目录; + ```bash + mkdir ${your_working_dir} + cd ${your_working_dir} + ``` + + 2. 复制远程仓库到本地。 + ```bash + git clone {$remote_link} + ``` + +3. 代码修改 + + 1. 根据您的想法,修复bug或者新增功能; + + 2. 推送到您的线上代码仓分支。在此之前,请确认您已完成一下步骤: + 1. 确保基于正确的分支进行修改。 + 2. 在项目根目录下运行了 `npm install`。 + 3. 如果你修复了一个 bug 或者新增了一个功能,请确保新增或完善了相应的测试,这很重要。 + 4. 确认所有的测试都是通过的 `npm run test` + 5. 确保你的代码通过了 lint 检查 `npm run lint`. + + 确认无误后即可推送 + ```bash + git push origin master + ``` + +4. 提交 Pull Request + + 1. 在代码仓首页点击 **+Pull Request**,创建一个新PR + 2. 选择分支为您修改过的分支 + 3. 补充标题与 PR 描述等信息。openInula 库提供 PR 模板,帮助您快速高效的传递 PR 的描述信息。 + 4. 确认无误后,点击**创建 Pull Request** + + 提交完毕后,请耐心等待 openInula 团队完成测试与评审流程。流程通过后,您的代码就会被合入 openInula 的代码仓中。 + + 如果你还不清楚怎么在Gitee上提交 Pull Request,你可以通过[这篇文章](https://oschina.gitee.io/opensource-guide/guide/%E7%AC%AC%E4%B8%89%E9%83%A8%E5%88%86%EF%BC%9A%E5%B0%9D%E8%AF%95%E5%8F%82%E4%B8%8E%E5%BC%80%E6%BA%90/%E7%AC%AC%207%20%E5%B0%8F%E8%8A%82%EF%BC%9A%E6%8F%90%E4%BA%A4%E7%AC%AC%E4%B8%80%E4%B8%AA%20Pull%20Request/#%E4%BB%80%E4%B9%88%E6%98%AF-pull-request)学习 + + +### 门禁构建 + +#### 创建 Issue + +1. 找到并打开对应 Repository 的首页 +2. 选择 Issues 页签。 +3. 在点击右侧 **+新建 Issue** 按钮,建立一个专属的任务,用于相关联的代码(开发特性/修改 bug)执行 CI 门禁。 + +#### 将 Issue 与 PR 关联 + +创建 PR 或编辑已有的 PR 时,描述框输入 `#I[五位 Issue ID]`,例如 `#I12345`,即可将 Issue 与 PR 关联。 + +#### 约束 +- 一个 PR 只允许关联一个 Issue,关联多个 Issue 时无法触发CI。 +- 相关特性开发或 bug 修复涉及多个代码仓联合修改时,多个 PR 可关联同一个 Issue。 +- Issue 关联的 PR 中,不允许存在已被合入或关闭的 PR,否则无法触发 CI。 +- 若 Issue 已被合入或关闭的 PR 关联,则该 Issue 无法被重复使用,需重新创建 Issue 并进行 OPEN 的 PR 关联。 +- 当你想开始处理一个 Issue 时,先检查一下 Issue 下面的留言,确保没有其他人正在处理。如果没有,你可以留言告知其他人你将处理这个 Issue,避免重复劳动。 + + +#### 触发代码门禁 + +在 PR 中评论“start build”即可触发 CI 门禁。 + +多个 PR 关联同一个 Issue 时,在任一 PR 中评论“start build”均可触发该 Issue 的 CI 门禁。 + +门禁执行完成,会在该 Issue 关联的所有 PR 中自动评论门禁执行结果。 + +如果门禁通过,该 Issue 关联的所有PR均会自动标记“测试通过”。 + +#### Bug 提交 + +我们使用 Gitee Issues 来进行 Bug 跟踪。在你发现 Bug 后,请通过我们提供的模板来提 Issue,以便你发现的 Bug 能被快速解决。 + +在你报告一个 bug 之前,请先确保不和已有 Issue 重复以及查阅了我们的用户使用指南。 + +#### 新增功能 + + 如果你有帮助我们改进 API 或者新增功能的想法,我们同样推荐你使用我们提供 Issue 模板来新建一个添加新功能的 Issue。 + +### CI 门户 + +openInula 通过持续集成(CI,Continuous Integration)及时发现代码问题,确保代码质量可靠和功能稳定,包括: + +* 代码门禁:开发者向 openInula 提交代码合入申请后,会触发门禁检查,例如静态检查、代码编译、功能测试等,门禁通过后才能合入代码。 +* 每日构建:openInula 的持续集成流水线每日自动执行,以便提前发现代码静态检查、编译、功能等方面的问题,及时修复问题,确保代码质量。 + +CI 门户是为了便于开发者及时查看、分析每日构建和代码门禁的执行结果的一个可持续集成的门户。 + +## 内容版权 + +用户提交的内容、图片必须是原创内容,不得侵犯他人知识产权。 + +对应采纳的内容,openInula 有权根据相关规范修改用户提交的内容。 + +## License + +openInula 主要遵循 Mulan Permissive Software License v2 协议,详情请参考各代码仓 LICENSE 声明。 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/conventional/FAQ/page.mdx b/packages/website-next/src/app/docs/conventional/FAQ/page.mdx new file mode 100644 index 00000000..19f2526b --- /dev/null +++ b/packages/website-next/src/app/docs/conventional/FAQ/page.mdx @@ -0,0 +1,35 @@ +--- +sidebar_position: 5 +--- + +## openInula 支持哪些浏览器? + +最新版的 openInula 支持原生支持 ES2015 的浏览器,不包括 IE 浏览器。 + +--- + +## openInula 可以扩展吗? + +是的,openInula 是一个成熟的完全的前端框架,其不仅可无缝兼容 React 框架,也可以基于 openInula 库,扩展一些生态能力: + + * inula-intl 提供了一个模块化的国际化框架,允许其和 openInula 框架配合使用 + * inula-request 提供了请求能力,允许其和 openInula 框架配合使用 + * inula-router 提供了路由能力,允许其和 openInula 框架配合使用 + +--- + +## openInula 的进入门槛如何? + +openInula 的进入门槛较低,详细的文档以及简洁的代码逻辑能减少新前端开发人员的学习成本。 + +--- + +## openInula 中应该使用 JavaScript 还是 TypeScript? + +openInula 本身是基于TypeScript实现的,提供了一流的 TypeScript 支持,但不会对您是否应该使用 TypeScript 作为用户强制执行意见。在 openInula API 实现中也尽可能在 JavaScript 与 TypeScript 进行折中选择。 + +--- + +## openInula 是轻量级的吗?性能如何? + +openInula 是轻量级的。其提供的响应式 API 性能相比与主流框架 React 的虚拟 DOM 方式,渲染效率提升了30%以上。 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/conventional/QuickStart/page.mdx b/packages/website-next/src/app/docs/conventional/QuickStart/page.mdx new file mode 100644 index 00000000..81b23bf7 --- /dev/null +++ b/packages/website-next/src/app/docs/conventional/QuickStart/page.mdx @@ -0,0 +1,94 @@ +欢迎学习 openInula 教程。此教程将会指导你使用 openInula 构建快速、轻便的 web 应用程序。 + +## 什么是openInula + +openInula 是一款用于构建用户界面的 JavaScript 库,提供响应式 API 帮助开发者简单高效构建 web 页面,比传统虚拟 DOM 方式渲染效率提升30%以上!同时 openInula 提供与 React 保持一致的 API,并且提供5大常用功能丰富的核心组件:**状态管理器**、**路由**、**国际化**、**请求组件**、**应用脚手架**,以便开发者高效、高质量的构筑基于 openInula 的前端产品。 + +### 在已有项目中安装 openInula + +#### 方式一:使用 `npm` 安装 + +在命令行中运行以下命令来通过 `npm` 安装 openInula: + +```sh filename="install.sh" +npm install openinula +``` + +上述命令会将最新版本的 openInula 包添加到您的项目中,当然,您也可以指定特定版本来安装包。最新版本号请在 npm 官网查看:[访问官网](https://www.npmjs.com/package/openinula) + +#### 方式二:使用 `yarn` 安装 + +openInula 也支持 `yarn` 命令安装,前提已安装了 `yarn`,如未安装,则通过 `npm install -g yarn` 命令来安装(全局安装)。 + +在命令行中运行以下命令来通过 `yarn` 安装 openInula: + +```sh filename="install.sh" +yarn add openinula +``` + +### 直接创建 openInula 项目 + +如果你已经安装了openInula,则可以简单地创建一个新的 JavaScript 文件,尝试使用 openInula,例如 `index.jsx`,并在其中添加以下代码: + +```jsx filename="index.jsx" +import { render } from 'openinula'; + +const HelloWorld = () => { + return ( +
+

Hello, World!

+
+ ); +}; + +render( + , + document.getElementById('root') +); +``` + +上述代码片段主要分为三部分,首先通过 `import` 语法导入 openInula 包,其次构建一个名为 `HelloWorld` 的函数组件,最后将 `HelloWorld` 组件挂载在 HTML 中 id 为 `root` 的 DOM元素上,详细使用请查阅[API参考Inula](https://docs.openinula.net/apis/Inula)。`index.jsx` 经过 babel 编译后,您将看到一个显示 "Hello, World!" 的页面。 + +### 使用脚手架创建openInula项目 + +#### 步骤一: 启动openInula脚手架 + +在您需要创建项目的目录下执行以下命令: + +```sh filename="create.sh" +npx create-inula <项目名> +``` + +#### 步骤二: 选择需要项目模板 + +执行启动命令后,您将收到以下回显信息询问,可根据回显信息进行相应的输入: + +```sh filename="select-template.txt" +Need to install the following packages:create-inula@0.0.2 +Ok to proceed? (y) y +? Please select the template (Use arrow keys) +> Simple-app +``` + +在创建项目过程中脚手架提供 Simple-app 模板供开发者使用: +- Simple-app 已默认安装 openInula,开发者可以直接在项目中专注于核心代码的开发。 + +#### 步骤三:选择打包方式 + +在创建项目过程中有两种打包方式供选择,您可以根据自己使用习惯选择: + +```sh filename="select-build.txt" +? Please select the build type (Use arrow keys) + > webpack + vite +``` + +如果您不知如何选择可分别参考 [Vite 文档](https://cn.vitejs.dev/) 以及 [webpack文档](https://webpack.js.org/)。 + +至此,可以使用 openInula 框架,通过 `npm run start` 命令运行项目,您会看到简单的 openInula 的示例。当然,您也可以基于 openInula 框架构建您的 web 项目。 + +### 开始使用openInula + +恭喜!您已经成功安装了 openInula。现在您可以根据项目需求自由使用 openInula 提供的组件和功能。 + +请查阅[《用户指南》](/docs/用户指南)以了解更多关于如何使用和配置框架的详细信息。 diff --git a/packages/website-next/src/app/docs/conventional/ReleaseNotes/page.mdx b/packages/website-next/src/app/docs/conventional/ReleaseNotes/page.mdx new file mode 100644 index 00000000..45bd6441 --- /dev/null +++ b/packages/website-next/src/app/docs/conventional/ReleaseNotes/page.mdx @@ -0,0 +1,24 @@ +--- +sidebar_position: 4 +--- +## 配套关系 + +表1 版本软件和工具配套关系 + +| 软件 | 版本 | 备注 | +|--------------|--------|----| +| inula | 0.0.11 | | +| create-inula | 1.0.11 | | + +## 新特性 + +**openInula** + +* 支持响应式 API(9月底发布β版本) +* 支持状态管理器 inulaX +* 兼容 React API,支持类式组件和函数式组件 + +**create-inula** + +- 支持选择 Simple-app 模板 +- 项目模板支持 webpack 和 vite 两种打包方式 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/conventional/SwitchingGuide/page.mdx b/packages/website-next/src/app/docs/conventional/SwitchingGuide/page.mdx new file mode 100644 index 00000000..73cf5db7 --- /dev/null +++ b/packages/website-next/src/app/docs/conventional/SwitchingGuide/page.mdx @@ -0,0 +1,180 @@ +--- +sidebar_position: 3 +--- + +为了便于开发者使用 openInula 进行页面开发,尤其是已经使用 React 的相关项目,openInula 提供了一种无感切换机制,可以从 React 切换到 openInula。您只需要按照如下的方式进行修改,就可以体验到 openInula 框架所提供的能力。 + +### 使用 React 的项目切换 openInula 步骤 + +- 步骤1:安装 openInula。 + +```bash filename="install.sh" +npm install openinula +``` + +最新版本号请在 npm 官网查看:[访问官网](https://www.npmjs.com/package/openinula) + +- 步骤2:引用切换,修改 openInula 相关 API 的加载方式。 + +```ts +// 修改前: +import React, { useContext, useEffect, Suspense, lazy, useState } from 'react'; +import ReactDOM from 'react-dom'; + +// 修改后: +import React, { useContext, useEffect, Suspense, lazy, useState } from 'openinula'; +import ReactDOM from 'openinula'; +``` +*注意*:修改后可以保留 React 全局变量。 + +- 步骤3:修改 webpack 配置文件中 `alias`,新增 `react`、`react-dom` 等别名,如下: + +```ts filename="webpack.config.js" +alias: { + // 省略其它... + 'react': 'openinula', // 新增 + 'react-dom': 'openinula', // 新增 + 'react-is': 'openinula', // 新增 +}, +``` + +### 切换FAQ + +#### openInula 编译 FAQ + +1. 在切换或者使用 openInula 框架时,`React.createElement` 无法转换成 `openinula.createElement`: + + 请排查编译命令中是否有 `--mode development`,该选项会导致 `React.createElement` 无法转换成 `openinula.createElement`,需要删除。 + +2. 如果在 webpack 配置文件中配置 `externals` 字段,需把 React 相关三方件的 `externals` 都替换,如下: + + ```ts filename="webpack.config.js" + externals: { + 'react': 'openinula', + 'react-dom': 'openinula', + 'react-redux': 'openinula', + 'react-thunk': 'openinula', + }, + ``` + +3、如果使用 babel,则需要修改 `.babelrc` (`babel.config.js`) 或 webpack 配置文件中 `babel-loader` 配置(解决编译后文件存留 `React.createElement` 的问题),如: + +- 如果你使用的是 `@babel/preset-react`,请确保版本号大于 `7.9.0` + + ```jsx + // 修改前: + { + "presets": [ + "@babel/preset-react" + ] + } + + // 修改后 + { + "presets": [ + [ + "@babel/preset-react", + { + "runtime": "automatic", // 新增 + "importSource": "openinula" // 新增 + } + ] + ] + } + ``` + +- 如若使用了 `@babel/plugin-transform-react-jsx`,请确保版本号大于 `7.9.0` + + ```jsx + // 修改前 + { + "plugins": [ + "@babel/plugin-transform-react-jsx" + ] + } + + // 修改后: + { + "plugins": [ + [ + "@babel/plugin-transform-react-jsx", + { + "runtime": "automatic", // 新增 + "importSource": "openinula" // 新增 + } + ] + ] + } + ``` + + > 注意:**`.babelrc` (`babel.config.js`)** 和 **webpack配置文件** 不要重复配置。 + +--- + +#### 不兼容 React 变更 FAQ + +1. openInula 不支持 Legacy Context,如:https://reactjs.org/docs/legacy-context.html ,请修改成new Context API,参考:https://reactjs.org/docs/context.html 。 + +2. openInula 不支持在 Class 组件中使用 `this.refs` + + ```jsx filename="InputFocusExample.jsx" + class InputFocusExample extends Component { + focusInput = () => { + this.refs.myInput.focus(); // 不支持 this.refs + }; + + render() { + return ( +
+ + +
+ ); + } + } + + // 请修改成以下新的 Ref API 方式: + class InputFocusExample extends Component { + constructor(props) { + super(props); + this.myInput = React.createRef(); // 新的 Ref API + } + + focusInput = () => { + this.myInput.current.focus(); // 通过 this.myInput.current 引用 + }; + + render() { + return ( +
+ + +
+ ); + } + } + ``` + +--- + +#### 测试框架 FAQ + +1. openInula 如何与 `@testing-library/react` 配套使用? + + openInula 支持与 React 提供的测试框架配合使用,方法配置简便,需要在 `jest.config.js` 中需要加入如下配置: + + ```js filename="jest.config.js" + module.exports = { + moduleNameMapper: { + "^react$": "/node_modules/openinula", + "^react-dom": "/node_modules/openinula", + "^react/jsx-runtime": "/node_modules/openinula/jsx-runtime" // 非必须,如存在 require("react/jsx-runtime") 这种引入方式才需要 + }, + }; + ``` + + > 注意:`"^react/jsx-runtime": "rootDir/node_modules/openinula/jsx-runtime"`是非必须添加,若存在 `require("react/jsx-runtime")` 这种引入方式才需要 + +2. openInula 项目如何使用 `react-test-renderer` 测试框架? + + openInula 不支持 `react-test-renderer` 这个测试框架,如果使用到需要自行修改。因为 `react-test-renderer` 用到了 React 的 `React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED` 接口,而 openInula 没有该接口。 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/conventional/UserInstruction/figure.png b/packages/website-next/src/app/docs/conventional/UserInstruction/figure.png new file mode 100644 index 0000000000000000000000000000000000000000..ba5a2f6044ecde43edaf33dd100a1d1411a15dbb GIT binary patch literal 155820 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 G@Bas2!LjQA literal 0 HcmV?d00001 diff --git a/packages/website-next/src/app/docs/conventional/UserInstruction/page.mdx b/packages/website-next/src/app/docs/conventional/UserInstruction/page.mdx new file mode 100644 index 00000000..cb988921 --- /dev/null +++ b/packages/website-next/src/app/docs/conventional/UserInstruction/page.mdx @@ -0,0 +1,745 @@ +--- +sidebar_position: 2 +--- + +# 用户指南 + +openInula 是一款构建用户界面的 JavaScript 前端框架。本篇文章会对 openInula 的组件及生命周期、数据管理、事件绑定等知识进行详细介绍,相信通过本章学习您将掌握到 openinula 的基本知识和使用方法。 + +## 开始使用 + +### JSX + +JSX 是 JavaScript XML 的缩写,是一种用于构建用户界面的语法扩展。在 openInula 中,JSX 被广泛使用。开发者可以使用 JSX 来描述 UI 组件的结构和样式,并将其与 JavaScript 代码逻辑相结合。然后使用转译工具(例如`Babel`)将 JSX 代码转换为普通的 JavaScript 代码,以便浏览器能够理解并渲染。 + +- JSX 是类 HTML 语言,其除了拥有 HTML 的功能外,还可以通过括号`{}`嵌套 JavaScript 表达式,这使得 JSX 更加灵活,可以动态地生成UI组件; +- JSX 支持双向数据绑定,使得数据和界面之间的更新更加简单。当数据发生变化时,会智能地更新必要部分。HTML 没有直接支持数据绑定的功能; +- 每个 JSX 必须返回独有元素。如果要返回多个顶级元素,请使用 `Fragment` 元素或者 <>。 + +```jsx filename="fragment-example.jsx" +<> +

Hello, {props.name}!

; + + + +``` + +### 组件 + +组件是 openInula 的核心概念之一。它们是构建用户界面(UI)的基础,是可重用和独立的代码单元。开发者可以将相关功能、状态以及模板封装在组件中,提高可复用性,使得程序开发具备模块化和可维护特性。下面我们将展开介绍。 + +#### 组件的设计 + +组件不是 openInula 特有的概念,但是组件的设计思想会是优秀应用开发的基础。接下来我们就谈一谈组件设计的奥秘。 + +openInula 组件思想具有普适性,无论是在其他框架还是原生 Web component 都适用。组件与我们之前学到的HTML的元素非常相似,如将一个 UI 界面分成独立的可重复复用的单独的部分,每个部称之为一个组件,各个组件之间相互交互以实现基本功能。 + +![image](./figure.png) + +如果您已经了解使用组件会给您的程序带来的优点,如何设计一个好的组件将是您接下来关注的问题,openInula 框架认为一个好的组件会遵循以下原则: + +1. 单一职责:组件只应该做一件事情。单一职责带来最大好处就是在修改组件时,不必担心对其他组件造成影响。 +2. 开闭原则:一个组件应该对扩展开放,对修改关闭,即通过扩展组件的行为来实现功能的变化,而不是修改组件的源代码。 + +上述原则可以帮助开发者设计出高内聚、低耦合、可扩展、可维护的组件。如下示例是我们展示如何使用设计原则来实现一个安全可靠的组件。 + +```jsx filename="button-form-page.jsx" +import Inula, { render, Component } from 'openinula'; + +// 示例组件 - 按钮组件 +class Button extends Component { + render() { + const { text, onClick } = this.props; + return ( + + ); + } +} + +// 示例组件 - 表单组件 +class Form extends Component { + handleSubmit = (event) => { + event.preventDefault(); + // 处理表单提交逻辑 + } + + render() { + return ( +
+ +
+ + ); + }; + }; + ``` + +2. 函数组件 + + 函数组件是以函数形式呈现,可以接收一个属性(`props`)作为输入,并返回一个 JSX 元素。函数组件的代码量更少,易于阅读和理解。相较于类组件,没有繁琐的类声明和生命周期方法,更加直观和简洁。此外,函数组件没有实例化的过程,在一些情况下,函数组件比类组件具有更好的性能。 + + ```jsx filename="picture-greeting.jsx" + function Picture() { + return ( + + ); + }; + + const Greeting = (props) => { + return ( +
+

Hello, {props.name}!

+ +
+ ); + }; + ``` + +此外,无论是函数组件还是类组件,组件之间可以进行嵌套,实现更复杂的代码逻辑。在上述函数组件示例中包含了两个组件,`Greeting`为父组件,`Picture`是它的子组件。 + +> 注意: +> 1. 如果定义组件,则首字母需要大写,以区分 HTML 标签; +> 2. 在渲染JSX元素时,`return` 时需要通过括号`()`包含多个组件,否则 `return` 中除首行代码外都会被忽略。 + +#### 组件的渲染 + +我们已经介绍了函数组件和类组件,下一步我们将思考如何能将创建的组件展示到界面?首先我们创建了一个 `index.jsx` 文件,使用 `document.getElementById('root')` 表示获取HTML文档中具有id为 `root` 的元素作为挂载点,进而在浏览器中展示 `Counter` 组件内容。 + +```jsx filename="app.jsx" +import { render } from 'openinula'; +import { Counter } from './Counter.js' + +function App() { + render( + , + document.getElementById('root') + ); +}; +``` + +### 组件间通信 + +#### Props(属性) + +Props(属性)是组件之间传递数据的一种机制。Props 是从父组件向子组件传递的不可变对象。Props 的参数传递是一种单向传递,即从父组件单向传递子组件,因此 Props 是一种只读属性,子组件只能读取父组件传递的 Props,但却不能修改值。在如下示例中,我们创建一个父组件 `ParentComponent`,通过 Props 机制将参数传递给子组件 `ChildComponent`。 + +```jsx filename="parent-child-component.jsx" +function ParentComponent() { + return ( + + ); +} + +// 类组件 +class ChildComponent extends Component { + render() { + return ( +
+

Name: {this.props.name}

+

Age: {this.props.age}

+

Gender: {this.props.gender || 'Unknown'}

+
+ ); + } +} + +// 函数组件 +function ChildComponent(props) { + return ( +
+

Name: {props.name}

+

Age: {props.age}

+

Gender: {props.gender || 'Unknown'}

+
+ ); +} +``` + +在上述代码中,子组件 `ChildComponent` 通过 Props 机制可以获取到父组件传入的 `props` 并获取 `name`、`age` 以及 `gender` 等值。 + +```jsx +

Name: {props.name}

+``` + +有些读者可能已经发现,父组件传入的 `props` 中没有 `gender` 属性。但是如果子组件执意使用时,也可传入默认值。在上述例子中,当父组件没有传入对应属性 `props.gender` 时,可以设置默认值为`Unknown`,如果没有设置对应属性的默认值,则获取到的值为 `undefined`。 + +#### State(状态) + +openInula 中 State(状态) 是一种用于存储和管理组件内部数据的机制。它是一个对象,包含了组件的可变数据。当状态发生变化时会自动重新渲染组件,以反映最新的状态。 + +在介绍组件的分类时,我们在[类组件](#组件的分类)中定义了 `Counter` 组件让读者更直观地感受类组件特点,在 `Counter` 类组件中,我们使用 `this.state = { count: 0 }` 定义了计数器的初始状态值,并通过 `setState` 函数进行修改状态。但是这只是针对类组件中的状态的设置以及修改,如果在函数组件中,我们又如何使用呢? + +下面示例中我们将类组件 `Counter` 改写写成函数组件,用 `useState` 钩子函数来声明管理组件的状态,因此代码也可以写为: + +```jsx filename="counter-func.jsx" +import Inula, { useState } from 'openinula'; + +function Counter() { + const [count, setCount] = useState(0); + + const increment = () => { + setCount(count + 1); + }; + + return ( +
+

Count: {count}

+ +
+ ); +} +``` + +`useState` 钩子用于定义名为 `count` 的状态变量,并使用初始值0进行初始化。同时返回的 `setCount` 函数用于更新 `count` 的值。当用户点击 `Increment` 按钮时,会触发 `increment` 函数并进一步调用 `setCount` 来增加计数器的值,并更新组件的状态。每次 `setCount` 被调用时会重新渲染 `Counter` 组件,并显示最新的计数值。 + +> Tips: `state` 与 `props`区别 +> `state` 是组件内部管理的可变数据,用于存储和更新组件的私有状态。而 `props` 是由父组件传递给子组件的不可变数据,用于组件之间的数据传递和通信。通过结合使用 `state` 和 `props`,可以实现动态的和可重用的组件,并在应用中管理和传递数据。 + +#### 组件通信的封装性 + +openInula 提倡开发者使用组件,对于单个组件来说,单一职责原则会保证组件的封装性,但是组件之间的应该存在必要的交互通信,才能相互协作协作,完整更复杂的功能逻辑。细心的读者已经发现在上述的例子中,我们已经使用 `props` 和 `state` 来进行组件的交互,但是如何在保证组件交互时同样具备封装性呢?下面我们通过一个错误案例以及对其的修改进行详细说明。 + +```jsx +// ParentComponent.js +import Inula, { Component } from 'openinula'; +import ChildComponent from './ChildComponent'; + +class ParentComponent extends Component { + constructor(props) { + super(props); + this.state = { + message: 'Hello', + }; + } + + handleChange = (e) => { + this.setState({ message: e.target.value }); + }; + + render() { + return ( +
+ + +
+ ); + } +} + +// ChildComponent.js +import Inula, { Component } from 'openinula'; + +class ChildComponent extends Component { + render() { + return
{this.props.message}
; + } +} +``` + +在上述示例中,`ParentComponent` 和 `ChildComponent` 是两个组件。然而,`ParentComponent` 直接将自己的状态(`message`)传递给了 `ChildComponent` 作为 `props` ,这违背了组件封装性的原则。 + +根据组件封装性的原则,一个组件应该尽可能地隐藏其内部实现细节,并通过 `props` 接口与外部进行通信。但在这个示例中,`ParentComponent` 将自己的状态直接传递给了 `ChildComponent`,导致 `ChildComponent` 依赖于 `ParentComponent` 的状态。 + +因此,我们在重构中,首先会考虑到以“粗暴、直接地”方式修改 `message` 值,并且考虑到组件的封装特性,保证组件只感知到自身的 `state`。我们可以将 `ChildComponent` 中的 `message` 属性改为通过 `props` 传递一个回调函数,然后在 `ParentComponent` 中定义这个回调函数,将 `message` 作为参数传递给它,最后在 `ChildComponent` 中调用这个回调函数来获取 `message`。 + +修改后的代码如下: + +```jsx +// ParentComponent.js +import Inula, { Component } from 'openinula'; +import ChildComponent from './ChildComponent'; + +class ParentComponent extends Component { + constructor(props) { + super(props); + this.state = { + message: 'Hello', + }; + } + + handleChange = (e) => { + this.setState({ message: e.target.value }); + }; + + render() { + return ( +
+ + this.state.message} /> +
+ ); + }; +} + + +// ChildComponent.js +import Inula, { Component } from 'openinula'; + +class ChildComponent extends Component { + render() { + return
{this.props.getMessage()}
; + }; +} + +export default ParentComponent; +``` + +这样,我们通过回调函数的方式,将 `message` 的获取封装在了 `ParentComponent` 中,`ChildComponent` 组件就不需要再知道 `ParentComponent` 组件的内部情况,保证了 `ChildComponent` 的封装性。 + +### 条件渲染与列表渲染 + +条件渲染与列表渲染是 openInula 中常用的功能,条件渲染的方式可以根据不同的情况来显示不同的内容,提高用户体验。列表渲染可以简化代码逻辑,更便捷的开发代码。因此,JSX 也满足在 openInula 中可以实现条件渲染以及列表渲染。 + +1. **条件渲染**:使用 if 条件语句或三元表达式来实现条件渲染。 + + ```jsx + function UserGreeting(props) { + return

Welcome back!

; + } + + function GuestGreeting(props) { + return

Please sign up.

; + } + + // 直接使用 if-else 语句 + function Example(props) { + const isLoggedIn = props.isLoggedIn; + if (isLoggedIn) { + return ; + } + return ; + } + + // 使用三元表达式 + function Example(props) { + const isLoggedIn = props.isLoggedIn; + return ( + {isLoggedIn ? : } + ); + } + ``` + + 在这个示例中我们定义了两种问候用户的组件 `` 与 ``,并希望根据用户是否登录 `isLoggedIn` 分别展示前后者。我们可以使用 if-else 语句分别返回不同的组件,也可以通过三元表达式择一返回。 + + +2. **列表渲染**:使用 for 循环或 `map` 来实现组件列表渲染。 + + ```jsx + function List(props) { + const items = props.items.map((item, index) => ( +
  • {item}
  • + )); + + return
      {items}
    ; + } + + function App() { + const items = ['Item 1', 'Item 2', 'Item 3']; + + return ( +
    +

    List Demo

    + +
    + ); + } + ``` + + 在这个示例中,我们定义了一个 `List` 组件,它接收一个 `items` 属性,该属性是一个字符串数组。我们使用 `map` 函数将每个字符串转换为一个 `
  • ` 元素,并将它们存储在一个 `items` 数组中。最后,我们将这个数组作为子元素传递给 `
      ` 元素,以渲染整个列表。 + +### 事件 + +openInula 中支持事件是为了实现交互性和动态性的用户界面,通过在组件中定义事件处理函数,可以将用户的操作与组件的状态和行为关联起来。当用户触发事件时,openInula 会调用相应的事件处理函数,并根据需要更新组件的状态或执行其他操作,从而实现动态的用户界面。 + +openInula组件感知到用户触发事件是通过 `onXxxx` 属性来监听 DOM 事件,并在事件触发时执行事件的处理函数。因此在 openInula 中必须定义一个事件处理函数,在使用时只需要传递事件即可。 + +> 事件的命名规则:on+驼峰形式事件名 = 事件处理函数 + +#### 事件处理函数的定义 + +事件处理函数其实就是一个函数,它被用来响应特定的事件。当事件被处理时,事件函数就会被触发。 + +```jsx +function handleClick() { + // 处理点击事件的逻辑 + console.log('Button clicked!'); +} +``` + +#### 事件处理函数的触发 + +在openInula中,我们使用`onXxxx`属性来绑定事件处理函数,例如,使用`onClick`属性来绑定点击事件。函数绑定为了确保事件处理函数可以正确地访问组件实例的上下文(`this`)。有几种方法可以实现函数绑定: + +1. 在构造函数中使用 `bind` 方法绑定函数 + + ```jsx + class App extends Component { + constructor(props) { + super(props); + this.handleClick = this.onHandleClick.bind(this); + } + + onHandleClick() { + // 处理点击事件的逻辑 + console.log('Button clicked!'); + }; + + render() { + return ; + }; + }; + ``` + +2. 使用箭头函数定义事件处理函数 + + ```jsx + class App extends Component { + handleClick = () => { + // 处理点击事件的逻辑 + console.log('Button clicked!'); + }; + + render() { + return ; + }; + }; + ``` + + > 箭头函数可以避免`this`指向问题,是因为箭头函数没有自己的`this`,它会继承外层函数的`this`。 + +#### openInula支持的事件 + +- Clipboard Events 剪切板事件 + - 事件名: `onCopy`, `onCut`, `onPaste` + - 属性: `DOMDataTransfer`, `clipboardData` +- compositionEvent 复合事件 + - 事件名: `onCompositionEnd`, `onCompositionStart`, `onCompositionUpdate` + - 属性: `string`, `data` +- Keyboard Events 键盘事件 + - 事件名: `onKeyDown`, `onKeyPress`, `onKeyUp` + - 属性: `number`, `keyCode` +- Focus Events 焦点事件 (这些焦点事件在 openinula DOM 上的所有元素都有效,不只是表单元素) + - 事件名: `onFocus`, `onBlur` + - 属性: `DOMEventTarget`, `relatedTarget` +- Form Events 表单事件 + - 事件名: `onChange`, `onInput`, `onInvalid`, `onSubmit` +- Mouse Events 鼠标事件 + - 事件名: `onClick`, `onContextMenu`, `onDoubleClick`, `onDrag`, `onDragEnd`, `onDragEnter`, `onDragExit`, `onDragLeave`, `onDragOver`, `onDragStart`, `onDrop`, `onMouseDown`, `onMouseEnter`, `onMouseLeave`, `, onMouseMove`, `onMouseOut`, `onMouseOver`, `onMouseUp` +- Pointer Events 指针事件 + - 事件名: `onPointerDown`, `onPointerMove`, `onPointerUp`, `onPointerCancel`, `onGotPointerCapture`, `onLostPointerCapture`, `onPointerEnter`, `onPointerLeave`, `onPointerOver`, `onPointerOut` + +### Hook + +Hook 是 openInula 目前提供的一种函数,Hook 函数可以让我们在函数组件中使用状态管理、生命周期方法、副作用等功能。常用的[钩子函数](/apis/Inula#钩子函数)包括 `useState`、`useEffect`、`useContext`、`useReducer`等。 + +当然,当 openInula 提供的 Hook 组件无法满足您的需求时,您可以自定义 Hook。在 openInula 中,自定义 Hook 函数的本质是一种重用状态逻辑思想。每一个 Hook 函数都是普通的函数。主要是其使用了 openInula 自带的 Hook API 等。下面我们就举例说明如何自定义一个 Hook 函数。 + +```jsx +import Inula, { useState, useEffect } from 'openinula'; + +function useFetch(url) { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + async function fetchData() { + const response = await fetch(url); + const data = await response.json(); + setData(data); + setLoading(false); + } + fetchData(); + }, [url]); + + return { data, loading }; +} +``` + +这个自定义的 Hook 函数 `useFetch` 接收一个URL作为参数,并返回一个包含 `data` 和 `loading` 状态的对象。在 `useEffect` 中,我们使用 `async/await` 语法来获取数据,并在获取数据后更新状态。 + +使用时: + +```jsx +import useFetch from './useFetch'; + +function MyComponent() { + const { data, loading } = useFetch('https://jsonplaceholder.typicode.com/todos/1'); + + if (loading) { + return
      Loading...
      ; + } + + return ( +
      +

      {data.title}

      +

      {data.completed ? 'Completed' : 'Not completed'}

      +
      + ); +} + +export default MyComponent; +``` + +在这个组件中,我们使用 `useFetch` 来获取数据,并根据 `loading` 状态显示不同的内容。这个自定义 Hook 函数可以在多个组件中重复使用,以避免重复的代码。 + +### 组件的生命周期 + +openInula 的组件创建时都会进行初始化步骤,在此过程会运行 openInula 所声明的生命周期钩子函数,便于开发者在特定阶段运行自己的代码,以实现复杂的项目逻辑。我们认为使用一个组件的主要流程遵循:**使用时创建,数据变化时更新,使用完卸载**。 + +#### 类组件的生命周期 + +在介绍类组件时,我们创建了一个 `Counter` 组件,其可以简单的实现计数器功能,但是当我们需要知道之前的值 `prevState` 以及当前的值 `currentState` 时,就需要使用更细节的代码控制,如生命周期。在下面新的 `Counter` 组件中我们调用了一些生命周期钩子函数,包含了组件的挂载、更新、卸载等过程。 + +```jsx +import { Component } from 'openinula'; + +class Counter extends Inula.Component { + constructor(props) { + super(props); + this.state = { + counter: 0 + }; + console.log('Constructor'); + } + + componentDidMount() { + console.log('Component Did Mount'); + } + + componentDidUpdate() { + console.log('Component Did Update'); + } + + componentWillUnmount() { + console.log('Component Will Unmount'); + } + + handleIncrement = () => { + this.setState(prevState => ({ + counter: prevState.counter + 1 + })); + }; + + render() { + console.log('Render'); + return ( +
      +

      Counter: {this.state.counter}

      + +
      + ); + } +} +``` + +**类组件的挂载** + +当 `Counter` 组件第一次通过 `render` 函数渲染在HTML页面时,这个方式被称为“挂载”。`componentDidMount` 钩子函数在组件挂载到 DOM 后被调用,可以用于执行初始化操作,例如发起网络请求、订阅事件等。 + +```jsx +componentDidMount() { + console.log('Component mounted'); +} +``` + +**类组件的更新** + +当组件中的内容变化时,则会触发组件的更新状态,会重新渲染页面。因此在组件挂载的情况存在两种,一种是初始化渲染,另一种是状态更新之后重新挂载。`componentDidUpdate` 在组件更新后被调用,可以用于处理组件的更新逻辑,比较前后状态的变化等。 + +```jsx +componentDidUpdate(prevProps, prevState) { + console.log('Component updated'); +} +``` + +**类组件的卸载** + +`componentWillUnmount` 在组件即将从 DOM 中卸载之前被调用,可以用于清理操作,例如取消网络请求、清除定时器等。 + +```jsx +componentWillUnmount() { + console.log('componentWillUnmount'); +} +``` + +#### 函数组件的生命周期 + +函数组件的生命周期是通过 `useEffect` 钩子函数来模拟的。 + +**函数组件的挂载** + +```jsx +// 模拟 componentDidMount +useEffect(() => { + console.log('Component did mount'); + // 在这里可以执行一些初始化操作 + // 也可以发送网络请求等操作 + // 注意:这个回调函数只会在组件挂载时执行一次 +}, []); +``` + +`useEffect`的第一个参数中的回调函数会被调用,模拟了`componentDidMount`。第二个参数为依赖项,可以控制回调函数的触发时机,这里未指定依赖项,则意味着只会在初次挂载时触发回调函数。 + +**函数组件的更新** + +```jsx +// 模拟 componentDidUpdate +useEffect(() => { + console.log('Component did update'); + // 在这里可以处理一些副作用操作 + // 例如,更新文档标题等 + // 注意:这个回调函数在组件更新时会执行 +}, [count]); +``` + +这里指定参数中的依赖项为 `count`,即只有依赖项 `count` 发生变化时,回调函数才会被调用。 + +**函数组件的卸载** + +```jsx +// 模拟 componentWillUnmount +useEffect(() => { + return () => { + console.log('Component will unmount'); + // 在这里可以执行一些清理操作 + // 例如,取消订阅、清除定时器等 + // 注意:这个回调函数只会在组件卸载时执行 + }; +}, []); +``` + +这里为回调函数设置了返回函数,在函数卸载时将调用这个返回函数中的操作,例如,取消订阅、清除定时器等。 + +## 快速进阶 + +### Ref + +openInula已经提供了两种管理数据的方式(`state` 和 `props`),但是针对一些特殊场景,当您的 openInula 组件需要与外部 API 通信时,通常需要在组件挂载后进行一些 DOM 操作,例如获取元素的尺寸、绑定事件监听器等。这些操作需要直接访问 DOM 元素,而 `props` 和 `state` 主要用于组件之间的数据传递和状态管理,不能达到操作 DOM 的目的,因此,openInula 还提供了 Ref 方式,允许我们直接操作组件的 DOM 元素或者调用组件内的方法,以进行数据交换。 + +#### Refs对象的创建 + +1. 使用 `createRef` 的方式可以创建一个 Ref 对象,可通过附加到 `ref` 属性上访问一个原生 DOM 元素或者组件。这种方式既可以在函数组件中使用,也可以在类组件中使用。 + + ```jsx + const ref = createRef(); + ``` + +2. 使用 `useRef(initialValue)` 创建,这种方式只能在函数组件中使用。 + + ```jsx + const ref = useRef(initialValue); + ``` + +> 上述两种方法的区别:`createRef` 每次渲染都会返回一个新的引用,而 `useRef` 每次都会返回相同的引用。详细请查阅[API参考](/apis/Inula)。 + +#### Ref 的两种使用场景 + +1. 存储变量 + + ```jsx + import Inula, { useState, useRef, useCallback } from 'openinula' + + export default function ClickWatch() { + let ref = useRef(0); + + const handleClick = useCallback(() => { + ref.current = ref.current + 1; + alert('You clicked ' + ref.current + ' times!'); + }, []); + + return ( + + ); + } + ``` + + 在上述示例中,通过使用`useRef(0)`我们创建了 + + ```jsx + { + current: 0 + } + ``` + + 这个对象,当对 `ref.current` 操作时,这个值是可变的,但是对象是不变的,这保证组件不会在每次递增时都触发重新渲染。 + +2. 操作DOM + + 通过使用 Ref,我们能够直接访问和操作 DOM 元素,而无需通过其他方式来获取或修改其值。下面的例子很好展示了 Ref 的用法。 + + ```jsx + import { useRef } from "openinula"; + + function Component() { + const inputRef = useRef(null); + + const handleClick = () => { + alert(`Input value: ${inputRef.current.value}`); + }; + + return ( +
      + + +
      + ); + } + ``` + + 在上述案例中,为了使用 Ref 特性,我们使用 `useRef` 钩子创建了一个 `inputRef` 变量,并将其初始化为 `null`。将 `inputRef` 传递给 `` 元素的 `ref` 属性。当按钮被点击时,则可以通过 `inputRef.current` 访问到DOM节点,并获取输入框的值。 + +> 注意:由于`ref`是可以避免重新渲染,因此,不要在渲染的过程中读取和写入,会导致结果不可控制。 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/introduction/page.mdx b/packages/website-next/src/app/docs/introduction/page.mdx new file mode 100644 index 00000000..64c47a60 --- /dev/null +++ b/packages/website-next/src/app/docs/introduction/page.mdx @@ -0,0 +1,41 @@ +--- +id: introduction +title: 项目介绍 +sidebar_label: 项目介绍 +--- + +# 项目介绍 + +OpenInula 是一个现代化的 JavaScript UI 框架,致力于提供极致性能和开发体验。 + +## 设计理念 + +- 无 API 哲学:只用 JSX + 原生 JS +- 编译优先:大部分逻辑编译期完成 +- 响应式:自动追踪依赖,极致性能 + +## 核心特性 + +- 直观的状态管理 +- 内置模板语法(if/for) +- 计算值与 watch +- 生命周期钩子 +- 兼容 React 生态 + +## 主要模块 + +- runtime:核心运行时 +- shared:通用工具 +- compiler:编译器 +- inula-bridge:兼容层 + +## 未来方向 + +- 更强的类型推导 +- 更丰富的生态组件 +- 更高效的编译优化 + +## 下一步 + +- [快速入门](./getting-started) +- [基础概念](next/core-concepts/introduction) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/layout.tsx b/packages/website-next/src/app/docs/layout.tsx new file mode 100644 index 00000000..6eee4178 --- /dev/null +++ b/packages/website-next/src/app/docs/layout.tsx @@ -0,0 +1,233 @@ +import { ReactNode } from 'react' +import { Layout } from 'nextra-theme-docs' +/*import { getPageMap } from 'nextra/page-map'*/ +import 'nextra-theme-docs/style.css' + +export default async function RootLayout({children}: Readonly<{ children: ReactNode }>) { + //const allPages = await getPageMap() + + const docsMap = [ + { + name: "概述", + route: '/docs', + title: '概述', + kind: 'MdxPage', + }, + { + name: 'introduction', + route: '/docs/introduction', + title: 'Introduction', + kind: 'MdxPage' + }, + { + name: 'Quick start', + route: '/docs/quick-start', + title: '快速开始', + kind: 'MdxPage' + }, + { + name: 'reactivity', + route: '/docs/reactivity', + title: '响应式系统', + kind: 'Folder', + children: [ + { + name: 'state', + route: '/docs/reactivity/state', + title: '状态管理', + kind: 'MdxPage' + }, + { + name: 'computed', + route: '/docs/reactivity/computed', + title: '计算值', + kind: 'MdxPage' + }, + { + name: 'watch', + route: '/docs/reactivity/watch', + title: '监听系统', + kind: 'MdxPage' + }, + { + name: 'untrack', + route: '/docs/reactivity/untrack', + title: 'untrack(非响应式访问)', + kind: 'MdxPage' + } + ] + }, + { + name: 'template-system', + route: '/docs/template-system', + title: '模板系统', + kind: 'Folder', + children: [ + { + name: 'conditional', + route: '/docs/template-system/conditional', + title: '条件渲染', + kind: 'MdxPage' + }, + { + name: 'event-handling', + route: '/docs/template-system/event-handling', + title: '事件处理', + kind: 'MdxPage' + }, + { + name: 'list-rendering', + route: '/docs/template-system/list-rendering', + title: '列表渲染', + kind: 'MdxPage' + } + ] + }, + { + name: 'lifecycle', + route: '/docs/lifecycle', + title: '生命周期', + kind: 'Folder', + children: [ + { + name: 'mounting', + route: '/docs/lifecycle/mounting', + title: '挂载阶段', + kind: 'MdxPage' + }, + { + name: 'unmounting', + route: '/docs/lifecycle/unmounting', + title: '卸载阶段', + kind: 'MdxPage' + }, + { + name: 'cleanup', + route: '/docs/lifecycle/cleanup', + title: '清理阶段', + kind: 'MdxPage' + } + ] + }, + { + name: 'components', + route: '/docs/components', + title: '组件', + kind: 'Folder', + children: [ + { + name: 'composition', + route: '/docs/components/composition', + title: '组合模式', + kind: 'MdxPage' + }, + { + name: 'context', + route: '/docs/components/context', + title: '上下文', + kind: 'MdxPage' + }, + { + name: 'Dynamic', + route: '/docs/components/Dynamic', + title: '动态组件', + kind: 'MdxPage' + }, + { + name: 'ErrorBoundary', + route: '/docs/components/ErrorBoundary', + title: '错误边界', + kind: 'MdxPage' + }, + { + name: 'Fragment', + route: '/docs/components/Fragment', + title: 'Fragment', + kind: 'MdxPage' + }, + { + name: 'Portal', + route: '/docs/components/Portal', + title: 'Portal', + kind: 'MdxPage' + }, + { + name: 'props', + route: '/docs/components/props', + title: 'Props', + kind: 'MdxPage' + }, + { + name: 'Suspense', + route: '/docs/components/Suspense', + title: 'Suspense', + kind: 'MdxPage' + } + ] + }, + { + name: 'conventional', + route: '/docs/conventional', + title: '传统API文档', + kind: 'Folder', + children: [ + { + name: 'UserInstruction', + route: '/docs/conventional/UserInstruction', + title: '用户指南', + kind: 'MdxPage', + }, + { + name: 'QuickStart', + route: '/docs/conventional/QuickStart', + title: '快速入门', + kind: 'MdxPage' + }, + { + name: 'SwitchingGuide', + route: '/docs/conventional/SwitchingGuide', + title: '切换指导书', + kind: 'MdxPage' + }, + { + name: 'ReleaseNotes', + route: '/docs/conventional/ReleaseNotes', + title: '发行说明', + kind: 'MdxPage' + }, + { + name: 'FAQ', + route: '/docs/conventional/FAQ', + title: '常见问题', + kind: 'MdxPage' + }, + { + name: 'CodeOfConduct', + route: '/docs/conventional/CodeOfConduct', + title: '行为准则', + kind: 'MdxPage' + }, + { + name: 'ContributingGuide', + route: '/docs/conventional/ContributingGuide', + title: '贡献指南', + kind: 'MdxPage' + } + ] + } + ] + + return ( +
      + + {children} + +
      + ) +} \ No newline at end of file diff --git a/packages/website-next/src/app/docs/lifecycle/cleanup/page.mdx b/packages/website-next/src/app/docs/lifecycle/cleanup/page.mdx new file mode 100644 index 00000000..86118017 --- /dev/null +++ b/packages/website-next/src/app/docs/lifecycle/cleanup/page.mdx @@ -0,0 +1,59 @@ +--- +id: cleanup +title: 清理操作 +sidebar_label: 清理操作 +--- + +# 清理操作 + +清理操作用于移除副作用,如定时器、事件监听、watch 清理函数等。 + +## 定时器清理 + +```tsx filename="TimerCleanup.jsx" +function Timer() { + let timer; + didMount(() => { + timer = setInterval(() => {}, 1000); + }); + willUnmount(() => clearInterval(timer)); + return
      定时器已启动
      ; +} +``` + +## 事件监听清理 + +```tsx filename="EventListener.jsx" +function Listener() { + function onResize() {} + didMount(() => window.addEventListener('resize', onResize)); + willUnmount(() => window.removeEventListener('resize', onResize)); + return
      监听窗口大小
      ; +} +``` + +## watch 清理函数 + +```tsx filename="WatchCleanup.jsx" +function Watcher() { + let timer; + watch(() => { + timer = setInterval(() => {}, 1000); + return () => clearInterval(timer); + }); + return
      watch 清理
      ; +} +``` + +## 最佳实践 + +- 所有副作用都应有清理逻辑 +- 推荐统一在 willUnmount/didUnmount 或 watch 清理函数中处理 + +## 注意事项 + +- 避免遗留定时器、事件监听等,防止内存泄漏 + +## 相关链接 + +- [卸载阶段](../unmounting) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/lifecycle/mounting/page.mdx b/packages/website-next/src/app/docs/lifecycle/mounting/page.mdx new file mode 100644 index 00000000..2ea05b05 --- /dev/null +++ b/packages/website-next/src/app/docs/lifecycle/mounting/page.mdx @@ -0,0 +1,49 @@ +--- +id: mounting +title: 挂载阶段 +sidebar_label: 挂载阶段 +--- + +# 挂载阶段 + +组件挂载时可执行副作用,如数据请求、事件监听等。OpenInula 提供 didMount 钩子。 + +## 基本用法 + +```tsx filename="PageTitle.jsx" +function PageTitle() { + let title = ''; + didMount(() => { + title = document.title; + }); + return

      页面标题:{title}

      ; +} +``` + +## 数据请求 + +```tsx filename="FetchData.jsx" +function FetchData() { + let data = null; + didMount(() => { + fetch('/api/data') + .then(res => res.json()) + .then(d => { data = d; }); + }); + return
      {JSON.stringify(data)}
      ; +} +``` + +## 最佳实践 + +- 只在 didMount 中执行副作用 +- 清理副作用请用 willUnmount/didUnmount + +## 注意事项 + +- didMount 只在组件首次挂载时执行一次 + +## 相关链接 + +- [卸载阶段](../unmounting) +- [清理操作](../cleanup) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/lifecycle/unmounting/page.mdx b/packages/website-next/src/app/docs/lifecycle/unmounting/page.mdx new file mode 100644 index 00000000..01316bb4 --- /dev/null +++ b/packages/website-next/src/app/docs/lifecycle/unmounting/page.mdx @@ -0,0 +1,43 @@ +--- +id: unmounting +title: 卸载阶段 +sidebar_label: 卸载阶段 +--- + +# 卸载阶段 + +组件卸载时需清理副作用,防止内存泄漏。OpenInula 提供 willUnmount/didUnmount 钩子。 + +## 基本用法 + +```tsx filename="Timer.jsx" +function Timer() { + let timer; + didMount(() => { + timer = setInterval(() => {}, 1000); + }); + willUnmount(() => clearInterval(timer)); + // 或 didUnmount(() => clearInterval(timer)); + return
      定时器已启动
      ; +} +``` + +## 副作用清理 + +- 清理定时器、事件监听、watch 副作用等 +- 推荐所有副作用都在卸载时清理 + +## 最佳实践 + +- 所有副作用都应在卸载时清理 +- 推荐用 willUnmount/didUnmount + +## 注意事项 + +- 清理函数只在组件卸载时执行一次 +- 避免遗留定时器、事件监听等,防止内存泄漏 + +## 相关链接 + +- [挂载阶段](../mounting) +- [清理操作](../cleanup) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/page.mdx b/packages/website-next/src/app/docs/page.mdx new file mode 100644 index 00000000..d606a912 --- /dev/null +++ b/packages/website-next/src/app/docs/page.mdx @@ -0,0 +1,110 @@ +# openInula 2 + +openInula 2版本是一个现代化的 JavaScript UI 开发库,具有以下特点: + +- **无 API 设计理念**:只需使用 JSX 和原生 JavaScript 即可直观编程 +- **编译优先**:通过编译时分析优化性能 +- **轻量级响应式系统**:高效的运行时更新机制 + +## 核心特性 + +### 直接状态管理 + +```tsx filename="Counter.jsx" +function Counter() { + let count = 0; // 直接声明状态 + + return ( +
      +

      计数: {count}

      + +
      + ); +} +``` + +### 内置流程控制 + +```tsx filename="UserList.jsx" +function UserList({ users }) { + return ( +
        + + {(user) => ( + +
      • {user.name}
      • +
        + )} +
        +
      + ); +} +``` + +### 计算值 + +```tsx filename="DoubleCounter.jsx" +function DoubleCounter() { + let count = 0; + const double = count * 2; // 自动计算的值 + + return
      双倍值: {double}
      ; +} +``` + +### 监听系统 + +```tsx filename="DataFetcher.jsx" +function DataFetcher() { + let data = null; + + watch(() => { + fetch('https://api.example.com/data') + .then(res => res.json()) + .then(_data => { + data = _data; + }); + }); + + return ( +
      + +
      {JSON.stringify(data, null, 2)}
      +
      + +

      加载中...

      +
      +
      + ); +} +``` + +## 快速开始 + +让我们通过以下章节来学习 openInula 2版本: + +1. [基础概念](./core-concepts/introduction) + +- 组件基础 +- JSX 语法 +- 状态管理 +2. [模板系统](./template-system/conditional) + +- 条件渲染 +- 列表渲染 +- 事件处理 +3. [响应式系统](./reactivity/state) + +- 状态声明 +- 计算值 +- 监听系统 +4. [组件开发](./components/props) + +- Props 传递 +- 组件组合 +- 上下文管理 +5. [生命周期](./lifecycle/mounting) + +- 挂载阶段 +- 卸载阶段 +- 清理操作 diff --git a/packages/website-next/src/app/docs/quick-start/page.mdx b/packages/website-next/src/app/docs/quick-start/page.mdx new file mode 100644 index 00000000..09b2b169 --- /dev/null +++ b/packages/website-next/src/app/docs/quick-start/page.mdx @@ -0,0 +1,141 @@ +--- +id: getting-started +title: 快速入门 +sidebar_label: 快速入门 +--- + +# 快速入门 + +欢迎使用 openInula 2!本节将带你完成环境搭建、插件集成、项目初始化和第一个组件。 + +## 环境要求 + +- Node.js >= 16.14 +- 推荐使用 npm 8+ 或 pnpm/yarn + +## 使用 CLI 快速创建项目 + +OpenInula 提供了官方脚手架工具 `create-inula`,可以一键初始化新项目,无需手动配置。 + +### 安装与使用 + +无需全局安装,直接用 npx 或 npm create: + +```bash filename="create-project.sh" +# 推荐方式(无需全局安装) +npm create inula@latest my-app + +# 或者使用 npx +npx create-inula my-app +``` + +执行命令后,CLI 会引导你选择项目模板、打包方式(如 webpack/vite)等,并自动拉取依赖、初始化目录结构。 + +### 典型交互流程 + +1. 选择项目名称(如 my-app) +2. 选择模板(如 Next-app,后续会有更多模板) +3. 选择打包方式(webpack 或 vite) +4. 自动安装依赖并初始化项目 + +### 目录结构示例 + +```text filename="project-structure.txt" +my-app/ +├── src/ +│ └── main.tsx +├── public/ +│ └── index.html +├── package.json +└── ... +``` + +### 启动开发服务器 + +进入项目目录后,运行: + +```bash filename="start-dev.sh" +npm install +npm start +``` + +即可在浏览器中访问本地开发环境。 + +### 更多用法 + +详细参数和高级用法请参考 [create-inula README](https://github.com/openinula/openinula/tree/main/packages/create-inula/README.md)。 + + +## 集成到主流构建工具 + +OpenInula 提供统一的 unplugin 插件,支持 Vite、Rollup、Webpack、Nuxt、Vue CLI、esbuild 等主流工具。 + +### 安装依赖 + + +```bash filename="install-unplugin.sh" +npm i @openinula/unplugin +``` + +### Vite + +```ts filename="vite.config.ts" +import { defineConfig } from 'vite'; +import inulaNext from '@openinula/unplugin/vite'; + +export default defineConfig({ + plugins: [ + inulaNext({ /* 可选配置 */ }), + ], +}); +``` + +### Rollup + +```js filename="rollup.config.js" +import inulaNext from '@openinula/unplugin/rollup'; + +export default { + plugins: [ + inulaNext({ /* 可选配置 */ }), + ], +}; +``` + +### Webpack + +```js filename="webpack.config.js" +// webpack.config.js +module.exports = { + /* ... */ + plugins: [ + require('@openinula/unplugin/webpack')({ /* 可选配置 */ }) + ] +} +``` + + +## 第一个组件 + +```tsx filename="Hello.jsx" +function Hello() { + return

      你好,OpenInula!

      ; +} +``` + +## 目录结构 + +- src/ 代码目录 +- public/ 静态资源 +- package.json 项目配置 + +## 相关链接 + +- [unplugin 官方文档](https://github.com/unjs/unplugin) +- [OpenInula 插件源码](https://github.com/openinula/openinula/tree/main/next-packages/compiler/unplugin-inula-next) +- [更多示例 playground/](https://github.com/openinula/openinula/tree/main/next-packages/compiler/unplugin-inula-next/playground) + +## 下一步 + +- 阅读[项目介绍](./introduction) +- 深入[基础概念](next/core-concepts/introduction) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/reactivity/computed/page.mdx b/packages/website-next/src/app/docs/reactivity/computed/page.mdx new file mode 100644 index 00000000..f7c45539 --- /dev/null +++ b/packages/website-next/src/app/docs/reactivity/computed/page.mdx @@ -0,0 +1,79 @@ +--- +id: computed +title: 计算值 +sidebar_label: 计算值 +--- + +# 计算值 + +在 openInula 2(zouyu)中,计算值(Computed)是指依赖于其他状态变量的表达式。你只需像写普通 JS 一样声明变量,编译器会自动识别并优化这些依赖关系。 + +## 基本用法 + +```tsx filename="DoubleCounter.jsx" +function DoubleCounter() { + let count = 0; + // 计算值:double 会自动随着 count 变化 + const double = count * 2; + + return ( +
      +

      当前计数:{count}

      +

      双倍值:{double}

      + +
      + ); +} +``` + +## 多重依赖 + +计算值可以依赖多个状态变量: + +```tsx filename="PriceCalculator.jsx" +function PriceCalculator() { + let price = 100; + let quantity = 2; + const total = price * quantity; + + return ( +
      +

      单价:{price}

      +

      数量:{quantity}

      +

      总价:{total}

      + +
      + ); +} +``` + +## 嵌套计算 + +计算值可以嵌套依赖其他计算值: + +```tsx filename="NestedComputed.jsx" +function NestedComputed() { + let a = 1; + const b = a + 2; + const c = b * 3; + + return
      c 的值:{c}
      ; +} +``` + +## 最佳实践 + +- 只需像写普通 JS 一样声明依赖关系,编译器会自动优化。 +- 避免在计算值中产生副作用(如修改外部状态)。 +- 计算值适合用于 UI 展示、派生数据等场景。 + +## 注意事项 + +- 计算值应为纯表达式,不要在其中执行异步操作或副作用。 +- 如果依赖的状态较多,建议提前拆分变量,提升可读性。 + +## 下一步 + +- 了解[监听系统](./watch)的用法 +- 学习[状态管理](./state)的更多技巧 +- 探索[组件组合](../components/composition)的高级用法 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/reactivity/state/page.mdx b/packages/website-next/src/app/docs/reactivity/state/page.mdx new file mode 100644 index 00000000..dcc8478a --- /dev/null +++ b/packages/website-next/src/app/docs/reactivity/state/page.mdx @@ -0,0 +1,293 @@ +--- +id: state +title: 状态管理 +sidebar_label: 状态管理 +--- + +# 状态管理 + +OpenInula 的状态管理采用直观的方式,无需特殊的 API 或 Hook,直接使用 JavaScript 变量和赋值即可。 + +## 基础用法 + +### 声明状态 + +在组件中直接声明变量作为状态: + +```tsx filename="Counter.jsx" +function Counter() { + let count = 0; // 直接声明状态 + + return ( +
      +

      计数:{count}

      + +
      + ); +} +``` + +### 对象状态 + +对于复杂的状态,可以使用对象: + +```tsx filename="UserProfile.jsx" +function UserProfile() { + let user = { + name: '张三', + age: 25, + preferences: { + theme: 'dark', + language: 'zh' + } + }; + + function updateTheme(newTheme) { + user.preferences.theme = newTheme; // 直接修改对象属性 + } + + return ( +
      +

      {user.name}

      +

      年龄:{user.age}

      +
      + 主题:{user.preferences.theme} + +
      +
      + ); +} +``` + +### 数组状态 + +处理数组类型的状态: + +```tsx filename="TodoList.jsx" +function TodoList() { + let todos = [ + { id: 1, text: '学习 OpenInula', done: false }, + { id: 2, text: '写文档', done: false } + ]; + + function addTodo(text) { + todos = [ + ...todos, + { + id: todos.length + 1, + text, + done: false + } + ]; + } + + function toggleTodo(id) { + todos = todos.map(todo => + todo.id === id + ? { ...todo, done: !todo.done } + : todo + ); + } + + return ( +
      + +
        + + {(todo) => ( +
      • toggleTodo(todo.id)} + style={{ + textDecoration: todo.done ? 'line-through' : 'none' + }} + > + {todo.text} +
      • + )} +
        +
      +
      + ); +} +``` + +## 状态更新 + +### 直接赋值 + +最简单的状态更新方式是直接赋值: + +```tsx filename="CounterWithMessage.jsx" +function Counter() { + let count = 0; + let message = ''; + + function increment() { + count++; // 直接赋值 + message = `当前计数:${count}`; // 状态之间可以互相依赖 + } + + return ( +
      +

      {message}

      + +
      + ); +} +``` + +### 批量更新 + +当需要同时更新多个状态时: + +```tsx filename="UserForm.jsx" +function UserForm() { + let formData = { + username: '', + email: '', + age: 0 + }; + + function resetForm() { + // 一次性更新多个字段 + formData = { + username: '', + email: '', + age: 0 + }; + } + + function updateField(field, value) { + formData[field] = value; // 更新单个字段 + } + + return ( + + updateField('username', e.target.value)} + /> + updateField('email', e.target.value)} + /> + updateField('age', parseInt(e.target.value))} + /> + + + ); +} +``` + +## 最佳实践 + +### 1. 状态初始化 + +将复杂的初始状态提取为函数: + +```tsx filename="createInitialState.jsx" +function createInitialState() { + return { + user: null, + preferences: { + theme: 'light', + language: 'zh' + }, + todos: [] + }; +} + +function App() { + let state = createInitialState(); + + function reset() { + state = createInitialState(); // 重置为初始状态 + } + + return ( +
      + {/* 使用状态 */} +
      + ); +} +``` + +### 2. 状态组织 + +对于复杂组件,建议将相关状态组织在一起: + +```tsx filename="ShoppingCart.jsx" +function ShoppingCart() { + let cart = { + items: [], + total: 0, + + addItem(product) { + this.items = [...this.items, product]; + this.updateTotal(); + }, + + removeItem(productId) { + this.items = this.items.filter(item => item.id !== productId); + this.updateTotal(); + }, + + updateTotal() { + this.total = this.items.reduce((sum, item) => sum + item.price, 0); + } + }; + + return ( +
      +

      购物车 ({cart.items.length})

      +

      总计:¥{cart.total}

      + {/* 渲染购物车内容 */} +
      + ); +} +``` + +### 3. 派生状态 + +避免重复存储可以从现有状态计算出的值: + +```tsx filename="TodoApp.jsx" +function TodoApp() { + let todos = []; + + // 好的做法:通过计算获得派生状态 + const completedCount = todos.filter(todo => todo.done).length; + const remainingCount = todos.length - completedCount; + + return ( +
      +

      完成:{completedCount}

      +

      剩余:{remainingCount}

      +
      + ); +} +``` + +## 注意事项 + +1. 避免直接修改复杂对象的深层属性,推荐使用不可变更新模式 +2. 确保状态更新是同步的,避免在异步操作中直接修改状态 +3. 对于大型应用,考虑使用状态管理库 +4. 注意状态的作用域,避免全局状态 + +## 下一步 + +学习完状态管理后,你可以: + +1. 了解[计算值](./computed.mdx)的使用 +2. 探索[监听系统](./watch)的功能 +3. 学习[组件组合](../components/composition)的最佳实践 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/reactivity/untrack/page.mdx b/packages/website-next/src/app/docs/reactivity/untrack/page.mdx new file mode 100644 index 00000000..b96f273f --- /dev/null +++ b/packages/website-next/src/app/docs/reactivity/untrack/page.mdx @@ -0,0 +1,124 @@ +--- +id: untrack +title: untrack(非响应式访问) +sidebar_label: untrack +--- + +# untrack(非响应式访问) + +`untrack` 是 openInula 2(zouyu)响应式系统中的一个高级工具,用于在响应式计算、watch、或其他依赖收集场景下,临时"跳出"依赖追踪,获取某个状态的当前值但不建立响应式依赖。 + +## 作用 + +- **避免依赖收集**:在 computed、watch、或其他响应式回调中,某些变量的读取不希望被追踪为依赖时使用。 +- **性能优化**:减少不必要的响应式更新,避免副作用函数被频繁触发。 +- **实现只读快照**:获取某一时刻的状态快照,而不关心后续变化。 + +## 基本用法 + +```tsx filename="Example.jsx" +import { untrack } from 'openinula'; + +function Example() { + let count = 0; + let log = []; + + watch(() => { + // 只在 count 变化时触发 + log.push(`count: ${count}, time: ${untrack(() => Date.now())}`); + }); + + return ( +
      + +
        + {(item) =>
      • {item}
      • }
        +
      +
      + ); +} +``` + +## Demo 示例 + +下面是一个最小可运行的 untrack 用法示例: + +```tsx filename="Demo.jsx" +import { watch, untrack } from 'openinula'; + +function Demo() { + let a = 0; + let b = 0; + watch(() => { + // 只依赖 b,a 的变化不会触发 watch + console.log('sum:', untrack(() => a) + b); + }); + return ( + <> + + + + ); +} +``` +点击 a 按钮不会触发 watch,点击 b 按钮会触发 watch 并输出 sum。 + +## 在 computed 中使用 + +```tsx filename="ComputedUntrack.jsx" +import { untrack } from 'openinula'; + +function ComputedUntrack() { + let count = 0; + // 只依赖 count,不依赖 Date.now() + const message = `当前计数:${count},时间:${untrack(() => Date.now())}`; + + return
      {message}
      ; +} +``` + +## 在 watch 中使用 + +```tsx filename="WatchUntrack.jsx" +import { untrack } from 'openinula'; + +function WatchUntrack() { + let count = 0; + let lastTime = 0; + + watch(() => { + // 只在 count 变化时触发 + lastTime = untrack(() => Date.now()); + }); + + return ( +
      + +

      上次更新时间:{lastTime}

      +
      + ); +} +``` + +## 在响应式系统的其他场景 + +- **避免副作用循环**:在副作用函数中读取但不追踪依赖,防止死循环。 +- **只读快照**:在复杂计算或日志记录时,获取当前值但不建立响应式关系。 + +## 最佳实践 + +- 仅在确实不希望建立响应式依赖时使用 `untrack`。 +- 用于性能优化、避免不必要的副作用触发。 +- 保持代码可读性,避免滥用。 + +## 注意事项 + +- `untrack` 只影响其回调函数内部的依赖收集。 +- 不要在 `untrack` 内部修改响应式状态,只做只读访问。 +- 滥用 `untrack` 可能导致响应式失效,需谨慎使用。 + +## 相关链接 + +- [计算值(computed)](./computed.mdx) +- [监听系统(watch)](./watch) +- [状态管理](./state.mdx) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/reactivity/watch/page.mdx b/packages/website-next/src/app/docs/reactivity/watch/page.mdx new file mode 100644 index 00000000..9e2e4eae --- /dev/null +++ b/packages/website-next/src/app/docs/reactivity/watch/page.mdx @@ -0,0 +1,114 @@ +--- +id: watch +title: 监听系统 +sidebar_label: 监听系统 +--- + +# 监听系统(watch) + +openInula 2(zouyu)提供了 `watch` 方法,用于监听状态或计算值的变化,并在变化时执行副作用逻辑。 + +## 基本用法 + +```tsx filename="FetchData.jsx" +function FetchData({ url }) { + let data = null; + + watch(() => { + fetch(url) + .then(res => res.json()) + .then(_data => { + data = _data; + }); + }); + + return ( +
      + +
      {JSON.stringify(data, null, 2)}
      +
      + +

      加载中...

      +
      +
      + ); +} +``` + +## 依赖追踪 + +`watch` 会自动追踪其回调中用到的所有状态和计算值,只要依赖发生变化,回调就会重新执行。 + +```tsx filename="Logger.jsx" +function Logger() { + let count = 0; + watch(() => { + console.log('count 变化为:', count); + }); + + return ; +} +``` + +## 清理副作用 + +可以在 `watch` 回调中返回一个清理函数,用于移除定时器、事件监听等副作用: + +```tsx filename="Timer.jsx" +function Timer() { + let time = Date.now(); + + watch(() => { + const timer = setInterval(() => { + time = Date.now(); + }, 1000); + // 返回清理函数 + return () => clearInterval(timer); + }); + + return
      当前时间:{new Date(time).toLocaleTimeString()}
      ; +} +``` + +## 多个 watch + +可以在同一个组件中使用多个 `watch`,分别监听不同的状态: + +```tsx filename="MultiWatch.jsx" +function MultiWatch() { + let a = 1; + let b = 2; + + watch(() => { + console.log('a 变化:', a); + }); + watch(() => { + console.log('b 变化:', b); + }); + + return ( +
      + + +
      + ); +} +``` + +## 最佳实践 + +- 只在需要副作用(如数据请求、日志、定时器等)时使用 `watch` +- 避免在 `watch` 中直接修改依赖自身的状态,防止死循环 +- 善用清理函数,避免内存泄漏 + +## 注意事项 + +- `watch` 回调应为同步函数,避免直接返回 Promise +- 清理函数只在依赖变化或组件卸载时调用 +- 不要在 `watch` 外部直接调用副作用逻辑 + +## 下一步 + +- 学习[状态管理](./state.mdx)的更多用法 +- 了解[计算值](./computed.mdx)的高级技巧 +- 探索[生命周期](../lifecycle/mounting)的管理 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/template-system/conditional/page.mdx b/packages/website-next/src/app/docs/template-system/conditional/page.mdx new file mode 100644 index 00000000..677fc7a5 --- /dev/null +++ b/packages/website-next/src/app/docs/template-system/conditional/page.mdx @@ -0,0 +1,208 @@ +--- +id: conditional +title: 条件渲染 +sidebar_label: 条件渲染 +--- + +# 条件渲染 + +OpenInula 提供了内置的条件渲染标签,使得条件渲染变得简单直观。 + +## 基本用法 + +### if 条件 + +最简单的条件渲染使用 `if` 标签: + +```tsx filename="SimpleCondition.jsx" +function Notification({ message }) { + return ( +
      + +

      {message}

      +
      +
      + ); +} +``` + +### if-else 条件 + +使用 `if` 和 `else` 标签处理两种情况: + +```tsx filename="IfElseCondition.jsx" +function LoginStatus({ isLoggedIn }) { + return ( +
      + + + + + + +
      + ); +} +``` + +### 多重条件 + +使用 `else-if` 处理多个条件: + +```tsx filename="MultipleConditions.jsx" +function TrafficLight({ color }) { + return ( +
      + +

      停止

      +
      + +

      注意

      +
      + +

      通行

      +
      + +

      信号灯故障

      +
      +
      + ); +} +``` + +## 条件表达式 + +条件表达式可以是任何返回布尔值的表达式: + +```tsx filename="ComplexConditions.jsx" +function UserProfile({ user }) { + return ( +
      + = 18}> +

      成年用户

      +
      + +

      高级会员

      +
      +
      + ); +} +``` + +## 嵌套条件 + +条件标签可以嵌套使用: + +```tsx filename="NestedConditions.jsx" +function ProductDisplay({ product, user }) { + return ( +
      + + + + + + + + +

      请登录后购买

      +
      +
      + +

      商品不存在

      +
      +
      + ); +} +``` + +## 最佳实践 + +### 1. 提前返回 + +对于简单的条件判断,可以使用提前返回模式: + +```tsx filename="EarlyReturn.jsx" +function AdminPanel({ user }) { + if (!user) { + return

      请先登录

      ; + } + + if (!user.isAdmin) { + return

      权限不足

      ; + } + + return
      管理员面板
      ; +} +``` + +### 2. 条件组合 + +对于复杂的条件逻辑,建议将条件提取为变量: + +```tsx filename="ComplexConditionLogic.jsx" +function UserAccess({ user, resource }) { + const canView = user && user.permissions.includes('view'); + const canEdit = canView && user.permissions.includes('edit'); + const isOwner = resource.ownerId === user.id; + + return ( +
      + +
      {resource.content}
      + + + +
      + +

      无访问权限

      +
      +
      + ); +} +``` + +### 3. 避免过度嵌套 + +当条件逻辑变得复杂时,考虑将其拆分为多个组件: + +```tsx filename="ComponentComposition.jsx" +function UserActions({ user, resource }) { + return ( +
      + + + + + + +
      + ); +} + +function ViewPermission({ user, children }) { + return ( + + {children} + + +

      无访问权限

      +
      + ); +} +``` + +## 注意事项 + +1. 条件标签必须包含 `cond` 属性 +2. `else-if` 和 `else` 标签必须跟在 `if` 或 `else-if` 标签之后 +3. 条件表达式应该返回布尔值 +4. 避免在条件表达式中进行复杂的计算,建议提前计算并存储结果 + +## 下一步 + +学习完条件渲染后,你可以: + +1. 了解[列表渲染](../list-rendering)的使用方法 +2. 探索[事件处理](../event-handling)系统 +3. 学习[组件组合](../../components/composition)的技巧 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/template-system/event-handling/page.mdx b/packages/website-next/src/app/docs/template-system/event-handling/page.mdx new file mode 100644 index 00000000..6fd5c7f6 --- /dev/null +++ b/packages/website-next/src/app/docs/template-system/event-handling/page.mdx @@ -0,0 +1,304 @@ +--- +id: event-handling +title: 事件处理 +sidebar_label: 事件处理 +--- + +# 事件处理 + +OpenInula 提供了简单直观的事件处理机制,使用 `onXxx` 属性来绑定事件处理函数。 + +## 基本用法 + +### 点击事件 + +最常用的事件处理是点击事件: + +```tsx filename="ClickCounter.jsx" +function ClickCounter() { + let count = 0; + + function handleClick() { + count++; + } + + return ( + + ); +} +``` + +### 内联事件处理 + +对于简单的事件处理,可以直接使用内联函数: + +```tsx filename="SimpleButton.jsx" +function SimpleButton() { + let message = ''; + + return ( +
      + +

      {message}

      +
      + ); +} +``` + +## 常用事件 + +### 表单事件 + +处理表单输入和提交: + +```tsx filename="LoginForm.jsx" +function LoginForm() { + let username = ''; + let password = ''; + + function handleSubmit(e) { + e.preventDefault(); + console.log('提交登录:', { username, password }); + } + + return ( +
      + username = e.target.value} + placeholder="用户名" + /> + password = e.target.value} + placeholder="密码" + /> + +
      + ); +} +``` + +### 鼠标事件 + +处理鼠标相关事件: + +```tsx filename="MouseTracker.jsx" +function MouseTracker() { + let position = { x: 0, y: 0 }; + + return ( +
      { + position = { + x: e.clientX, + y: e.clientY + }; + }} + style={{ height: '200px', background: '#f0f0f0' }} + > +

      鼠标位置:{position.x}, {position.y}

      +
      + ); +} +``` + +### 键盘事件 + +处理键盘输入: + +```tsx filename="KeyboardInput.jsx" +function KeyboardInput() { + let pressedKeys = []; + + return ( + { + pressedKeys = [...pressedKeys, e.key]; + }} + onKeyUp={e => { + pressedKeys = pressedKeys.filter(key => key !== e.key); + }} + placeholder="请按键..." + /> + ); +} +``` + +## 事件修饰符 + +OpenInula 支持事件修饰符来简化常见的事件处理场景: + +```tsx filename="EventModifiers.jsx" +function EventModifiers() { + return ( +
      + {/* 阻止默认行为 */} + e.preventDefault()} href="#"> + 阻止默认跳转 + + + {/* 停止事件传播 */} +
      console.log('外层点击')}> + +
      +
      + ); +} +``` + +## 自定义事件 + +在组件间通信时,可以通过 props 传递自定义事件处理函数: + +```tsx filename="CustomButton.jsx" +function CustomButton({ onClick, children }) { + return ( + + ); +} + +function App() { + return ( + console.log('处理点击')}> + 点击我 + + ); +} +``` + +## 最佳实践 + +### 1. 事件处理函数命名 + +建议使用 `handle` 前缀命名事件处理函数: + +```tsx filename="UserForm.jsx" +function UserForm() { + let formData = { + name: '', + email: '' + }; + + function handleNameChange(e) { + formData.name = e.target.value; + } + + function handleEmailChange(e) { + formData.email = e.target.value; + } + + function handleSubmit(e) { + e.preventDefault(); + console.log('提交表单:', formData); + } + + return ( +
      + + + +
      + ); +} +``` + +### 2. 事件参数处理 + +在需要传递额外参数时,使用箭头函数包装: + +```tsx filename="ItemList.jsx" +function ItemList() { + const items = ['项目1', '项目2', '项目3']; + + function handleItemClick(item, index, e) { + console.log('点击项目:', item, '索引:', index, '事件:', e); + } + + return ( +
        + + {(item, index) => ( +
      • handleItemClick(item, index, e)}> + {item} +
      • + )} +
        +
      + ); +} +``` + +### 3. 性能优化 + +对于频繁触发的事件,考虑使用节流或防抖: + +```tsx filename="SearchInput.jsx" +function SearchInput() { + let searchTerm = ''; + let timeoutId; + + function handleInput(e) { + // 使用防抖处理搜索 + clearTimeout(timeoutId); + timeoutId = setTimeout(() => { + searchTerm = e.target.value; + console.log('搜索:', searchTerm); + }, 300); + } + + willUnmount(() => { + clearTimeout(timeoutId); + }); + + return ( + + ); +} +``` + +## 注意事项 + +1. 事件处理函数中的 `this` 绑定 +2. 避免在渲染函数中创建内联函数 +3. 记得清理定时器和事件监听器 +4. 注意事件冒泡和捕获的顺序 + +## 下一步 + +学习完事件处理后,你可以: + +1. 探索[组件组合](../../components/composition)的技巧 +2. 了解[生命周期](../../lifecycle/mounting)的管理 +3. 学习[状态管理](../../reactivity/state)的最佳实践 \ No newline at end of file diff --git a/packages/website-next/src/app/docs/template-system/list-rendering/page.mdx b/packages/website-next/src/app/docs/template-system/list-rendering/page.mdx new file mode 100644 index 00000000..8703d132 --- /dev/null +++ b/packages/website-next/src/app/docs/template-system/list-rendering/page.mdx @@ -0,0 +1,257 @@ +--- +id: list-rendering +title: 列表渲染 +sidebar_label: 列表渲染 +--- + +# 列表渲染 + +OpenInula 提供了内置的 `for` 标签来实现列表渲染,使得数组的遍历和渲染变得简单直观。 + +## 基本用法 + +### 简单列表 + +使用 `for` 标签遍历数组: + +```tsx filename="FruitList.jsx" +function FruitList() { + const fruits = ['苹果', '香蕉', '橙子']; + + return ( +
        + + {(fruit) =>
      • {fruit}
      • } +
        +
      + ); +} +``` + +### 带索引的列表 + +通过第二个参数获取索引: + +```tsx filename="NumberedList.jsx" +function NumberedList() { + const items = ['第一项', '第二项', '第三项']; + + return ( +
        + + {(item, index) => ( +
      • #{index + 1}: {item}
      • + )} +
        +
      + ); +} +``` + +## 对象列表 + +渲染对象数组: + +```tsx filename="UserTable.jsx" +function UserList() { + const users = [ + { id: 1, name: '张三', age: 25 }, + { id: 2, name: '李四', age: 30 }, + { id: 3, name: '王五', age: 28 } + ]; + + return ( + + + + + + + + + + + {(user) => ( + + + + + + )} + + +
      ID姓名年龄
      {user.id}{user.name}{user.age}
      + ); +} +``` + +## 列表操作 + +### 列表过滤 + +可以在渲染前对列表进行过滤: + +```tsx filename="ActiveUserList.jsx" +function ActiveUserList() { + const users = [ + { id: 1, name: '张三', active: true }, + { id: 2, name: '李四', active: false }, + { id: 3, name: '王五', active: true } + ]; + + const activeUsers = users.filter(user => user.active); + + return ( +
        + + {(user) =>
      • {user.name}
      • } +
        +
      + ); +} +``` + +### 列表排序 + +可以在渲染前对列表进行排序: + +```tsx filename="SortedUserList.jsx" +function SortedUserList() { + const users = [ + { id: 1, name: '张三', age: 25 }, + { id: 2, name: '李四', age: 30 }, + { id: 3, name: '王五', age: 28 } + ]; + + const sortedUsers = [...users].sort((a, b) => a.age - b.age); + + return ( +
        + + {(user) => ( +
      • {user.name} ({user.age}岁)
      • + )} +
        +
      + ); +} +``` + +## 嵌套列表 + +可以嵌套使用 `for` 标签: + +```tsx filename="NestedList.jsx" +function NestedList() { + const departments = [ + { + name: '技术部', + teams: ['前端组', '后端组', '测试组'] + }, + { + name: '产品部', + teams: ['设计组', '运营组'] + } + ]; + + return ( +
      + + {(dept) => ( +
      +

      {dept.name}

      +
        + + {(team) =>
      • {team}
      • } +
        +
      +
      + )} +
      +
      + ); +} +``` + +## 最佳实践 + +### 1. 列表项组件化 + +对于复杂的列表项,建议将其抽取为单独的组件: + +```tsx filename="UserItemComponent.jsx" +function UserItem({ user }) { + return ( +
      + {user.name} +
      +

      {user.name}

      +

      {user.email}

      +
      +
      + ); +} + +function UserList() { + const users = [/* ... */]; + + return ( +
      + + {(user) => } + +
      + ); +} +``` + +### 2. 列表更新优化 + +当列表项可能发生变化时,建议使用不可变数据操作: + +```tsx +function TodoList() { + let todos = [ + { id: 1, text: '学习 OpenInula', done: false }, + { id: 2, text: '写文档', done: false } + ]; + + function toggleTodo(id) { + todos = todos.map(todo => + todo.id === id + ? { ...todo, done: !todo.done } + : todo + ); + } + + return ( +
        + + {(todo) => ( +
      • toggleTodo(todo.id)} + style={{ textDecoration: todo.done ? 'line-through' : 'none' }} + > + {todo.text} +
      • + )} +
        +
      + ); +} +``` + +## 注意事项 + +1. `for` 标签必须包含 `each` 属性 +2. 回调函数必须返回 JSX 元素 +3. 对于大列表,考虑使用分页或虚拟滚动 +4. 避免在渲染函数中进行复杂计算,建议提前处理数据 + +## 下一步 + +学习完列表渲染后,你可以: + +1. 了解[事件处理](../event-handling)系统 +2. 探索[组件组合](../../components/composition)的技巧 +3. 学习[状态管理](../../reactivity/state)的最佳实践 \ No newline at end of file diff --git a/packages/website-next/src/app/error.tsx b/packages/website-next/src/app/error.tsx new file mode 100644 index 00000000..fd91b8bc --- /dev/null +++ b/packages/website-next/src/app/error.tsx @@ -0,0 +1,16 @@ +'use client'; + +export default function Error({ error, reset }: { error: Error; reset: () => void }) { + return ( +
      +

      出错了

      +

      {error.message}

      + +
      + ); +} \ No newline at end of file diff --git a/packages/website-next/src/app/examples/page.tsx b/packages/website-next/src/app/examples/page.tsx new file mode 100644 index 00000000..028441bb --- /dev/null +++ b/packages/website-next/src/app/examples/page.tsx @@ -0,0 +1,34 @@ +"use client"; + +export default function ExamplesPage() { + return ( +
      +
      +
      +
      +

      + 示例库 +

      +
      +
      +
      + +
      +
      +
      +
  • ` 下挂载了组件 ``,组件 `` 返回了一个 html 标题元素。 + +### createElement + +**功能介绍** + +当无法使用 JSX 语法时,可以使用 `createElement` 创建一个 openInula 元素。 + +**接口定义** + +```tsx +function createElement(type: any, setting: any, ...children: any[]): { + [x: string]: any; + vtype: number; + src: null; + type: any; + key: any; + ref: any; + props: any; +} +``` + +* `type`:创建的组件类型; +* `setting`:创建元素时传入的 `props` 对象。 +* `...children`:组件的零个或多个子节点。 + +**示例** + +```tsx +import { createElement } from 'openinula'; + +function Welcome() { + return createElement( + 'h1', + { className: 'welcome' }, + '你好' + ); +} +``` + +在上述示例中,创建了一个 `` 函数组件,这个组件返回了一个 `h1` 元素,其中包含了一个 `className` 属性,属性值为 'welcome',并包含文本内容'你好'。 + +### createPortal + +**功能介绍** + +`createPortal` 可以将某些元素的子元素渲染到 DOM 中的不同位置。 + +**接口定义** + +```tsx +function createPortal(children: any, realNode: any, key?: string): PortalType + +type PortalType = { + vtype: number; + key: null | string; + realNode: any; + children: any; +}; +``` + +* `children`:需要渲染的 openInula 组件; +* `readNode`:是某个已经存在的DOM节点,`children` 将会渲染在该元素中; +* `key`:可选参数,用作 portal key 的独特字符串或数字。 + +**示例** + +```jsx +import { createPortal, render } from 'openinula'; + +function Component() { + return ( +
    +

    这个子节点被放置在父节点 div 中

    + {createPortal( +

    这个子节点被放置在 document body 中

    , + document.body + )} +
    + ); +} +render(, document.getElementById('root')); +``` + +在这段代码中,`createPortal` 函数传入的第一个参数是一个 `

    ` 标签,第二个参数是 `document.body`,意味着这个`

    ` 标签将被创建并插入到文档的 `body` 元素中。这样,即使父组件的 `

    ` 被其他元素覆盖,这个 `

    ` 标签也会被放置在 `body` 的最顶层,而不会被覆盖。 + +> 注意:portal 只改变 DOM 元素所处的位置,而不改变组件在 React 树中的位置。子节点仍能访问父节点的上下文,且事件仍将从子节点冒泡到父节点。 + +### createRef + +**功能介绍** + +`createRef` 用于在类组件中声明一个 `ref` 对象,该对象可以用来引用DOM元素或组件实例。 + +**接口定义** + +```tsx +function createRef(): RefType + +type RefType = { + current: any; +}; +``` + +**示例** + +```jsx +import { Component, createRef, render } from 'openinula'; + +class App extends Component { + inputRef = createRef(); + + handleClick = () => { + this.inputRef.current.value++; + } + + render() { + return ( + <> + + + + ); + } +} +render(, document.getElementById('root')); +``` + +上述示例创建了一个 `App` 组件,通过调用 `createRef()` 函数创建一个 `ref` 对象 `inputRef`。在渲染时,`handleClick` 方法会被调用,它会通过 `this.inputRef.current.value++` 来增加 `input` 元素的值。`input` 元素通过 `ref` 属性引用 `inputRef`。这样就可以通过 `this.inputRef` 来操作输入框。 + +### forwardRef + +**功能介绍** + +`forwardRef` 允许组件通过参数中的 `ref` 将一个 DOM 节点暴露给父组件。 + +**类型定义** + +```tsx +function forwardRef(render: Function): { + vtype: number; + $$typeof: number; + render: Function; +} +``` + +* `render`: 是一个组件渲染函数,可以接收 `props` 和 `ref` 作为参数。 + +**示例** + +```tsx +import { forwardRef, useRef, render } from 'openinula'; + +const MyInput = forwardRef(function MyInput(props, ref) { + const { label, ...otherProps } = props; + return ( + + ); +}); + +export default function Form() { + const ref = useRef(null); + + function handleClick() { + ref.current.value++; + } + + return ( +

    + + + + ); +} +render(
    , document.getElementById('root')); +``` + +上述示例中,`MyInput` 组件通过 `forwardRef` 将 `input` 输入框暴露给父组件 `Form`,这样 `Form` 可以通过该 `ref` 操作该 `inupt`。 + +### lazy + +**功能介绍** + +`lazy` 声明一个懒加载组件,直到该组件第一次被加载前,才会加载该组件的代码。 + +**接口定义** + +```tsx +function lazy(promiseCtor: () => PromiseType<{ + default: T; +}>): LazyComponent> +``` + +* `promiseCtor` 是一个返回 `Promise` 对象的函数,第一次渲染组件前,openInula 才会调用该函数获取组件。 + +**示例** + +```jsx +import { lazy } from 'openinula'; + +const LazyComp = lazy(() => import { App } from './App'); +``` + +在上述示例中,使用`lazy`函数来异步加载``组件。`lazy` 函数接受一个函数,该函数返回一个`import()`语句,用于动态加载组件模块。 + +### memo + +**功能介绍** + +使用 `memo` 函数包裹组件,通常情况下,只要该组件的 props 没有改变,可以防止组件的重新渲染。 + +**接口定义** + +```tsx +function memo(type: any, compare?: ((oldProps: Props, newProps: Props) => boolean) | undefined): { + vtype: number; + $$typeof: number; + type: any; + compare: ((oldProps: Props, newProps: Props) => boolean) | null; +} +``` + +* `type`:需要进行记忆化的组件; +* `compare`:可选参数,是一个函数,接收一对新旧 `props`,判断两者是否完全相同。 + +**示例** + +```jsx +import { memo, useState, render } from 'openinula'; + +const MyComponent = ({ name }) => { + return
    Hello, {name}!
    ; +}; + +// 使用memo将MyComponent包装 +const MemoizedComponent = memo(MyComponent); + +const App = () => { + const [count, setCount] = useState(0); + + const handleClick = () => { + setCount(prevCount => prevCount + 1); + }; + + return ( +
    + {/* 每次更新会重新渲染MyComponent */} + + + {/* 使用MemoizedComponent,只有在name发生变化时才会重新渲染 */} + + +
    + Current count: {count} + +
    +
    + ); +}; +render(, document.getElementById('root')); +``` + +在上述示例中,创建了两个组件,一个是普通 `MyComponent` 组件,一个是使用 `memo` 包装的 `MemoizedComponent`。使用 `memo` 包装的 `MemoizedComponent` 只会在 `props` 的 `name` 属性发生变化时重新渲染。在点击按钮时,由于 `MemoizedComponent` 的 `name` 属性没有变化,所以不会重新渲染。 + +> 注意:在实际场景中,memo可以有效地避免无需更新的组件重新渲染,提高应用的性能。 + +### createContext + +**功能介绍** + +`createContext` 创建一个可供不同组件调用的上下文对象,这样各层组件之间不需要通过逐层传递信息。 + +**接口定义** + +```tsx +function createContext(val: T): ContextType +``` + +* `val`: 是上下文的初始值。 + +**示例** + +```tsx +import { createContext, render, useContext } from 'openinula'; + +const LanguageContext = createContext('zh-cn'); + +function Header() { + const locale = useContext(LanguageContext); + return

    Header {locale}

    ; +} + +function Footer() { + const locale = useContext(LanguageContext); + return

    Footer {locale}

    ; +} + +function Page() { + const locale = useContext(LanguageContext); + return ( +
    +
    +

    Page {locale}

    +
    +
    + ); +} +render(, document.getElementById('root')); +``` + +上述示例展示了 `createContext` 方法的使用方式,可以通过 `createContext` 创建一个供全局组件使用的 `LanguageContext` ,组件可以直接获取,不需要通过逐级传值的方式进行获取。 + +### cloneElement + +**功能介绍** + +`cloneElement` 可以从一个已有元素创建一个新的 Inula 元素。 + +**接口定义** + +```jsx +function cloneElement(element: any, setting: any, ...children: any[]): { + [x: string]: any; + vtype: number; + src: null; + type: any; + key: any; + ref: any; + props: any; +} +``` + +* `element`:需要克隆的 Inula 元素; +* `setting`:克隆后元素的 `props`; +* `...children`:是零个或多个子节点,如果不传入,将使用原始 `element.props.children`。 + +**示例** + +```jsx +import { cloneElement, createElement, render } from 'openinula'; + +function Time({ time }) { + return createElement( + 'h1', + { className: 'clock' }, + 'Time is ', + createElement('i', null, time), + ); +} +function Clock() { + const time = new Date().toLocaleTimeString(); + return cloneElement( +
    \ No newline at end of file diff --git a/packages/website-next/src/app/api/request/page.mdx b/packages/website-next/src/app/api/request/page.mdx new file mode 100644 index 00000000..0d141018 --- /dev/null +++ b/packages/website-next/src/app/api/request/page.mdx @@ -0,0 +1,1302 @@ +欢迎使用`inula-request`请求组件,接下来本文档将对`inula-request` API使用进行一个详细介绍,帮助您更便捷地发送网络请求! + +## Inula-request请求方法引入 + +方便起见,该文档将使用`ir`别名介绍`inula-request`请求方法,即使用如下方式导入请求组件: + +```typescript +import ir from 'inula-request'; +``` + +## Inula-request 全局 API + +### ir(config) + +**功能介绍** + +该请求方法为通用请求方法,可以通过配置`config`参数完成多种形式的网络请求,关于`config`具体参数配置将在[参数配置章节](#请求配置全量参数)详细介绍。 + +**接口定义** + +```typescript +ir(config: IrRequestConfig): Promise>; +``` + +其中请求配置参数类型`IrRequestConfig`和请求响应类型`IrResponse`定义如下: + +```typescript +// 请求配置 +interface IrRequestConfig { + url?: string; + + method?: Method; + + // 公共URL前缀 + baseURL?: string; + + headers?: Record; + + params?: Record | null; + + // 请求参数序列化函数 + paramsSerializer?: (params: any) => string; + + data?: any; + + timeout?: number; + + // 超时错误消息 + timeoutErrorMessage?: string; + + // 是否发送凭据 + withCredentials?: boolean; + + // 响应类型 + responseType?: ResponseType; + + // 上传进度事件回调 + onUploadProgress?: (progressEvent: any) => void; + + // 下载进度事件回调 + onDownloadProgress?: (progressEvent: any) => void; + + // 状态码校验函数 + validateStatus?: (status: number) => boolean; + + // 请求取消令牌 + cancelToken?: CancelToken; + + signal?: AbortSignal; + + // 过渡选项 + transitional?: TransitionalOptions; +} + +// 请求响应 +type IrResponse = { + // 响应数据 + data: T; + + // 响应状态码 + status: number; + + // 响应状态消息 + statusText: string; + + // 响应头 + headers: any; + + // 请求配置 + config: IrRequestConfig; + + // 请求对象 + request?: any; + + // 响应事件消息 + event?: string; +}; +``` + +**示例** + +```typescript +ir({ + url: 'https://www.example.com/data', + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + data: { + name: 'inula-request' + }, + timeout: 5000 +}) + .then(response => { + // 处理成功响应 + }) + .catch(error => { + // 处理错误 + }); +``` + +使用`ir(config)`方法可以灵活地定制请求的各个参数,以满足特定的需求,并注意正确处理成功响应和错误情况。 + +### ir(url[, config]) + +**功能介绍** + +该接口提供一种简化的请求方式,您可以将网络请求的`URL`作为请求方法的第一个参数,省略其他复杂的配置,`inula-request`请求组件将为您发送一个默认的`GET`请求,在多数简单`GET`请求场景中,您可以使用这种方式来简化您的代码。 + +**接口定义** + +```typescript +ir(url: string[, config: IrRequestConfig]): Promise>; +``` + +**示例** + +```typescript +ir('https://www.example.com/data', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + }, +}) + .then(response => { + // 处理成功响应 + }) + .catch(error => { + // 处理错误 + }); + +// 简化写法 +ir('https://www.example.com/data') + .then(response => { + // 处理成功响应 + }) + .catch(error => { + // 处理错误 + }); +``` + +在上面的示例中,将 `url` 作为请求的第一个参数,发送了一个 `GET` 请求,您也可以使用第二个示例这种简化形式,不显式设置请求方法会默认发送 `GET` 请求并配置正确的 `Content-Type` 请求头。 + +### ir.request(config) & ir.request(url[, config]) + +**功能介绍** + +`ir.request(config) & ir.request(url[, config])`为`ir(config) & ir(url[, config])`的完整表达方式,其功能完全等同,接口定义和代码使用用法参见 [ir(config)](#ir(config)) 和 [ir(url[, config])](#ir(config)) 章节。 + +**接口定义** + +参见 [ir(config)](#ir(config)) 和 [ir(url[, config])](#ir(config)) 章节。 + +**示例** + +参见 [ir(config)](#ir(config)) 和 [ir(url[, config])](#ir(config)) 章节。 + +### ir.get(url[, config]) + +**功能介绍** + +该接口将发送`GET`网络请求并返回一个`Promise`对象。 + +**接口定义** + +```typescript +ir.get(url: string, config?: IrRequestConfig): Promise>; +``` + +**示例** + +```typescript +// 使用默认配置发送GET请求 +ir.get('https://www.example.com/data') + .then(response => { + // 请求成功,处理响应数据 + }) + .catch(error => { + // 请求失败,处理错误 + }); + +// 使用自定义配置发送GET请求 +ir.get('https://www.example.com/data', { + params: { + id: 123, + sortBy: 'name' + }, + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Authorization': 'your-token' + } +}) + .then(response => { + // 处理响应数据 + }) + .catch(error => { + // 处理错误 + }); +``` + +上述示例中,通过`ir.get`方法发送一个GET请求到`https://www.example.com/data`。在请求成功后,通过`response.data`访问服务器返回的数据。如果请求失败,将会捕获到`catch`块中的错误并进行处理。 同时,您也可以传入响应头等进行自定义配置请求。 + +### ir.post(url[, data[, config]]) + +**功能介绍** + +该接口将发送`POST`网络请求并返回一个`Promise`对象。 + +**接口定义** + +```typescript +ir.post(url: string, data?: any, config?: IrRequestConfig): Promise>; +``` + +**示例** + +```typescript +// 使用默认配置发送POST请求 +ir.post('https://www.example.com/data', { + name: 'Xiao Ming', + age: 18 +}) + .then(response => { + // 请求成功,处理响应数据 + }) + .catch(error => { + // 请求失败,处理错误 + }); + +// 使用自定义配置发送POST请求 +ir.post('https://www.example.com/data', { + name: 'Xiao Ming', + age: 18 +}, { + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'your-token' + } +}) + .then(response => { + // 处理响应数据 + }) + .catch(error => { + // 处理错误 + }); +``` + +上述示例中,通过`ir.post`方法发送一个POST请求到`https://www.example.com/data`,并传递了一个包含`name`和`age`字段的数据对象。在请求成功后,通过`response.data`访问服务器返回的数据。如果请求失败,将会捕获到`catch`块中的错误并进行处理。 同时,您也可以传入响应头等进行自定义配置请求。 + +### ir.delete(url[, config]) + +**功能介绍** + +该接口将发送`DELETE`网络请求删除`url`上的资源,并返回一个`Promise`对象。 + +**接口定义** + +```typescript +ir.delete(url: string, config?: IrRequestConfig): Promise>; +``` + +**示例** + +```typescript +// 使用默认配置发送DELETE请求 +ir.delete('https://www.example.com/data/123') + .then(response => { + // 删除成功 + }) + .catch(error => { + // 删除失败 + }); + +// 使用自定义配置发送DELETE请求 +ir.delete('https://api.example.com/data/123', { + params: { + force: true + }, + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Authorization': 'your-token' + } +}) + .then(response => { + // 删除成功 + }) + .catch(error => { + // 删除失败 + }); +``` + +上述示例中,通过`ir.delete`方法发送一个DELETE请求删除`https://www.example.com/data/123`上的资源。在请求成功后,服务器成功删除`URL`上的资源。如果请求失败,将会捕获到`catch`块中的错误并进行处理。 同时,您也可以传入响应头等进行自定义配置请求。 + +### ir.head(url[, config]) + +**功能介绍** + +该接口将发送`HEAD`网络请求并返回一个`Promise`对象。HEAD请求方法与GET方法类似,但是服务器不会返回实际内容。它仅返回响应头,包括状态码、响应日期、服务器信息以及其他元数据 。 + +**接口定义** + +```typescript +ir.head(url: string, config?: IrRequestConfig): Promise>; +``` + +**示例** + +```typescript +// 使用默认配置发送HEAD请求 +ir.head('https://api.example.com/data') + .then(response => { + // 请求成功,处理响应头等信息 + }) + .catch(error => { + // 请求失败,处理错误 + }); + +// 使用自定义配置发送HEAD请求 +ir.head('https://api.example.com/data', { + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Authorization': 'your-token' + } +}) + .then(response => { + // 处理响应头等信息 + }) + .catch(error => { + // 请求失败,处理错误 + }); +``` + +上述示例中,通过`ir.head`方法发送一个HEAD请求到`https://api.example.com/data`。在请求成功后,可以通过`response.headers`访问服务器返回的头信息等。如果请求失败,将会捕获到`catch`块中的错误并进行处理。 同时,您也可以传入响应头等进行自定义配置请求。 + +### ir.options(url[, config]) + +**功能介绍** + +该接口将发送`OPTIONS`网络请求目标资源所支持的请求方法、请求头等信息 ,并返回一个`Promise`对象。 + +**接口定义** + +```typescript +ir.options(url: string, config?: IrRequestConfig): Promise>; +``` + +**示例** + +```typescript +// 使用默认配置发送OPTIONS请求 +ir.options('https://www.example.com/data') + .then(response => { + // 请求成功,处理响应 + }) + .catch(error => { + // 请求失败,处理错误 + }); + +// 使用自定义配置发送OPTIONS请求 +ir.options('https://api.example.com/data', { + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Authorization': 'your-token' + } +}) + .then(response => { + // 请求成功,处理响应 + }) + .catch(error => { + // 请求失败,处理错误 + }); +``` + +上述示例中,通过`ir.options`方法发送一个OPTIONS请求到`https://api.example.com/data`。在请求成功后,获取访问服务器支持的请求方法、请求头等信息。如果请求失败,将会捕获到`catch`块中的错误并进行处理。 同时,您也可以传入响应头等进行自定义配置请求。 + +### ir.put(url[, data[, config]]) + +**功能介绍** + +该接口将发送`PUT`网络请求更新或替换现有资源 ,并返回一个`Promise`对象。 + +**接口定义** + +```typescript +ir.put(url: string, data?: any, config?: IrRequestConfig): Promise>; +``` + +**示例** + +```typescript +// 使用默认配置发送PUT请求 +ir.put('https://api.example.com/data/123', { + name: 'Xiao Ming', + age: 18 +}) + .then(response => { + // 请求成功,处理响应 + }) + .catch(error => { + // 请求失败,处理错误 + }); + +// 使用自定义配置发送PUT请求 +ir.put('https://api.example.com/data/123', { + name: 'Xiao Ming', + age: 18 +}, { + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'your-token' + } +}) + .then(response => { + // 请求成功,处理响应 + }) + .catch(error => { + // 请求失败,处理错误 + }); +``` + +上述示例中,通过`ir.put`方法发送一个PUT请求到`https://api.example.com/data/123`,并传递了一个包含`name`和`age`字段的数据对象去更新服务端数据。在请求成功后,说明成功更新了服务端数据。如果请求失败,将会捕获到`catch`块中的错误并进行处理。同时,您也可以传入响应头等进行自定义配置请求。 + +### ir.patch(url[, data[, config]]) + +**功能介绍** + +该接口将发送`PATCH`网络请求更新服务器上现有资源 ,并返回一个`Promise`对象。与 `PUT` 请求不同,`PATCH` 请求是对已存在的资源进行部分更新。它允许客户端发送仅包含要更新的资源的部分数据,而不需要发送整个资源的副本。 + +**接口定义** + +```typescript +ir.patch(url: string, data?: any, config?: IrRequestConfig): Promise>; +``` + +**示例** + +```typescript +// 使用默认配置发送PATCH请求 +ir.patch('https://api.example.com/data/123', { + name: 'Xiao Ming', + age: 18 +}) + .then(response => { + // 请求成功,处理响应数据 + }) + .catch(error => { + // 请求失败,处理错误 + }); + +// 使用自定义配置发送PATCH请求 +ir.patch('https://api.example.com/data/123', { + name: 'Xiao Ming', + age: 18 +}, { + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'your-token' + } +}) + .then(response => { + // 请求成功,处理响应数据 + }) + .catch(error => { + // 请求失败,处理错误 + }); +``` + +上述示例中,通过`ir.patch`方法发送一个PATCH请求到`https://api.example.com/data/123`,并传递了一个包含`name`和`age`字段的数据对象。在请求成功后,说明服务端成功更新了所传入的字段值。如果请求失败,将会捕获到`catch`块中的错误并进行处理。 同时,您也可以传入响应头等进行自定义配置请求。 + +### ir.all(iterable) + +**功能介绍** + +该接口是`inula-request`请求组件中的一个静态方法,用于同时发送多个并发请求。它接收一个可迭代对象`iterable`作为参数,该可迭代对象包含多个`ir`请求实例,方法返回一个Promise对象 。 + +**接口定义** + +```typescript +ir.all(promises: Array>): Promise>; +``` + +**示例** + +```typescript +// 创建多个 ir 请求实例 +const request1 = ir.get('https://www.example.com/data1'); +const request2 = ir.get('https://www.example.com/data2'); +const request3 = ir.get('https://www.example.com/data3'); + +// 发送并发请求 +ir.all([request1, request2, request3]) + .then(responseArray => { + // 请求成功,处理每个请求的响应数据 + responseArray.forEach(response => { + console.log(response.data); + }); + }) + .catch(error => { + // 请求失败,处理错误 + }); +``` + +上述示例中,通过`ir.get`方法创建了三个`ir`请求实例,并将它们放入一个数组中。然后,将这个数组作为参数传递给`ir.all`方法,以同时发送这三个请求。在所有请求成功完成后,通过`responseArray`参数获取每个请求的响应数据,并进行处理。 + +### ir.spread(callback) + +**功能介绍** + +该接口是`inula-request`库中的一个静态方法,用于将多个并发请求的响应数据传递给回调函数进行处理。通常配合`ir.all(iterable)`接口同时使用。 + +**接口定义** + +```typescript +ir.spread(callback: Callback): (arr: any[]) => T; +``` + +**示例** + +```typescript +// 创建多个 ir 请求实例 +const request1 = ir.get('https://www.example.com/data1'); +const request2 = ir.get('https://www.example.com/data2'); +const request3 = ir.get('https://www.example.com/data3'); + +// 发送并发请求 +ir.all([request1, request2, request3]) + .then(ir.spread((response1, response2, response3) => { + // 请求成功,处理每个请求的响应数据 + console.log(response1.data); + console.log(response2.data); + console.log(response3.data); + })) + .catch(error => { + // 请求失败,处理错误 + }); +``` + +上述示例中,通过`ir.get`方法创建了三个`ir`请求实例,并将它们放入一个数组中。然后,使用`ir.all`方法将这个数组作为参数传递给`ir.all`方法,以同时发送这三个请求。在`then`回调中,通过`ir.spread`方法将多个请求的响应数据传递给回调函数进行处理。在回调函数中,可以通过多个参数(`response1`、`response2`、`response3`)访问每个请求的响应数据。 + +### ir.create([config]) + +**功能介绍** + +该接口是`inula-request`请求组件中的一个静态方法,用于创建一个独立的 ir 实例 。 + +**接口定义** + +```typescript +ir.create(config?: IrRequestConfig):IrInstance; +``` + +其中`ir`实例类型`IrInstance`定义如下: + +```typescript +// Ir 类接口类型 +interface IrInterface { + request(url: string | Record, config?: IrRequestConfig): Promise>; + + get(url: string, config?: IrRequestConfig): Promise>; + + post(url: string, data?: any, config?: IrRequestConfig): Promise>; + + put(url: string, data?: any, config?: IrRequestConfig): Promise>; + + delete(url: string, config?: IrRequestConfig): Promise>; + + head(url: string, config?: IrRequestConfig): Promise>; + + options(url: string, config?: IrRequestConfig): Promise>; +} + +// Ir 实例接口类型 +interface IrInstance extends IrInterface { + // Ir 类 + InulaRequest: IrInterface; + + // 创建 Ir 实例 + create: (config?: IrRequestConfig) => IrInstance; + + // 使用内置的配置初始化实例属性 + defaults: IrRequestConfig; + + // 取消当前正在进行的请求 + CancelToken: CancelTokenStatic; + + // 判断是否请求取消 + isCancel: (value: any) => boolean; + + // CanceledError的别名,用于向后兼容 + Cancel: typeof CanceledError; + + // 实例拦截请求 + interceptors: Interceptors; + + // 并发发送多个 HTTP 请求 + all(promises: Array>): Promise>; + + // 封装多个 Promise 至数组,便于作为 all 传入参数 + spread: (callback: Callback) => (arr: any[]) => T; + + // InulaRequest 对象的默认实例 + default: IrInstance; + + CanceledError: typeof CancelError; + + // IrError 错误 + IrError: typeof IrError; + + // 判断输入值是否为 IrError + isIrError: (avl: any) => boolean; + + // IrHeaders 响应头 + IrHeaders: typeof IrHeaders; + + useIR: (url: string, config?: IrRequestConfig, options?: QueryOptions) => { data?: T; error?: any }; +} +``` + +**示例** + +```typescript +// 创建一个独立的 ir 实例 +const instance = ir.create({ + baseURL: 'https://www.example.com', + timeout: 5000, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'your-token' + } +}); + +// 使用独立实例发送请求 +instance.get('/data') + .then(response => { + // 请求成功,处理响应数据 + }) + .catch(error => { + // 请求失败,处理错误 + }); +``` + +上述示例中,使用`ir.create`方法创建了一个名为`instance`的独立`ir`实例。通过传递一个配置对象给`ir.create`方法,指定了实例的默认配置,包括基础`URL`、超时时间和请求头。然后,使用`instance`实例发送GET请求到`https://www.example.com/data`。在请求成功后,通过`response.data`访问服务器返回的数据。如果请求失败,将会捕获到`catch`块中的错误并进行处理。 + +## inula-request 实例 API + +通过`ir.create`方法可以创建一个独立的`ir`实例,您可以更改该实例的默认配置以便在同类场景中发送同类配置的网络请求,您可以创建多个实例以满足多场景下同类请求的发送。 + +方便起见,以下`ir`实例统一使用`instance`代替,实例对象上同样可以进行`request`、`get`、`post`、`delete`、`head`、`options`、`put`及`patch`请求的发送,其接口类型和使用方法与第一章节中各类请求方式一致。 + +```typescript +// 创建一个默认配置的 ir 实例 +const instance = ir.create(); + +// 实例对象上请求方法接口类型 +instance.get(url: string, config?: IrRequestConfig): Promise>; + +instance.get(url: string, config?: IrRequestConfig): Promise>; + +instance.post(url: string, data?: any, config?: IrRequestConfig): Promise>; + +instance.delete(url: string, config?: IrRequestConfig): Promise>; + +instance.head(url: string, config?: IrRequestConfig): Promise>; + +instance.options(url: string, config?: IrRequestConfig): Promise>; + +instance.put(url: string, data?: any, config?: IrRequestConfig): Promise>; + +instance.patch(url: string, data?: any, config?: IrRequestConfig): Promise>; +``` + +## 请求配置全量参数 + +### 请求配置参数使用 + +**功能介绍** + +`inula-request`请求组件可以通过传入请求配置参数`config`自定义网络请求的行为,以便满足您在不同场景下的请求需求。 + +**接口定义** + +```typescript +// 请求配置 +interface IrRequestConfig { + url?: string; + + method?: Method; + + // 公共URL前缀 + baseURL?: string; + + headers?: Record; + + params?: Record | null; + + data?: any; + + timeout?: number; + + // 超时错误消息 + timeoutErrorMessage?: string; + + // 是否发送凭据 + withCredentials?: boolean; + + // 响应类型 + responseType?: ResponseType; + + // 上传进度事件回调 + onUploadProgress?: (progressEvent: any) => void; + + // 下载进度事件回调 + onDownloadProgress?: (progressEvent: any) => void; + + // 请求取消令牌 + cancelToken?: CancelToken; + + signal?: AbortSignal; + + // 过渡选项 + transitional?: TransitionalOptions; +} +``` + +### url + +**参数说明** + +该参数为请求的`URL`地址,类型为`string`。 该参数可以通过请求方法的第一个参数传入,也可以通过`config`配置对象的`url`字段传入。 + +**示例** + +```typescript +ir({ + url: 'https://www.example.com' +}) +``` + +### method + +**参数说明** + +该参数为请求的`HTTP`方法。该参数在使用特定的请求方法时无需传入,在使用通用请求方法时通过`config`配置对象的`method`字段传入。 其类型定义如下: + +```typescript +type Method = 'get' | 'GET' | 'delete' | 'DELETE' | 'head' | 'HEAD' | 'options' | 'OPTIONS' | 'post' | 'POST' | 'put' | 'PUT' | 'patch' | 'PATCH'; +``` + +**示例** + +```typescript +ir('https://www.example.com', { + method: 'GET' +}) +``` + +### baseURL + +**参数说明** + +该参数为请求的公共 `URL` 前缀,类型为 `string`。该参数会自动拼接在传入的 `URL` 之前,通常配合实例化请求使用,提供公共场景下的便利请求方式。 + +**示例** + +```typescript +ir.get('/data', { + baseURL: 'https://www.example.com' +}) +``` + +### headers + +**参数说明** + +该参数为请求的自定义头信息,类型为`Record`。您可以根据自身需求在`config`中配置请求头信息,以满足不同场景的请求需求。 + +**示例** + +```typescript +ir.get('https://www.example.com', { + headers: { + 'Content-Type': 'application/json' + } +}) +``` + +### params + +**参数说明** + +该参数为请求`URL`中的参数,类型为`Record`。该参数可以通过URL请求参数传入或通过`config`配置的`params`参数传入进而自动拼接到`URL`中。 + +**示例** + +```typescript +ir.get('https://www.example.com', { + params: { + id: 123, + limit: 10, + } +}) +``` + +### data + +**参数说明** + +该参数为请求的数据体,类型为任意值。该参数为`POST`、 `PUT` 及 `PATCH` 请求所需要携带的数据,可以通过这些请求的第二个参数传入,也可以通过`config`配置的 `data` 字段传入。 + +**示例** + +```typescript +ir.post('https://www.example.com/data', { + data: { + name: 'Xiao Ming', + age: 18, + } +}) +``` + +### timeout + +**参数说明** + +该参数为请求的超时时间(以毫秒为单位),类型为`number`。 请求过程中超过该配置时间,`inula-request`请求组件会自动中断请求并发送请求超时的错误消息。 + +**示例** + +```typescript +ir.get('https://www.example.com', { + timeout: 5000 +}) +``` + +### timeoutErrorMessage + +**参数说明** + +该参数为请求超时时的错误消息,类型为`string`,该参数需配合`timeout`参数同时使用 。 + +**示例** + +```typescript +ir.get('https://www.example.com', { + timeout: 5000, + timeoutErrorMessage: '请求超时,请重试。', +}) +``` + +### withCredentials + +**参数说明** + +该参数控制是否在跨域请求时包含凭据信息(如果存在),类型为`boolean`。默认情况下,该值为`false`,浏览器不会在跨域请求中发送凭据 。 + +**示例** + +```typescript +ir.get('https://www.example.com', { + withCredentials: true +}) +``` + +### responseType + +**参数说明** + +该参数用于设置请求的响应类型,其类型定义如下: + +```typescript +type ResponseType = 'text' | 'json' | 'blob' | 'arraybuffer'; +``` + +**示例** + +```typescript +ir.get('https://www.example.com', { + responseType: 'json' +}) +``` + +### onUploadProgress + +**参数说明** + +该参数用于设置上传进度事件回调函数。 配置该参数后`inula-request`请求组件将自动检测上传进度,并将进度信息作为参数传递给`onUploadProgress`回调函数。这个参数可以帮助您在UI中显示进度条或其他形式的进度指示器,以使用户能够了解文件上传的进展情况。 + +**示例** + +```typescript +ir.post('https://www.example.com/upload', formData, { + onUploadProgress: function(progressEvent) { + // 计算上传进度的百分比 + const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total); + + // 更新用户界面上的进度条等元素 + console.log('上传进度:' + percentCompleted + '%'); + } +}) +``` + +### onDownloadProgress + +**参数说明** + +该参数用于设置下载进度事件回调函数。 配置该参数后`inula-request`请求组件将自动检测下载进度,并将进度信息作为参数传递给`onDownloadProgress`回调函数。这个参数可以帮助您在 UI 中显示进度条或其他形式的进度指示器,以使用户能够了解文件下载的进展情况。 + +**示例** + +```typescript +ir.get('https://www.example.com/download', { + onDownloadProgress: function(progressEvent) { + // 计算下载进度的百分比 + var percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total); + + // 更新用户界面上的进度条等元素 + console.log('下载进度:' + percentCompleted + '%'); + } +}) +``` + +### cancelToken(不推荐) + +**参数说明** + +该参数用于取消请求操作,它是一个特殊的标记对象,允许您在发送请求之前或请求过程中取消该请求。使用 `cancelToken` 参数可以避免不必要的网络请求,尤其是当您发送多个并发请求时。如果你想在某个请求完成之前取消其中一个或全部请求,便可以使用 `cancelToken`。 + +**示例** + +```typescript +// 首先创建一个 cancelToken 对象 +const CancelToken = ir.CancelToken; +const source = CancelToken.source(); + +// 将 cancelToken 对象作为配置对象的属性传递给请求组件 +ir.get('https://www.example.com/data', { + cancelToken: source.token +}) + +// 在某个时刻您需要取消请求则调用 cancel() 方法 +source.cancel('请求被取消'); +``` + +### signal(推荐) + +**参数说明** + +该参数用于设置一个 `AbortSignal` 对象,用于取消正在进行的请求。`AbortSignal` 是 Web API 的一部分,在现代浏览器中提供了一种用于取消网络请求的机制。 + +**示例** + +```typescript +// 创建一个 AbortController 对象和对应的 AbortSignal +const controller = new AbortController(); +const signal = controller.signal; + +// 发起请求并传入 signal 参数 +ir.get('https://www.example.com/data', { signal }) + .then(response => { + // 请求成功处理逻辑 + }) + .catch(error => { + if (ir.isCancel(error)) { + console.log('请求已取消', error.message); + } else { + console.log('请求发生错误', error.message); + } + }); + +// 在某个时刻您需要取消请求则调用 abort() 方法 +controller.abort(); +``` + +### transitional + +**参数说明** + +该参数可以用来定义一些转换规则,其接口类型定义如下: + +```typescript +interface TransitionalOptions { + // 是否忽略 JSON parse 的错误配置 + silentJSONParsing?: boolean; + + // 强制解析为 JSON 格式 + forcedJSONParsing?: boolean; + + // 请求超时异常错误配置 + clarifyTimeoutError?: boolean; +} +``` + +- `silentJSONParsing`:用于配置解析 `JSON` 时是否静默处理错误,默认为`true`。配置为`true`时,如果发生 `JSON` 解析错误,将不会抛出异常,而是返回解析前的原始数据。 +- `forcedJSONParsing`:用于控制是否强制解析 `JSON` 数据,默认为`true`。配置为`true`时,无论数据的 `MIME` 类型(如`text/plain`)是什么,都会尝试将其解析为 `JSON`。 +- `clarifyTimeoutError`:用于控制是否在超时错误中提供更明确的错误信息,默认为`false`。配置为`true`时,将提供更具体的错误消息,指示发生的超时错误类型。 + +**示例** + +```typescript +ir.get('https://www.example.com', { + transitional: { + silentJSONParsing: true, + forcedJSONParsing: false, + clarifyTimeoutError: false, + } +}) +``` + +## 拦截器 API + +`inula-request`请求组件的拦截器有两种类型:请求拦截器和响应拦截器。 + +### 请求拦截器 + +**功能介绍** + +请求拦截器允许您在发送请求之前对其进行修改或添加特定配置。通过请求拦截器,您可以执行以下操作(任意一项/几项/其他操作): + +> - 修改请求头信息,例如添加身份验证令牌。 +> - 在每个请求中添加通用参数。 +> - 对请求体进行转换。 +> - 拦截请求错误并进行相应处理。 +> - ... + +**接口定义** + +```typescript +ir.interceptors.request.use( + fulfilled?: FulfilledFn, + rejected?: RejectedFn, + options?: { synchronous?: boolean; runWhen?: (value: IrRequestConfig) => boolean } +): number; + +type FulfilledFn = (value: T) => T | Promise; +type RejectedFn = (error: any) => any; +``` + +- `fulfilled`:为请求成功的回调函数,在请求成功时被调用。它接收一个参数类型为 `IrRequestConfig`的配置`config`,表示已经发送请求的配置。 +- `rejected`:为请求失败的回调函数,用于处理请求失败的情况 。 +- `options` :为拦截器的配置参数,用于配置拦截器的行为 。其中`synchronous` 为一个布尔值,指示是否同步地运行拦截器 ; +- `runWhen` 用于确定是否应该运行拦截器,返回值为一个数字 ,表示拦截器的唯一标识符,这个标识符可以用于后续操作,如移除拦截器。 + +**示例** + +```typescript +// 定义一个成功回调函数 +const fulfilledCallback = (config) => { + // 修改请求配置或添加通用参数 + config.headers.Authorization = 'new token'; + return config; +}; + +// 定义一个拒绝回调函数 +const rejectedCallback = (error) => { + console.error('请求失败!', error); + return Promise.reject(error); +}; + +// 定义拦截器选项 +const options = { + synchronous: true, // 选择同步执行拦截器,默认为异步执行 + runWhen: (config) => config.method === 'GET', // 只在请求方法为GET时运行拦截器 +}; + +// 注册拦截器 +const interceptorId = ir.interceptors.request.use( + fulfilledCallback, + rejectedCallback, + options, +); + +// 发起请求 +ir.get('https://www.example.com') + .then((response) => { + console.log('响应数据:', response.data); + }) + .catch((error) => { + console.error('请求出错!', error); + }); + +// 取消拦截器 +ir.interceptors.request.eject(interceptorId); +``` + +在上面示例中,定义了一个成功的回调函数和一个拒绝的回调函数,并配置了 `synchronous` 为 `true` 同步执行拦截器,配置了 `runWhen` 只有在请求方法为 `GET` 时才运行拦截器。将请求拦截器参数传入拦截器接口中,会返回一个拦截器 `id` ,可以用于后续注销。配置拦截器后正常发送请求,在请求发送到服务端之前会进入请求拦截器逻辑,您可以通过请求拦截器更加个性化定制您的请求。 + +### 响应拦截器 + +**功能介绍** + +请求拦截器允许您在发送请求之前对其进行修改或添加特定配置。通过请求拦截器,您可以执行以下操作(任意一项/几项/其他操作): + +- 修改响应头。 +- 在每个响应体添加额外内容。 +- 对响应体进行转换。 +- 拦截错误响应,并进行相应处理。 +- ... + +**接口定义** + +```typescript +ir.interceptors.response.use( + fulfilled?: FulfilledFn>, + rejected?: RejectedFn, + options?: { synchronous?: boolean; runWhen?: (value: IrResponse) => boolean } +): number; + +type FulfilledFn = (value: T) => T | Promise; +type RejectedFn = (error: any) => any; +``` + +- `fulfilled`:为请求成功的回调函数,在请求成功时被调用。它接收一个参数类型为 `IrResponse`的请求响应`response`,表示获取的请求响应。 +- `rejected`:为请求失败的回调函数,用于处理请求失败的情况 。 +- `options` :为拦截器的配置参数,用于配置拦截器的行为 。其中`synchronous` 为一个布尔值,指示是否同步地运行拦截器 ; +- `runWhen` 用于确定是否应该运行拦截器,返回值为一个数字 ,表示拦截器的唯一标识符,这个标识符可以用于后续操作,如移除拦截器。 + +**示例** + +```typescript +// 定义成功处理函数 +const fulfilledCallback = (response) => { + // 修改响应内容 + response.status = 404; + return response; +}; + +// 定义失败处理函数 +const rejectedCallback = (error) => { + console.error('请求失败:', error); + return Promise.reject(error); +}; + +// 定义拦截器选项 +const options = { + synchronous: true, // 选择同步执行拦截器,默认为异步执行 + runWhen: (config) => config.method === 'GET', // 只在请求方法为GET时运行拦截器 +}; + +// 使用ir.interceptors.response.use方法 +const interceptorId = ir.interceptors.response.use( + fulfilledHandler, + rejectedHandler, + options, +); + +// 发起请求 +ir.get('https://www.example.com') + .then((response) => { + console.log('请求结果:', response); + }) + .catch((error) => { + console.error('请求错误:', error); + }); + +// 取消拦截器 +ir.interceptors.response.eject(interceptorId); +``` + +在上面示例中,定义了一个成功的回调函数和一个拒绝的回调函数,并配置了 `synchronous` 为 `true` 同步执行拦截器,配置了 `runWhen` 只有在请求方法为 `GET` 时才运行拦截器。将响应拦截器参数传入拦截器接口中,会返回一个拦截器 `id`,可以用于后续注销。配置拦截器后正常发送请求,在请求被服务端响应后会进入响应拦截器逻辑,您可以通过响应拦截器更加个性化定制您的请求。 + +## 请求错误 + +**功能介绍** + +`inula-request`请求组件提供了`IrError`类用于实例化请求错误对象,其包含了与请求相关的详细信息,以帮助开发者识别和处理错误。 + +**接口定义** + +```typescript +class IrError extends Error implements IrErrorInterface; + +interface IrErrorInterface { + // 产生错误的请求配置对象 + config?: IrRequestConfig; + // 表示请求错误的字符串代码。例如,"ECONNABORTED"表示连接被中止。 + code?: string; + // 产生错误的原始请求实例。 + request?: IrInstance; + // 包含错误响应的响应实例。如果请求成功完成,但服务器返回错误状态码(例如404或500),则此属性存在。 + response?: IrResponse; +} +``` + +**示例** + +```typescript +ir.get('https://www.example.com/users') + .then(response => { + // 处理成功响应 + console.log(response.data); + }) + .catch((error: IrError) => { + if (error.response) { + // 请求已发出,但服务器响应状态码不在 2xx 范围内 + console.log(error.response.data); + console.log(error.response.status); + console.log(error.response.headers); + } else if (error.request) { + // 请求已发出,但没有收到响应 + console.log(error.request); + } else { + // 在设置请求时触发错误,或者发生了一些其他错误 + console.log('Error', error.message); + } + console.log(error.config); + }); +``` + +- 在上面的示例中,使用ir发送一个GET请求到`https://www.example.com/users`。如果请求成功,打印出返回的数据;如果请求失败,捕获`IrError`并根据错误的类型进行处理。 +- 在`catch`块中,可以通过`error.response`访问到服务器返回的响应信息。如果`error.response`存在,则意味着服务器有响应,但状态码不在2xx范围内。可以访问`error.response.data`获取服务器返回的数据,`error.response.status`获取状态码,以及`error.response.headers`获取响应头信息。 +- 如果`error.response`不存在,而`error.request`存在,则表示请求已发送但未收到响应。在这种情况下,可以直接访问`error.request`获取请求对象。 +- 如果以上两种情况都不满足,说明在设置请求时出现了错误,或者其他一些未知的错误,可以通过`error.message`打印错误信息。 + +## 请求取消 + +在`inula-request`请求组件中,提供两种取消请求方式:`cancelToken`和`AbortController`。其中`cancelToken`的方式已过时,推荐使用`AbortController`的取消请求方式。具体使用方式参见 [cancelToken (不推荐)](#cancelToken(不推荐)) 和 [signal(推荐)](#signal(推荐))章节。 + +## 请求实时刷新 API + +**功能介绍** + +`inula-request`请求组件提供支持动态轮询的实时数据刷新能力,帮助您在使用`openinula`框架进行页面开发时拥有更加便捷的请求体验! + +**接口定义** + +```typescript +ir.useIR: (url: string, config?: IrRequestConfig, options?: QueryOptions) => {data?: T, error?: any} + +// 轮询查询配置 轮询间隔(毫秒) +interface QueryOptions { + pollingInterval?: number; + // 是否启用动态轮询策略 + enablePollingOptimization?: boolean; + // 配置动态轮询策略后生效 + limitation?: Limitation; + // 动态轮询策略分析历史查询容量,默认100 + capacity?: number; + // 动态轮询策略窗口大小,默认5 + windowSize?: number; +} + +interface Limitation { + minInterval: number, + maxInterval: number, +} +``` + +`url`和`config`参数和`inula-request`请求组件接口参数一致,用于配置网络请求。 + +`options`参数为动态轮询配置参数,其中: + +- 配置`pollingInterval`参数后将开启实时数据刷新功能,`inula-request`请求组件会根据`pollingInterval`的间隔轮询请求服务端,当请求的服务端数据发生改变时会通知组件拿到最新数据并重新渲染; +- `enablePollingOptimization`参数用于开启动态轮询策略,该参数配置为`true`时,会启动动态轮询策略,`inula-request`请求组件将分析历史请求数据,动态更新轮询间隔(若服务器数据变化频繁则会缩短轮询间隔时间,反之增加轮询间隔时间,最大保证用户体验一致性的同时减缓服务器压力),动态轮询间隔会有一个默认的最大间隔时间`60000ms`和最小间隔时间`100ms`; +- 您也可以通过`limitation`中的`maxInterval`参数来配置最大间隔时间,`minInterval`参数配置最小间隔时间; +- 您也可以自定义动态轮询策略的配置参数,通过`capacity`参数来设置分析的历史数据容量,组件内部会通过您设置的数据容量分析数据更新的间隔趋势,以更新当前的轮询时间。通过`windowSize`设置动态轮询策略滑动窗口大小,该参数用于帮助用户更加细粒度控制分析数据变化趋势的梯度范围,以提供更加精准的轮询间隔设置。 + +通过以上参数,您可以更加灵活的配置实时数据刷新特性以满足您在不同场景下的使用需求。 + +**示例** + +```typescript +import { useIR } from 'inula-request'; + +const App = () => { + const options = { + pollingInterval: 3000, + enablePollingOptimization: true, + limitation: {minInterval: 500, maxInterval: 4000} + }; + const { data, error } = useIR('https://www.example.com', null, options); + + return ( +
    +
    {error ? error.message : data }
    +
    + ); +} +``` + +在上面的示例中,`App`组件使用`useIR`获取了服务端的最新数据,并配置了动态轮询策略。若请求成功则会将服务端数据显示在`pre`标签中,当服务器数据发生变化,`pre`标签中也会同步刷新最新数据,当请求发生错误,将会显示错误信息。 + + diff --git a/packages/website-next/src/app/api/router/page.mdx b/packages/website-next/src/app/api/router/page.mdx new file mode 100644 index 00000000..cdede395 --- /dev/null +++ b/packages/website-next/src/app/api/router/page.mdx @@ -0,0 +1,713 @@ +## Inula-router 组件式API + +### BrowserRouter + +**功能介绍** + +使用`BrowserRouter`组件包裹整个应用,它提供一个`history`对象来管理浏览器的历史记录,`BrowserRouter`使用HTML5的`history API`来实现路由。 + +**接口定义** + +```tsx +type BrowserRouterProps = { + basename: string; + getUserConfirmation: (message: string, callBack: (isJump: boolean) => void) => void; + children?: InualNode; + forceRefresh: boolean; +}; +``` + + + +- `basename`:一个字符串,用于指定路由的根路径。如`/app`,这样所有的网页都会以`/app`开头,比如`/app/home`、`/app/user`等。 +- `getUserConfirmation`:一个函数,作用是自定义用户在导航到新的历史记录条目时的确认提示。它接受两个参数:message 和 callback。message 是一个字符串,表示要显示给用户的提示信息。callback 是一个函数,它接受一个布尔值作为参数,表示用户是否确认导航。默认使用函数`callBack(window.confirm(message))`。 +- `forceRefresh`:是否再路由跳转后强制页面刷新。 + +> 说明: +> `BrowserRouter`支持在`history.push`,`history.replace`方法中传递`state`,`state`是一个任意对象,它可以存储一些数据,并通过浏览器API`history.state`或[`useLocation`](#useLocation)访问该对象。 + +**示例** + +```tsx +import { BrowserRouter, Link, Route, Switch } from 'inula-router'; + +function App() { + return ( + + Home + About + +

    Home page

    } /> +

    About Page

    } /> +
    +
    + ); +} +``` + + + +### HashRouter + +**功能介绍** + +使用`HashRouter`组件包裹整个应用,它提供一个`history`对象来管理浏览器的历史记录,`HashRouter`使用`URL`的`hash`值来实现路由,会在`URL`中显示`#`符号。 + +**接口定义** + +```tsx +type HashRouterProps = { + basename: string; + getUserConfirmation: (message: string, callBack: (isJump: boolean) => void) => void; + children?: InualNode; + hashType: urlHashType; +}; +``` + + + +- `basename`:一个字符串,用于指定路由的根路径。如`/app`,这样所有的网页都会以`/app`开头,比如`/app/home`、`/app/user`等。 +- `getUserConfirmation`:一个函数,作用是自定义用户在导航到新的历史记录条目时的确认提示。它接受两个参数:message 和 callback。message 是一个字符串,表示要显示给用户的提示信息。callback 是一个函数,它接受一个布尔值作为参数,表示用户是否确认导航。默认使用函数`callBack(window.confirm(message))`。 +- `hashType`:`window.location.hash` 使用的编码类型。可用值为“slash“和”noslash”,默认为“slash”。 + - `slash`:创建如#/api/web的hash值。 + - `noslash`:创建如#api/web的hash值。 + +> 说明: +> `HashRouter`使用`URL`的`hash`来表示路由,不使用`history API`,因此不支持在`history.push`,`history.replace`中传递state。 + +**示例** + +```tsx +import { HashRouter, Link, Route, Switch } from 'inula-router'; + +function App() { + return ( + + Home + About + +

    Home page

    } /> +

    About Page

    } /> +
    +
    + ); +} +``` + + + +### Switch + +**功能介绍** + +`Switch`用于包裹多个`Route`或`Redirect`,并根据当前的`URL`匹配第一个合适的组件进行渲染。 + +**接口定义** + +```tsx +type SwitchProps = { + location?: Location; + children?: Inula.InualNode; +}; +``` + + + +- `location`:指定匹配子元素时的位置(默认为浏览器当前的URL)。 + +> 说明: +> 所有的Route组件和Redirect组件都应该被Switch组件包裹,Switch会遍历所有的子元素,第一个匹配成功的Route组件会被渲染,其他的会被忽略。 + +**示例** + +```tsx +import { BrowserRouter, Link, Route, Switch } from 'inula-router'; + +// 定义一些页面组件 +const Home = () =>

    Home Page

    ; +const About = () =>

    About Page

    ; +const Contact = () =>

    Contact Page

    ; +const NotFound = () =>

    404 Not Found

    ; + +// 定义一个 App 组件,使用 BrowserRouter 和 Switch 来创建路由 +const App = () => { + return ( + +
    + Home + About + Contact + {/* 使用 Switch 来渲染匹配到的第一个子路由 */} + + {/* 使用 exact 属性来确保只有当 URL 完全匹配时才渲染组件 */} + + + + {/* 使用 * 来匹配上述以外的 URL,渲染 NotFound 组件 */} + + +
    +
    + ); +}; +``` + + + +### Route + +**功能介绍** + +`Route`是一个定义了路径和组件的映射关系的组件,其基本功能是当路径与当前URL匹配时呈现对应组件。 + +**接口定义** + +```tsx +type RouteProps

    = {}, Path extends string = string> = { + location?: Location; + component?: Inula.ComponentType> | Inula.ComponentType | undefined; + children?: ((props: RouteChildrenProps

    ) => Inula.InulaNode) | Inual.InulaNode; + render?: (props: RouteComponentProps

    ) => Inula.InulaNode; + path?: Path | Path[]; + exact?: boolean; + sensitive?: boolean; + strict?: boolean; +}; +``` + + + +- `location`:指定匹配子元素时的位置(默认为浏览器当前的URL)。 +- `render`,`component`,`children` 是渲染组件的三种方式,这三种方式互斥,只会执行其中一个,优先级是`children` > `component` > `render`。 +- `path`:定义该组件对应的URL。 +- `exact`:仅当path与浏览器URL完全匹配时才匹配到该路由。 +- `sensitive`:在路由匹配时是否忽略大小写。 +- `strict`:路由匹配时是否忽略URL尾部的“/”。 + +> 说明: +> 当使用`component`传递组件渲染UI时,router将会用createElement来将给定的组件创建一个新的element,会执行组件对应的生命周期函数,而`render`和`children`这两种方式不会。 + +**示例** + +```tsx +import { BrowserRouter, Link, Route, Switch } from 'inula-router'; + +const Home = () =>

    Home Page

    ; +const About = () =>

    About Page

    ; +const Contact = () =>

    Contact Page

    ; + +const App = () => { + return ( + + Home + About + Contact + + {/* 使用 Route 渲染匹配到路径的对应组件 */} + {/* 使用 exact 属性来确保只有当 URL 完全匹配时才渲染组件 */} + + {/* 使用 render 属性来直接渲染一个内联函数返回的组件 */} + } /> + {/* 使用 children 属性来渲染一个无论是否匹配都会显示的组件 */} + } /> + + + ); +}; +``` + + + +### Link + +**功能介绍** + +`Link`是一个可以生成超链接的组件,可以在不刷新页面的情况下跳转到其他路由。 + +**接口定义** + +```tsx +type LinkProps = { + component?: Inula.ComponentType; + to: Partial | string | ((location: Location) => string | Partial); + replace?: boolean; + tag?: string; +} & Inula.AnchorHTMLAttributes; +``` + + + +- `to`:将一条记录加入到历史栈中来导航到一个新的 URL,可以为字符串、Location对象或函数。 +- `replace`:单击链接将替换而不是加入一个新的历史记录。 +- `component`:自定义导航组件。 +- `tag`:生成Link使用的HTML标签,默认为``。 + +**示例** + +```tsx +import { HashRouter, Link, Route, Switch } from 'inula-router'; + +function App() { + return ( + + {/* 使用 Link 跳转到对应的路径,Link组件只能在Router下使用 */} + Home + About + +

    Home page

    } /> +

    About Page

    } /> +
    +
    + ); +} +``` + + + +### NavLink + +**功能介绍** + +与`Link`组件相同,可以在不刷新页面的情况下跳转到其他路由。当呈现的组件与当前`URL`匹配时,`NavLink`会为元素添加对应的样式。 + +**接口定义** + +```tsx +type NavLinkProps = { + to: Partial | string | ((location: Location) => string | Partial); + isActive?: (match: Matched | null, location: Location) => boolean; +} & LinkProps; +``` + + + +- `isActive`:指定一个函数,以确定该链接是否处于激活状态,当处于激活状态``标签的`aria-current`属性为`page`。 + +**示例** + +```tsx +import { HashRouter, Link, Route, Switch, NavLink } from 'inula-router'; + +function App() { + return ( + + {/* 使用 NavLink 跳转到对应的路径,NavLink组件只能在Router下使用 */} + Home + About + +

    Home page

    } /> +

    About Page

    } /> +
    +
    + ); +} +``` + + + +### Redirect + +**功能介绍** + +`Redirect`是一个可以执行重定向操作的组件,它可以在路由匹配时跳转到另一个路由。 + +**接口定义** + +```tsx +type RedirectProps = { + to: string | Partial; + push?: boolean; + path?: string; + from?: string; + exact?: boolean; + strict?: boolean; +}; +``` + + + +- `to`:重定向跳转到的位置。 +- `push`:重定向是否替换而不是加入一个新的历史记录。 +- `path`、`from`:用来指定重定向的目标路径,当URL为path或from的地址时,触发重定向。 +- `exact`:仅当path与浏览器URL完全匹配时才匹配到该路由。 +- `strict`:路由匹配时是否忽略URL尾部的“/”。 + +> 说明: +> `path`和`from`两个属性都可以用来指定重定向的目标路径,若两者同时设置,`path`的优先级高于`from`。 + +**示例** + +```tsx +import { HashRouter, Link, Route, Switch, Redirect } from 'inula-router'; + +function App() { + return ( + + {/* 使用 Link 跳转到对应的路径,Link组件只能在Router下使用 */} + Home + About + +

    Home page

    } /> +

    About Page

    } /> + + {/* 当URL匹配不到时,使用Redirect组件跳转到Home页面 */} + +
    +
    + ); +} +``` + + + +### Prompt + +**功能介绍** + +`Prompt`组件用于在用户离开页面时,弹出提示确认用户是否执行跳转行为,提示的回调函数返回布尔值,如果为`true`,则离开页面,如果为`false`,则停留在该页。 + +**接口定义** + +```tsx +type PromptProps = { + message?: string | ((location: Partial, action: Action) => string | boolean); + when?: boolean | ((location: Partial) => boolean); +}; + +enum Action { + pop = 'POP', + push = 'PUSH', + replace = 'REPLACE', +} + +type Location = { + pathname: string; + search: string; + hash: string; + state?: object; +}; +``` + + + +- `message`:当用户尝试离开时提示用户的消息。将通过用户尝试导航到的下一个位置时。返回一个字符串以向用户显示提示,或返回`true`以允许用户跳转。 +- `when`:指定在对应条件下渲染`Prompt`以阻止用户跳转页面。 + +**示例** + +在该实例中,当用户在`Input`中输入字符后再跳转到其他页面时,`Prompt`组件会阻止路由跳转并询问用户是否执行跳转。 + +```tsx +import { useState } from 'openinula'; +import { BrowserRouter, Link, Switch, Route, Prompt } from 'inula-router'; + +function PromptDemo() { + return ( + + Form + Other Page + + + } /> + Other Page} /> + + + ); +} + +function InputForm() { + let [isBlocking, setIsBlocking] = useState(false); + + return ( + { + event.preventDefault(); + setIsBlocking(false); + }} + > + + `你是否确认前往 ${location.pathname}` + } + /> + + { + setIsBlocking(event.target.value.length > 0); + }} + /> + + ); +} +``` + + + +## Inula-router 函数式API + +### useHistory + +**功能介绍** + +`useHistory`是一个函数,调用`useHistory`返回`inula-router`中的`history`对象。 + +**定义** + +```tsx +function useHistory(): History +``` + + + +* History对象具有的属性: + - `length`: 历史记录栈的长度。 + - `action`: 当前导航的动作类型,可以是`PUSH`、`REPLAC`E或`POP`。 + - `location`: 当前的位置对象,包含`pathname`、`search`、`hash`和`state`等属性。 +* history具有的方法: + - `push(path,state)`: 用于向历史记录栈中添加一个新的位置,并导航到该位置。 + - `replace(path,state)`: 用于替换历史记录栈中的当前位置,并导航到新的位置。 + - `go(n)`: 用于在历史记录栈中向前或向后跳转指定的步数。 + - `goBack()`: 用于回退到历史记录栈中的上一个位置,等价于go(-1)。 + - `goForward()`: 用于前进到历史记录栈中的下一个位置,等价于go(1)。 + - `block()`: 用于阻止导航,并在导航发生时执行一个回调函数。 + - `listen()`: 用于注册一个监听器,当历史记录发生变化时执行。 + +**示例** + +```tsx +import { useHistory } from 'inula-router'; + +function HomeButton() { + let history = useHistory(); + + function handleClick() { + history.push('/home'); + } + + return ( + + ); +} +``` + + + +### useLocation + +**功能介绍** +`useLocation`是一个函数,调用`useLocation`返回一个`Location`对象,包含当前`URL`信息,如路径名、查询字符串、哈希。当浏览器的`URL`发生变化,`useLocation`就会随之变化。 + +**定义** + +```tsx +function useLocation(): Location; + +// Location对象结构 +type Location = { + pathname: string; // URL路径名 + search: string; // URL查询字符串 + hash: string; // URL哈希值 + state: Object; // 额外状态数据 +}; +``` + + + +**示例** + +```tsx +import { useLocation } from 'inula-router'; + +function App() { + {/* 使用useLocation获取当前位置 */} + let location = useLocation(); + + useEffect(() => { + console.log('location change to ', location); + }, [location]); +} +``` + + + +### useParams + +**功能介绍** + +`useParams`是一个函数,调用`useParams`返回一个包含当前URL下路由参数的对象,比如 /user/:id 中的 id 。 + +**定义** + +```tsx +function useParams(): Params | {}; + +type Params = { [K in keyof P]?: P[K] }; +``` + + + +**示例** + +```tsx +import { HashRouter, Switch, Route, useParams } from 'inula-router'; + +const User = () => { + // 使用 useParams 获取URL中对应的参数 + const { userid } = useParams(); + + return
    {userid} profile page
    ; +}; + +function App() { + return ( + + + }/> + + + ); +} +``` + + + +### useRouteMatch + +**功能介绍** + +`useRouteMatch`返回一个包含当前路由的匹配信息的`match`对象,可以在无需``的情况下访问匹配数据,`useRouteMatch`对于那些非路由但自身状态与当前路径相关的组件非常有用。 + +**定义** + +```tsx +function useRouteMatch

    (path?: string): Matched

    | null + +// match对象结构 +type Matched = { + score: number[]; // 匹配到该URL的匹配分数 + params: Object; // 从URL中解析出来的与path对应的参数 + path: string; // 匹配使用的URL模板 + url: string; // 匹配到的URL部分 + isExact: boolean; // 是否完全匹配URL +}; +``` + + + +**示例** + +- 不使用`useRouteMatch` + +```tsx +import { BrowserRouter, Switch, Route } from 'inula-router'; + +// Header组件只会在匹配`/detail/:id`时出现 +const Header = () => { + return ( + { + return match &&

    Header
    + }} + /> + ) +} +function App() { + return ( + +
    + +
    Home
    }/> +
    Detail
    }/> +
    + + ); +} +``` + + + +- 使用`useRouteMatch` + +```tsx +import { BrowserRouter, Switch, Route, useRouteMatch } from 'inula-router'; + +// Header组件只会在匹配`/detail/:id`时出现 +const Header = () => { + // 只有当前路径匹配`/detail/:id`时,match不为null + const match = useRouteMatch('/detail/:id') + return ( + match &&
    Header
    + ) +} +function App() { + return ( + +
    + +
    Home
    }/> +
    Detail
    }/> +
    + + ); +} +``` + + + +### withRouter + +**功能介绍** + +`withRouter`是一个高阶函数组件,可以将inula-router的`history`,`location`,`match`三个对象注入到任何自定义组件中的props中。 + +* `history` + - `length`: 历史记录栈的长度。 + - `action`: 当前导航的动作类型,可以是PUSH、REPLACE或POP。 + - `location`: 当前的位置对象,包含pathname、search、hash和state等属性。 + - `push(path,state)`: 用于向历史记录栈中添加一个新的位置,并导航到该位置。 + - `replace(path,state)`: 用于替换历史记录栈中的当前位置,并导航到新的位置。 + - `go(n)`: 用于在历史记录栈中向前或向后跳转指定的步数。 + - `goBack()`: 用于回退到历史记录栈中的上一个位置,等价于go(-1)。 + - `goForward()`: 用于前进到历史记录栈中的下一个位置,等价于go(1)。 + - `block()`: 用于阻止导航,并在导航发生时执行一个回调函数。 + - `listen()`: 用于注册一个监听器,当历史记录发生变化时执行。 +* `location` + - `pathname`: URL路径名。 + - `search`: URL查询字符串。 + - `hash`: URL哈希值。 + - `state`: 额外状态数据。 +* `match` + - `score`: 匹配到该URL的匹配分数。 + - `params`: 从URL中解析出来的与path对应的参数. + - `path`: 匹配使用的URL模板。 + - `url`: 匹配到的URL部分。 + - `isExact`: 是否完全匹配URL。 + +**示例** + +```tsx +import Inula from 'openinula'; +import { withRouter } from 'inula-router'; + +class DemoComponent extends Inula.Component { + // 可以在这里使用this.props.history、this.props.location、this.props.match等属性 + + toHome = () => { + this.props.history.push('/home'); // 通过history对象push方法返回首页 + }; + + render() { + return ( + + ); + } +} + +export default withRouter(DemoComponent) // 使用withRouter包裹组件 +``` \ No newline at end of file diff --git a/packages/website-next/src/app/blog/[slug]/page.tsx b/packages/website-next/src/app/blog/[slug]/page.tsx new file mode 100644 index 00000000..6accc86e --- /dev/null +++ b/packages/website-next/src/app/blog/[slug]/page.tsx @@ -0,0 +1,108 @@ +import React from "react"; +import Link from "next/link"; +import Image from "next/image"; +import { compileMdx } from "nextra/compile"; +import { MDXRemote } from "nextra/mdx-remote"; + +const BLOG_API = + "https://openinula-website.obs.ap-southeast-1.myhuaweicloud.com/data/blogData.json"; +const MD_BASE = + "https://openinula-website.obs.ap-southeast-1.myhuaweicloud.com/doc/"; + +async function getBlogData() { + const res = await fetch(BLOG_API, { cache: "no-store" }); + if (!res.ok) throw new Error("无法获取博客数据"); + return res.json(); +} + +async function getBlogMd(slug: string) { + const url = `${MD_BASE}blog.${slug}.md`; + const res = await fetch(url, { cache: "no-store" }); + if (!res.ok) return null; + return res.text(); +} + +// 你可以在这里自定义 mdx 组件 +const components = { + // 例如:MyComponent: () =>
    My Component
    , +}; + +interface BlogParams { + slug: string; +} + +interface BlogData { + key: string | number; + title: string; + author: string; + time: string; + type: string; + img?: string; +} + +export default async function BlogDetailPage({ + params, +}: { + params: Promise; +}) { + const resolvedParams = await params; + const blogs = await getBlogData(); + const blog = blogs.find( + (b: BlogData) => String(b.key) === resolvedParams.slug + ); + if (!blog) { + return ( +
    + 未找到对应博客 +
    + ); + } + const mdContent = await getBlogMd(resolvedParams.slug); + if (!mdContent) { + return ( +
    + 博客正文加载失败 +
    + ); + } + // 编译 mdx 内容 + const compiled = await compileMdx(mdContent); + return ( +
    +
    + {/* 封面图 */} + {blog.img && ( + {blog.title} + )} + {/* 标题 */} +

    + {blog.title} +

    + {/* 作者/时间/类型 */} +
    + 作者:{blog.author} + 发表于:{blog.time} + + {blog.type} + +
    + {/* 正文 */} +
    + +
    +
    + + ← 返回博客列表 + +
    + ); +} diff --git a/packages/website-next/src/app/blog/components/BlogCard.tsx b/packages/website-next/src/app/blog/components/BlogCard.tsx new file mode 100644 index 00000000..10315fec --- /dev/null +++ b/packages/website-next/src/app/blog/components/BlogCard.tsx @@ -0,0 +1,57 @@ +import Link from "next/link"; +import { MagicCard } from "@/components/magicui/magic-card"; +import React from "react"; + +type BlogItem = { + key: number; + img?: string; + title: string; + time: string; + author: string; + type: string; + tags?: string[]; +}; + +interface BlogCardProps { + blog: BlogItem; + theme: string | undefined; +} + +export default function BlogCard({ blog, theme }: BlogCardProps) { + return ( + + +
    +
    + {blog.img ? ( + + ) : ( +
    B
    + )} +
    +
    {blog.title}
    +
    + {blog.author || "-"} + · + {blog.type} +
    +
    +
    +
    + {/* 标签区,预留 */} + 标签 + {/* 时间 */} + {blog.time} +
    +
    +
    + + ); +} \ No newline at end of file diff --git a/packages/website-next/src/app/blog/components/BlogFilterBar.tsx b/packages/website-next/src/app/blog/components/BlogFilterBar.tsx new file mode 100644 index 00000000..01002e6d --- /dev/null +++ b/packages/website-next/src/app/blog/components/BlogFilterBar.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import { Select } from "antd"; + +interface BlogFilterBarProps { + type: string; + onTypeChange: (value: string) => void; + keyword: string; + onKeywordChange: (e: React.ChangeEvent) => void; + onClearKeyword: () => void; + typeOptions: { label: string; value: string }[]; +} + +export default function BlogFilterBar({ + type, + onTypeChange, + keyword, + onKeywordChange, + onClearKeyword, + typeOptions, +}: Readonly) { + return ( +
    + {/* 类型筛选 */} +
    + 类型 + + {keyword && ( + + )} +
    +
    + ); +} \ No newline at end of file diff --git a/packages/website-next/src/app/blog/components/BlogList.tsx b/packages/website-next/src/app/blog/components/BlogList.tsx new file mode 100644 index 00000000..82bd1493 --- /dev/null +++ b/packages/website-next/src/app/blog/components/BlogList.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import BlogCard from "./BlogCard"; + +type BlogItem = { + key: number; + img?: string; + title: string; + time: string; + author: string; + type: string; + tags?: string[]; +}; + +interface BlogListProps { + blogs: BlogItem[]; + theme: string | undefined; +} + +export default function BlogList({ blogs, theme }: BlogListProps) { + return ( +
    + {blogs.map((item) => ( + + ))} +
    + ); +} \ No newline at end of file diff --git a/packages/website-next/src/app/blog/components/BlogPagination.tsx b/packages/website-next/src/app/blog/components/BlogPagination.tsx new file mode 100644 index 00000000..d1182cca --- /dev/null +++ b/packages/website-next/src/app/blog/components/BlogPagination.tsx @@ -0,0 +1,31 @@ +import React from "react"; + +interface BlogPaginationProps { + page: number; + totalPages: number; + total: number; + onPrev: () => void; + onNext: () => void; +} + +export default function BlogPagination({ page, totalPages, total, onPrev, onNext }: BlogPaginationProps) { + return ( +
    + + 共 {total} 条,{page}/{totalPages || 1} 页 + +
    + + +
    +
    + ); +} \ No newline at end of file diff --git a/packages/website-next/src/app/blog/page.tsx b/packages/website-next/src/app/blog/page.tsx new file mode 100644 index 00000000..f3113d1a --- /dev/null +++ b/packages/website-next/src/app/blog/page.tsx @@ -0,0 +1,138 @@ +"use client"; + +import React, { useEffect, useState, useMemo } from "react"; +import { useTheme } from "next-themes"; +import BlogFilterBar from "./components/BlogFilterBar"; +import BlogList from "./components/BlogList"; +import BlogPagination from "./components/BlogPagination"; +import { MagicCard } from "@/components/magicui/magic-card"; + +const BLOG_API = "https://openinula-website.obs.ap-southeast-1.myhuaweicloud.com/data/blogData.json"; +const PAGE_SIZE = 10; +const TYPE_OPTIONS = [ + { label: "全部", value: "" }, + { label: "编程语言", value: "编程语言" }, + { label: "技术分享", value: "技术分享" }, + { label: "官方文档", value: "官方文档" }, + { label: "会议纪要", value: "会议纪要" }, +]; + +type BlogItem = { + key: number; + img?: string; + title: string; + time: string; + author: string; + type: string; + tags?: string[]; +}; + +export default function BlogOverview() { + const [blogs, setBlogs] = useState([]); + const [loading, setLoading] = useState(true); + const [type, setType] = useState(""); + const [keyword, setKeyword] = useState(""); + const [page, setPage] = useState(1); + + useEffect(() => { + setLoading(true); + fetch(BLOG_API) + .then((res) => res.json()) + .then((data) => { + setBlogs(data); + setLoading(false); + }); + }, []); + + // 过滤和搜索 + const filteredBlogs = useMemo(() => { + let result = blogs; + if (type) { + result = result.filter((item) => item.type === type); + } + if (keyword.trim()) { + result = result.filter((item) => item.title.includes(keyword.trim())); + } + // 按时间逆序排列,若时间相同则按 key 降序排列 + result = result.slice().sort((a, b) => { + const timeCompare = b.time.localeCompare(a.time); + if (timeCompare !== 0) return timeCompare; + return b.key - a.key; + }); + return result; + }, [blogs, type, keyword]); + + // 分页 + const total = filteredBlogs.length; + const totalPages = Math.ceil(total / PAGE_SIZE); + const pagedBlogs = filteredBlogs.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE); + + function handleClearKeyword() { + setKeyword(""); + } + + function handleTypeChange(value: string) { + setType(value); + setPage(1); + } + + function handleKeywordChange(e: React.ChangeEvent) { + setKeyword(e.target.value); + setPage(1); + } + + function handlePrevPage() { + setPage((p) => Math.max(1, p - 1)); + } + function handleNextPage() { + setPage((p) => Math.min(totalPages, p + 1)); + } + const { theme } = useTheme(); + + return ( +
    +

    博客概览

    + {/* 控件区 */} + + {/* 列表区 */} + { + (() => { + let renderListContent; + if (loading) { + renderListContent = ( +
    + {Array.from({ length: 4 }).map((_, i) => ( + +
    + + ))} +
    + ); + } else if (pagedBlogs.length === 0) { + renderListContent = ( +
    暂无数据
    + ); + } else { + renderListContent = ; + } + return renderListContent; + })() + } + {/* 分页 */} + +
    + ); +} \ No newline at end of file diff --git a/packages/website-next/src/app/contact/page.tsx b/packages/website-next/src/app/contact/page.tsx new file mode 100644 index 00000000..4121b3f0 --- /dev/null +++ b/packages/website-next/src/app/contact/page.tsx @@ -0,0 +1,196 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import Image from 'next/image'; + +export default function ContactPage() { + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + setIsVisible(true); + }, []); + + return ( +
    +
    + {/* 页面标题 */} +
    +

    + 联系我们 +

    +

    + 了解 openInula 项目理念,与我们建立联系 +

    +
    + +
    + {/* 项目理念板块 */} +
    +
    +
    +

    + 项目理念 +

    + +
    + {/* 左上角图片 */} +
    +
    + OpenInula Logo +
    +
    +
    + + {/* 居中内容 */} +
    + {/* 项目介绍 */} +
    +

    + 项目介绍 +

    +

    + openInula是一款用于构建用户界面的JavaScript库,提供响应式API并完全兼容现有React生态,凭借高性能、易用性以及对React生态的兼容,帮助开发者简单高效构建高质量的前端项目。此外,openInula涵盖了一系列核心组件,包含状态管理器、路由、国际化、请求组件等;并提供应用脚手架等开发工具,以便开发者更高效地管理和维护基于openInula的前端产品。我们期待openInula能提升现代Web前端开发体验,为全球开发者提供全新选择。 +

    +
    + + {/* 历史发展 */} +
    +

    + 历史发展 +

    +
    +
    +
    +
    +

    + 2023年7月 - openInula在全球开源技术峰会首秀。 +

    +
    +
    +
    +
    +
    +

    + 2023年9月22日 - 项目首发开源。开源后命名为openInula。 +

    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + + {/* 联系我们板块 */} +
    +
    +
    +
    +
    + ); +} diff --git a/packages/website-next/src/app/contribute/components/Contributors.tsx b/packages/website-next/src/app/contribute/components/Contributors.tsx new file mode 100644 index 00000000..7fddb4a6 --- /dev/null +++ b/packages/website-next/src/app/contribute/components/Contributors.tsx @@ -0,0 +1,123 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { Avatar } from "antd"; +import { UserOutlined } from "@ant-design/icons"; + +interface Contributor { + name: string; + url: string; + avatar_url: string; + admin: boolean; +} + +export default function Contributors() { + const [contributorList, setContributorList] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + fetch( + "https://gitee.com/api/v5/repos/openinula/core/collaborators?page=1&per_page=100" + ) + .then((res) => { + if (!res.ok) { + throw new Error("Failed to request contributor list"); + } + return res.json(); + }) + .then((res) => + res + .map( + (item: { + name: string; + html_url: string; + avatar_url: string; + permissions: { admin: boolean }; + }) => ({ + name: item.name, + url: item.html_url, + avatar_url: item.avatar_url, + admin: item.permissions.admin, + }) + ) + .sort( + (a: Contributor, b: Contributor) => + Number(b.admin) - Number(a.admin) + ) + ) + .then((res) => { + setContributorList(res); + setLoading(false); + }) + .catch((err) => { + setError(err.message); + setLoading(false); + }); + }, []); + + if (loading) { + return ( +
    +

    贡献者

    +
    +
    +
    +
    + ); + } + + if (error) { + return ( +
    +

    贡献者

    +
    +

    加载贡献者列表失败

    +

    {error}

    +
    +
    + ); + } + + return ( +
    + ); +} diff --git a/packages/website-next/src/app/contribute/components/DocumentSidebar.tsx b/packages/website-next/src/app/contribute/components/DocumentSidebar.tsx new file mode 100644 index 00000000..66d3fdc3 --- /dev/null +++ b/packages/website-next/src/app/contribute/components/DocumentSidebar.tsx @@ -0,0 +1,125 @@ +"use client"; + +import { useState, ReactNode } from "react"; + +export interface DocumentItem { + id: string; + title: string; + url?: string; + description: string; +} + +interface DocumentSidebarProps { + documents: DocumentItem[]; + defaultActiveId?: string; + title?: string; + onDocumentChange?: (docId: string) => void; + className?: string; + children?: (currentDoc: DocumentItem | undefined) => ReactNode; +} + +export default function DocumentSidebar({ + documents, + defaultActiveId, + title = "文档导航", + onDocumentChange, + className = "", + children, +}: Readonly) { + const [activeDoc, setActiveDoc] = useState( + defaultActiveId || documents[0]?.id || "" + ); + + const handleDocumentChange = (docId: string) => { + setActiveDoc(docId); + onDocumentChange?.(docId); + }; + + const currentDoc = documents.find((doc) => doc.id === activeDoc); + + return ( +
    +
    + {/* 侧边栏 */} + + + {/* 主内容区 */} +
    + {/* 移动端文档选择器 */} +
    +

    + {title} +

    +
    + {documents.map((doc) => ( + + ))} +
    +
    + +
    + {children + ? children(currentDoc) + : currentDoc && ( +
    +

    + {currentDoc.title} +

    +

    + {currentDoc.description} +

    +
    + )} +
    +
    +
    +
    + ); +} diff --git a/packages/website-next/src/app/contribute/page.tsx b/packages/website-next/src/app/contribute/page.tsx new file mode 100644 index 00000000..509e447f --- /dev/null +++ b/packages/website-next/src/app/contribute/page.tsx @@ -0,0 +1,53 @@ +"use client"; + +import DocumentSidebar, { DocumentItem } from "@/app/contribute/components/DocumentSidebar"; +import MarkdownPage from "@/components/MarkdownPage"; +import Contributors from "@/app/contribute/components/Contributors"; + +const PRIVATE_URL1 = "https://openinula-website.obs.ap-southeast-1.myhuaweicloud.com/doc/guide.md" +const PRIVATE_URL2 = "https://openinula-website.obs.ap-southeast-1.myhuaweicloud.com/doc/behavior.md" + +const documents: DocumentItem[] = [ + { + id: "guide", + title: "贡献指南", + url: PRIVATE_URL1, + description: "了解如何为OpenInula项目做出贡献" + }, + { + id: "behavior", + title: "行为准则", + url: PRIVATE_URL2, + description: "社区行为准则和规范" + }, + { + id: "contributors", + title: "贡献者", + description: "查看OpenInula项目的贡献者列表" + } +]; + +export default function ContributePage() { + return ( + + {(currentDoc) => { + if (!currentDoc) return null; + + if (currentDoc.id === "contributors") { + return ; + } + + return ( + + ); + }} + + ); +} \ No newline at end of file diff --git a/packages/website-next/src/app/docs/components/Dynamic/page.mdx b/packages/website-next/src/app/docs/components/Dynamic/page.mdx new file mode 100644 index 00000000..e4cea464 --- /dev/null +++ b/packages/website-next/src/app/docs/components/Dynamic/page.mdx @@ -0,0 +1,63 @@ +--- +id: Dynamic +title: Dynamic +sidebar_label: Dynamic +--- + +# Dynamic + +`Dynamic` 组件用于动态渲染不同的组件类型,支持 props 传递、context、生命周期等,适合需要根据状态切换渲染内容的场景。 + +## 典型用法 + +```tsx filename="DynamicComponent.jsx" +function Hello() { return
    Hello
    ; } +function World() { return
    World
    ; } + +``` +- 支持 props 透传、context 获取、生命周期钩子。 +- 支持组件切换时自动卸载/挂载。 + +## props/context/生命周期 + +- 支持 props 传递: +```tsx filename="DynamicWithProps.jsx" + +``` +- 支持 context: +```tsx filename="DynamicWithContext.jsx" +const Ctx = createContext(0); + + + +``` +- 支持 didUnmount/willUnmount 等生命周期钩子。 + +## 多元素/事件/空组件 + +- 支持组件返回多个元素(Fragment): +```tsx filename="DynamicMultiElement.jsx" +function Multi() { return <>
    First
    Second
    ; } + +``` +- 支持事件处理: +```tsx filename="DynamicWithEvent.jsx" +function Btn({ onClick }) { return ; } + +``` +- component 可为 null/undefined,渲染为空。 + +## 注意事项 + +- component 可为 null/undefined,渲染为空。 +- 支持多种 props 结构、rest props。 +- 支持多元素返回、事件处理。 + +## 最佳实践 + +- 用于需要动态切换组件的场景,如 tab、动态表单等。 +- props 建议使用解构,便于类型推导和响应式。 + +## 相关链接 + +- [React Dynamic Rendering](https://react.dev/reference/react/cloneElement) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/components/ErrorBoundary/page.mdx b/packages/website-next/src/app/docs/components/ErrorBoundary/page.mdx new file mode 100644 index 00000000..77ce2682 --- /dev/null +++ b/packages/website-next/src/app/docs/components/ErrorBoundary/page.mdx @@ -0,0 +1,54 @@ +--- +id: ErrorBoundary +title: ErrorBoundary +sidebar_label: ErrorBoundary +--- + +# ErrorBoundary + +`ErrorBoundary` 组件用于捕获其子组件渲染过程中的异常,并渲染备用 UI(fallback)。适用于防止整个应用因单个组件错误而崩溃。 + +## 典型用法 + +```tsx filename="ErrorBoundaryExample.jsx" +function BuggyComponent() { + throw new Error('出错了'); + return
    不会渲染
    ; +} + +const Fallback = error =>
    {error.message}
    ; + + + + +``` + +- 当子组件抛出异常时,`fallback` 会接收到 error 对象并渲染对应内容。 +- 正常情况下渲染 children。 + +## 嵌套与错误冒泡 + +支持嵌套 ErrorBoundary,错误会冒泡到最近的 ErrorBoundary: + +```tsx filename="NestedErrorBoundary.jsx" +
    外部错误: {outerErr.message}
    }> +
    内部错误: {innerErr.message}
    }> + +
    +
    +``` + +## 注意事项 + +- `fallback` 必须是函数,参数为 error。 +- 只捕获渲染过程中的错误,不捕获事件处理等异步错误。 +- 多层嵌套时,内层优先捕获。 + +## 最佳实践 + +- 建议在应用入口或关键区域包裹 ErrorBoundary。 +- fallback UI 应简洁明了,便于用户理解。 + +## 相关链接 + +- [React Error Boundaries](https://reactjs.org/docs/error-boundaries.html) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/components/Fragment/page.mdx b/packages/website-next/src/app/docs/components/Fragment/page.mdx new file mode 100644 index 00000000..4836a667 --- /dev/null +++ b/packages/website-next/src/app/docs/components/Fragment/page.mdx @@ -0,0 +1,68 @@ +--- +id: Fragment +title: Fragment +sidebar_label: Fragment +--- + +# Fragment + +`Fragment` 用于包裹多个元素,避免额外的 DOM 节点,常用于返回多个兄弟节点的场景。 + +## 典型用法 + +```tsx filename="FragmentExample.jsx" +<> +
    First
    +
    Second
    + +``` +- 渲染结果不会多出额外的 DOM 层级。 + +## 嵌套/条件/三元/事件 + +- 支持嵌套: +```tsx filename="NestedFragment.jsx" +<> +
    Start
    + <> +

    Nested

    + Child + +
    End
    + +``` +- 支持条件渲染: +```tsx filename="ConditionalFragment.jsx" +<> +
    Always
    + {showExtra && <>
    Extra 1
    Extra 2
    } + +``` +- 支持三元表达式: +```tsx filename="TernaryFragment.jsx" +<> + {cond ? <>
    True 1
    True 2
    : <>
    False 1
    False 2
    } + +``` +- 支持事件处理: +```tsx filename="FragmentWithEvent.jsx" +<> + +
    {clicked ? 'Clicked' : 'Not clicked'}
    + +``` + +## 注意事项 + +- Fragment 不会影响 CSS 或事件。 +- 可与文本、JSX 表达式混用。 +- 支持多层嵌套。 + +## 最佳实践 + +- 用于组件需要返回多个兄弟节点时,避免多余的 div。 +- 可与条件渲染、列表渲染等结合使用。 + +## 相关链接 + +- [React Fragments](https://react.dev/reference/react/Fragment) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/components/Portal/page.mdx b/packages/website-next/src/app/docs/components/Portal/page.mdx new file mode 100644 index 00000000..38ab24f4 --- /dev/null +++ b/packages/website-next/src/app/docs/components/Portal/page.mdx @@ -0,0 +1,64 @@ +--- +id: Portal +title: Portal +sidebar_label: Portal +--- + +# Portal + +`Portal` 组件用于将子节点渲染到指定的 DOM 容器外部,常用于模态框、弹窗等场景。 + +## 典型用法 + +```tsx filename="PortalExample.jsx" +const portalRoot = document.getElementById('portal-root'); + +
    Portal Content
    +
    +``` +- target 必须为有效的 DOM 元素。 +- 组件卸载时自动移除内容。 + +## 多 Portal 与嵌套 Portal + +- 支持多个 Portal 指向同一目标: + +```tsx filename="MultiPortal.jsx" +First Content +Second Content +``` +- 支持嵌套 Portal: + +```tsx filename="NestedPortal.jsx" + +
    Outer Content
    + +
    Inner Content
    +
    +
    +``` + +## 事件处理 + +- Portal 内的事件(如 onClick)可正常冒泡和处理。 + +```tsx filename="PortalEvent.jsx" + + + +``` + +## 注意事项 + +- target 必须为已挂载的 DOM 元素。 +- 组件卸载时内容会自动清理。 +- 支持内容和事件的动态更新。 + +## 最佳实践 + +- 用于模态框、弹窗、全局提示等需要脱离父 DOM 层级的场景。 +- 建议统一管理 portal 容器节点。 + +## 相关链接 + +- [React Portal](https://react.dev/reference/react-dom/createPortal) \ No newline at end of file diff --git a/packages/website-next/src/app/docs/components/Suspense/page.mdx b/packages/website-next/src/app/docs/components/Suspense/page.mdx new file mode 100644 index 00000000..bcdc5b2f --- /dev/null +++ b/packages/website-next/src/app/docs/components/Suspense/page.mdx @@ -0,0 +1,54 @@ +--- +id: Suspense +title: Suspense & lazy +sidebar_label: Suspense & lazy +--- + +# Suspense & lazy + +`Suspense` 组件用于包裹异步组件(如 `lazy` 加载),在异步加载期间渲染 fallback。`lazy` 用于声明异步加载的组件。 + +## 典型用法 + +```tsx filename="SuspenseExample.jsx" +const LazyComponent = lazy(() => import('./Comp')); + +loading...
    }> + + +``` + +- fallback 在异步加载期间显示,加载完成后自动切换为真实内容。 +- 支持多个 lazy 组件、嵌套 Suspense。 + +## 嵌套与多组件 + +```tsx filename="NestedSuspense.jsx" +outer loading...
    }> + + inner loading...