feat(docs): add JavaScript intro demos and update content structure

refactor(docs): rename "ClaudeCode" to "Claude Code" across all language versions

chore: add ESLint configuration and update build scripts

style: update component organization and remove unused imports
This commit is contained in:
sanbuphy
2026-02-15 18:15:42 +08:00
parent 9c1a395962
commit 9ee3312569
29 changed files with 5168 additions and 1123 deletions
+1 -1
View File
@@ -209,7 +209,7 @@ Easy-Vibe 通过以下几个阶段,带你从 0 到 1:
| 章节 | 关键内容 | 状态 | | 章节 | 关键内容 | 状态 |
| :------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | :--- | | :------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | :--- |
| [高级一:MCP 与 ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | 通过 MCP 与 Skills 扩展 IDE 能力,把外部服务接成工具 | 🚧 | | [高级一:MCP 与 Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | 通过 MCP 与 Skills 扩展 IDE 能力,把外部服务接成工具 | 🚧 |
| [高级二:如何让 Coding Tools 长时间工作](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 设计和配置长时间运行的任务,让 Coding Tools 更稳定可靠 | 🚧 | | [高级二:如何让 Coding Tools 长时间工作](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 设计和配置长时间运行的任务,让 Coding Tools 更稳定可靠 | 🚧 |
| [高级三:多平台开发:如何构建微信小程序](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | 了解微信小程序生态,从官方模板到上线完成一个前端小程序 | ✅ | | [高级三:多平台开发:如何构建微信小程序](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | 了解微信小程序生态,从官方模板到上线完成一个前端小程序 | ✅ |
| [高级四:多平台开发:如何构建微信小程序-包含后端](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | 在小程序中接入数据库与后端逻辑,打通完整业务闭环 | 🚧 | | [高级四:多平台开发:如何构建微信小程序-包含后端](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | 在小程序中接入数据库与后端逻辑,打通完整业务闭环 | 🚧 |
+1 -1
View File
@@ -140,7 +140,7 @@
| الفصل | المحتوى الرئيسي | الحالة | | الفصل | المحتوى الرئيسي | الحالة |
| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------- | :----- | | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------- | :----- |
| [المتقدم 1: MCP ومهارات ClaudeCode](docs/stage-3/core-skills/3.1-mcp-claudecode-skills/) : توسيع قدرات IDE من خلال MCP والمهارات، توصيل الخدمات الخارجية كأدوات | 🚧 | | [المتقدم 1: MCP ومهارات ClaudeCode](docs/stage-3/core-skills/3.1-mcp-claude-code-skills/) : توسيع قدرات IDE من خلال MCP والمهارات، توصيل الخدمات الخارجية كأدوات | 🚧 |
| [المتقدم 2: كيفية جعل Coding Tools تعمل لفترة طويلة](docs/stage-3/core-skills/3.2-long-running-tasks/) : تصميم وتكوين المهام طويلة التشغيل، جعل Coding Tools أكثر استقرارًا وموثوقية | 🚧 | | [المتقدم 2: كيفية جعل Coding Tools تعمل لفترة طويلة](docs/stage-3/core-skills/3.2-long-running-tasks/) : تصميم وتكوين المهام طويلة التشغيل، جعل Coding Tools أكثر استقرارًا وموثوقية | 🚧 |
| [المتقدم 3: التطوير متعدد المنصات: كيفية بناء برامج WeChat المصغرة](docs/stage-3/cross-platform/3.3-wechat-miniprogram/) : فهم نظام البرامج المصغرة WeChat، إكمال برنامج مصغر للواجهة الأمامية من القالب الرسمي إلى الإطلاق | ✅ | | [المتقدم 3: التطوير متعدد المنصات: كيفية بناء برامج WeChat المصغرة](docs/stage-3/cross-platform/3.3-wechat-miniprogram/) : فهم نظام البرامج المصغرة WeChat، إكمال برنامج مصغر للواجهة الأمامية من القالب الرسمي إلى الإطلاق | ✅ |
| [المتقدم 4: التطوير متعدد المنصات: كيفية بناء برامج WeChat المصغرة - بما في ذلك الخلفية](docs/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : دمج قاعدة البيانات ومنطق الواجهة الخلفية في البرامج المصغرة، تحقيق دورة نشاط كاملة | 🚧 | | [المتقدم 4: التطوير متعدد المنصات: كيفية بناء برامج WeChat المصغرة - بما في ذلك الخلفية](docs/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : دمج قاعدة البيانات ومنطق الواجهة الخلفية في البرامج المصغرة، تحقيق دورة نشاط كاملة | 🚧 |
+1 -1
View File
@@ -140,7 +140,7 @@ Wir glauben, dass durch die Beherrschung von Vibe Coding in Kombination mit syst
| Kapitel | Schlüsselinhalt | Status | | Kapitel | Schlüsselinhalt | Status |
| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------- | :----- | | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------- | :----- |
| [Fortgeschritten 1: MCP und ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) : IDE-Fähigkeiten durch MCP und Skills erweitern, externe Dienste als Tools anschließen | 🚧 | | [Fortgeschritten 1: MCP und Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) : IDE-Fähigkeiten durch MCP und Skills erweitern, externe Dienste als Tools anschließen | 🚧 |
| [Fortgeschritten 2: Coding Tools lange laufen lassen](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) : Lang laufende Aufgaben entwerfen und konfigurieren, Coding Tools stabiler und zuverlässiger machen | 🚧 | | [Fortgeschritten 2: Coding Tools lange laufen lassen](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) : Lang laufende Aufgaben entwerfen und konfigurieren, Coding Tools stabiler und zuverlässiger machen | 🚧 |
| [Fortgeschritten 3: Plattformübergreifende Entwicklung: WeChat-Miniprogramme erstellen](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) : WeChat-Miniprogramm-Ökosystem verstehen, Frontend-Miniprogramm von offizieller Vorlage bis zum Start completed | ✅ | | [Fortgeschritten 3: Plattformübergreifende Entwicklung: WeChat-Miniprogramme erstellen](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) : WeChat-Miniprogramm-Ökosystem verstehen, Frontend-Miniprogramm von offizieller Vorlage bis zum Start completed | ✅ |
| [Fortgeschritten 4: Plattformübergreifende Entwicklung: WeChat-Miniprogramme erstellen - Mit Backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : Datenbank und Backend-Logik in Miniprogramme integrieren, vollständigen Geschäftskreislauf realisieren | 🚧 | | [Fortgeschritten 4: Plattformübergreifende Entwicklung: WeChat-Miniprogramme erstellen - Mit Backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : Datenbank und Backend-Logik in Miniprogramme integrieren, vollständigen Geschäftskreislauf realisieren | 🚧 |
+1 -1
View File
@@ -143,7 +143,7 @@ We believe that by mastering Vibe Coding combined with systematic training, one
| Chapter | Key Content | Status | | Chapter | Key Content | Status |
| :-------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------- | :----- | | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------- | :----- |
| [Advanced 1: MCP and ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | Extend IDE capabilities through MCP and Skills, integrate external services as tools | 🚧 | | [Advanced 1: MCP and Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | Extend IDE capabilities through MCP and Skills, integrate external services as tools | 🚧 |
| [Advanced 2: Making Coding Tools Work for Long Periods](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | Design and configure long-running tasks, make Coding Tools more stable and reliable | 🚧 | | [Advanced 2: Making Coding Tools Work for Long Periods](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | Design and configure long-running tasks, make Coding Tools more stable and reliable | 🚧 |
| [Advanced 3: Multi-Platform Development: Building WeChat Mini Programs](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | Understand WeChat mini program ecosystem, complete a frontend mini program from official template to launch | ✅ | | [Advanced 3: Multi-Platform Development: Building WeChat Mini Programs](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | Understand WeChat mini program ecosystem, complete a frontend mini program from official template to launch | ✅ |
| [Advanced 4: Multi-Platform Development: Building WeChat Mini Programs - With Backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | Integrate databases and backend logic in mini programs, complete business loops | 🚧 | | [Advanced 4: Multi-Platform Development: Building WeChat Mini Programs - With Backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | Integrate databases and backend logic in mini programs, complete business loops | 🚧 |
+1 -1
View File
@@ -140,7 +140,7 @@ Creemos que al dominar Vibe Coding y combinarlo con entrenamiento sistemático,
| Capítulo | Contenido clave | Estado | | Capítulo | Contenido clave | Estado |
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------- | :----- | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------- | :----- |
| [Avanzado 1: MCP y ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | Extender capacidades del IDE a través de MCP y Skills, conectar servicios externos como herramientas | 🚧 | | [Avanzado 1: MCP y Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | Extender capacidades del IDE a través de MCP y Skills, conectar servicios externos como herramientas | 🚧 |
| [Avanzado 2: Cómo hacer que Coding Tools funcione durante mucho tiempo](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | Diseñar y configurar tareas de ejecución prolongada, hacer Coding Tools más estable y confiable | 🚧 | | [Avanzado 2: Cómo hacer que Coding Tools funcione durante mucho tiempo](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | Diseñar y configurar tareas de ejecución prolongada, hacer Coding Tools más estable y confiable | 🚧 |
| [Avanzado 3: Desarrollo multiplataforma: Cómo construir mini programas de WeChat](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | Entender el ecosistema de mini programas de WeChat, completar un mini programa frontend desde plantilla oficial hasta lanzamiento | ✅ | | [Avanzado 3: Desarrollo multiplataforma: Cómo construir mini programas de WeChat](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | Entender el ecosistema de mini programas de WeChat, completar un mini programa frontend desde plantilla oficial hasta lanzamiento | ✅ |
| [Avanzado 4: Desarrollo multiplataforma: Cómo construir mini programas de WeChat - Incluyendo backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | Integrar base de datos y lógica backend en mini programas,实现 ciclo completo de negocio | 🚧 | | [Avanzado 4: Desarrollo multiplataforma: Cómo construir mini programas de WeChat - Incluyendo backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | Integrar base de datos y lógica backend en mini programas,实现 ciclo completo de negocio | 🚧 |
+1 -1
View File
@@ -140,7 +140,7 @@ Nous croyons qu'en maîtrisant Vibe Coding et en le combinant avec un entraînem
| Chapitre | Contenu clé | Statut | | Chapitre | Contenu clé | Statut |
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :---------- | :----- | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :---------- | :----- |
| [Avancé 1 : MCP et ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) : Étendre les capacités de l'IDE via MCP et Skills, connecter des services externes comme outils | 🚧 | | [Avancé 1 : MCP et Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) : Étendre les capacités de l'IDE via MCP et Skills, connecter des services externes comme outils | 🚧 |
| [Avancé 2 : Comment faire fonctionner Coding Tools longtemps](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) : Concevoir et configurer des tâches à longue exécution, rendre Coding Tools plus stable et fiable | 🚧 | | [Avancé 2 : Comment faire fonctionner Coding Tools longtemps](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) : Concevoir et configurer des tâches à longue exécution, rendre Coding Tools plus stable et fiable | 🚧 |
| [Avancé 3 : Développement multiplateforme : Comment construire des mini-programmes WeChat](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) : Comprendre l'écosystème des mini-programmes WeChat, compléter un mini-programme frontend du modèle officiel au lancement | ✅ | | [Avancé 3 : Développement multiplateforme : Comment construire des mini-programmes WeChat](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) : Comprendre l'écosystème des mini-programmes WeChat, compléter un mini-programme frontend du modèle officiel au lancement | ✅ |
| [Avancé 4 : Développement multiplateforme : Comment construire des mini-programmes WeChat - Y compris backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : Intégrer une base de données et une logique backend dans les mini-programmes, réaliser un cycle d'activité complet | 🚧 | | [Avancé 4 : Développement multiplateforme : Comment construire des mini-programmes WeChat - Y compris backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : Intégrer une base de données et une logique backend dans les mini-programmes, réaliser un cycle d'activité complet | 🚧 |
+1 -1
View File
@@ -140,7 +140,7 @@ AI でコードを書こうとしてエラーが続き、諦めかけたくな
| 章 | 主要内容 | 状態 | | 章 | 主要内容 | 状態 |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | :--- | | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | :--- |
| [上級一:MCP と ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | MCP と Skills を通じて IDE 能力を拡張し、外部サービスをツールとして接続 | 🚧 | | [上級一:MCP と Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | MCP と Skills を通じて IDE 能力を拡張し、外部サービスをツールとして接続 | 🚧 |
| [上級二:Coding Tools を長時間動作させる方法](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 長時間動作するタスクを設計・設定し、Coding Tools をより安定して信頼性の高いものに | 🚧 | | [上級二:Coding Tools を長時間動作させる方法](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 長時間動作するタスクを設計・設定し、Coding Tools をより安定して信頼性の高いものに | 🚧 |
| [上級三:マルチプラットフォーム開発:WeChat ミニプログラムの構築方法](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | WeChat ミニプログラムのエコシステムを理解し、公式テンプレートからリリースまでフロントエンドミニプログラムを完成 | ✅ | | [上級三:マルチプラットフォーム開発:WeChat ミニプログラムの構築方法](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | WeChat ミニプログラムのエコシステムを理解し、公式テンプレートからリリースまでフロントエンドミニプログラムを完成 | ✅ |
| [上級四:マルチプラットフォーム開発:WeChat ミニプログラムの構築方法 - バックエンド含む](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | ミニプログラムにデータベースとバックエンドロジックを統合し、完全な業務クローズドループを実現 | 🚧 | | [上級四:マルチプラットフォーム開発:WeChat ミニプログラムの構築方法 - バックエンド含む](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | ミニプログラムにデータベースとバックエンドロジックを統合し、完全な業務クローズドループを実現 | 🚧 |
+1 -1
View File
@@ -140,7 +140,7 @@ AI로 코드를 작성하려고 할 때 오류가 계속 발생하고, 포기하
| 장 | 주요 내용 | 상태 | | 장 | 주요 내용 | 상태 |
| :--------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | :--- | | :--------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | :--- |
| [고급 1: MCP와 ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | MCP와 Skills를 통해 IDE 능력 확장, 외부 서비스를 도구로 연결 | 🚧 | | [고급 1: MCP와 Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | MCP와 Skills를 통해 IDE 능력 확장, 외부 서비스를 도구로 연결 | 🚧 |
| [고급 2: Coding Tools를 장시간 작동시키는 방법](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 장시간 실행되는 작업 설계 및 구성, Coding Tools를 더 안정적이고 신뢰할 수 있게 | 🚧 | | [고급 2: Coding Tools를 장시간 작동시키는 방법](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 장시간 실행되는 작업 설계 및 구성, Coding Tools를 더 안정적이고 신뢰할 수 있게 | 🚧 |
| [고급 3: 멀티플랫폼 개발: 위챗 미니 프로그램 구축 방법](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | 위챗 미니 프로그램 생태계 이해, 공식 템플릿부터 출시까지 프론트엔드 미니 프로그램 완성 | ✅ | | [고급 3: 멀티플랫폼 개발: 위챗 미니 프로그램 구축 방법](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | 위챗 미니 프로그램 생태계 이해, 공식 템플릿부터 출시까지 프론트엔드 미니 프로그램 완성 | ✅ |
| [고급 4: 멀티플랫폼 개발: 위챗 미니 프로그램 구축 방법 - 백엔드 포함](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | 미니 프로그램에 데이터베이스와 백엔드 로직 통합, 완전한 비즈니스 폐루프 실현 | 🚧 | | [고급 4: 멀티플랫폼 개발: 위챗 미니 프로그램 구축 방법 - 백엔드 포함](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | 미니 프로그램에 데이터베이스와 백엔드 로직 통합, 완전한 비즈니스 폐루프 실현 | 🚧 |
+1 -1
View File
@@ -140,7 +140,7 @@ Chúng tôi tin rằng thông qua việc làm chủ Vibe Coding kết hợp vớ
| Chương | Nội dung chính | Trạng thái | | Chương | Nội dung chính | Trạng thái |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------- | :--------- | | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------- | :--------- |
| [Cao cấp 1: MCP và ClaudeCode Skills](docs/stage-3/core-skills/3.1-mcp-claudecode-skills/) : Mở rộng khả năng IDE qua MCP và Skills, kết nối dịch vụ bên ngoài như công cụ | 🚧 | | [Cao cấp 1: MCP và Claude Code Skills](docs/stage-3/core-skills/3.1-mcp-claude-code-skills/) : Mở rộng khả năng IDE qua MCP và Skills, kết nối dịch vụ bên ngoài như công cụ | 🚧 |
| [Cao cấp 2: Cách để Coding Tools hoạt động lâu](docs/stage-3/core-skills/3.2-long-running-tasks/) : Thiết kế và cấu hình nhiệm vụ chạy dài, làm Coding Tools ổn định và đáng tin cậy hơn | 🚧 | | [Cao cấp 2: Cách để Coding Tools hoạt động lâu](docs/stage-3/core-skills/3.2-long-running-tasks/) : Thiết kế và cấu hình nhiệm vụ chạy dài, làm Coding Tools ổn định và đáng tin cậy hơn | 🚧 |
| [Cao cấp 3: Phát triển đa nền tảng: Cách xây dựng chương trình nhỏ WeChat](docs/stage-3/cross-platform/3.3-wechat-miniprogram/) : Hiểu hệ sinh thái chương trình nhỏ WeChat, hoàn thành chương trình nhỏ frontend từ mẫu chính thức đến phát hành | ✅ | | [Cao cấp 3: Phát triển đa nền tảng: Cách xây dựng chương trình nhỏ WeChat](docs/stage-3/cross-platform/3.3-wechat-miniprogram/) : Hiểu hệ sinh thái chương trình nhỏ WeChat, hoàn thành chương trình nhỏ frontend từ mẫu chính thức đến phát hành | ✅ |
| [Cao cấp 4: Phát triển đa nền tảng: Cách xây dựng chương trình nhỏ WeChat - Bao gồm backend](docs/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : Tích hợp cơ sở dữ liệu và logic backend vào chương trình nhỏ, thực hiện vòng tuần hoàn hoạt động hoàn chỉnh | 🚧 | | [Cao cấp 4: Phát triển đa nền tảng: Cách xây dựng chương trình nhỏ WeChat - Bao gồm backend](docs/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : Tích hợp cơ sở dữ liệu và logic backend vào chương trình nhỏ, thực hiện vòng tuần hoàn hoạt động hoàn chỉnh | 🚧 |
+1 -1
View File
@@ -140,7 +140,7 @@
| 章节 | 關鍵內容 | 狀態 | | 章节 | 關鍵內容 | 狀態 |
| :---------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | :--- | | :---------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | :--- |
| [高級一:MCP 與 ClaudeCode Skills](../docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | 通過 MCP 與 Skills 擴展 IDE 能力,把外部服務接成工具 | 🚧 | | [高級一:MCP 與 Claude Code Skills](../docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | 通過 MCP 與 Skills 擴展 IDE 能力,把外部服務接成工具 | 🚧 |
| [高級二:如何讓 Coding Tools 長時間工作](../docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 設計和配置長時間運行的任務,讓 Coding Tools 更穩定可靠 | 🚧 | | [高級二:如何讓 Coding Tools 長時間工作](../docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 設計和配置長時間運行的任務,讓 Coding Tools 更穩定可靠 | 🚧 |
| [高級三:多平台開發:如何建構微信小程式](../docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | 了解微信小程式生態,從官方模板到上線完成一個前端小程式 | ✅ | | [高級三:多平台開發:如何建構微信小程式](../docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | 了解微信小程式生態,從官方模板到上線完成一個前端小程式 | ✅ |
| [高級四:多平台開發:如何建構微信小程式-包含後端](../docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | 在小程式中接入數據庫與後端邏輯,打通完整業務閉環 | 🚧 | | [高級四:多平台開發:如何建構微信小程式-包含後端](../docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | 在小程式中接入數據庫與後端邏輯,打通完整業務閉環 | 🚧 |
+2 -2
View File
@@ -445,8 +445,8 @@ export default defineConfig({
collapsed: false, collapsed: false,
items: [ items: [
{ {
text: '高级一:MCP 与 ClaudeCode Skills', text: '高级一:MCP 与 Claude Code Skills',
link: '/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/' link: '/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/'
}, },
{ {
text: '高级二:如何让 Coding Tools 长时间工作', text: '高级二:如何让 Coding Tools 长时间工作',
@@ -0,0 +1,477 @@
<script setup>
import { ref } from 'vue'
const mode = ref('sync')
const isRunning = ref(false)
const elapsedTime = ref(0)
const customerA = ref({ time: 2, status: 'waiting' })
const customerB = ref({ time: 3, status: 'waiting' })
const customerC = ref({ time: 5, status: 'waiting' })
const modes = [
{ value: 'sync', label: '同步模式 🐢' },
{ value: 'async', label: '异步模式 ⚡' }
]
const reset = () => {
elapsedTime.value = 0
customerA.value = { time: 2, status: 'waiting' }
customerB.value = { time: 3, status: 'waiting' }
customerC.value = { time: 5, status: 'waiting' }
}
const start = async () => {
if (isRunning.value) return
isRunning.value = true
reset()
if (mode.value === 'sync') {
//
await processCustomer(customerA, 2000)
await processCustomer(customerB, 3000)
await processCustomer(customerC, 5000)
} else {
//
await Promise.all([
processCustomer(customerA, 2000),
processCustomer(customerB, 3000),
processCustomer(customerC, 5000)
])
}
isRunning.value = false
}
const processCustomer = async (customer, realTime) => {
customer.status = 'cooking'
await new Promise(resolve => setTimeout(resolve, realTime))
customer.status = 'done'
}
</script>
<template>
<div class="async-restaurant-demo">
<h3>异步同步 vs 异步</h3>
<div class="mode-selector">
<button
v-for="m in modes"
:key="m.value"
@click="mode = m.value"
:class="{ 'active': mode === m.value }"
class="mode-btn"
:disabled="isRunning"
>
{{ m.label }}
</button>
</div>
<div class="restaurant-scene">
<!-- 厨房 -->
<div class="kitchen">
<h4>厨房</h4>
<div class="stoves">
<div
class="stove"
:class="{ 'cooking': customerA.status === 'cooking', 'done': customerA.status === 'done' }"
>
<div class="stove-label">灶位 1</div>
<div class="stove-content">
<div v-if="customerA.status === 'cooking'" class="cooking-text">煮面 {{ customerA.time }}s</div>
<div v-if="customerA.status === 'done'" class="done-text"> 完成</div>
<div v-if="customerA.status === 'waiting'" class="waiting-text">空闲</div>
</div>
</div>
<div
class="stove"
:class="{ 'cooking': customerB.status === 'cooking', 'done': customerB.status === 'done' }"
>
<div class="stove-label">灶位 2</div>
<div class="stove-content">
<div v-if="customerB.status === 'cooking'" class="cooking-text">炒饭 {{ customerB.time }}s</div>
<div v-if="customerB.status === 'done'" class="done-text"> 完成</div>
<div v-if="customerB.status === 'waiting'" class="waiting-text">空闲</div>
</div>
</div>
<div
class="stove"
:class="{ 'cooking': customerC.status === 'cooking', 'done': customerC.status === 'done' }"
>
<div class="stove-label">灶位 3</div>
<div class="stove-content">
<div v-if="customerC.status === 'cooking'" class="cooking-text">烤鱼 {{ customerC.time }}s</div>
<div v-if="customerC.status === 'done'" class="done-text"> 完成</div>
<div v-if="customerC.status === 'waiting'" class="waiting-text">空闲</div>
</div>
</div>
</div>
</div>
<!-- 顾客 -->
<div class="customers">
<h4>顾客</h4>
<div class="customer-list">
<div class="customer" :class="{ 'served': customerA.status === 'done' }">
<div class="customer-avatar">👤</div>
<div class="customer-info">
<div class="customer-name">顾客 A</div>
<div class="customer-order">煮面 ({{ customerA.time }})</div>
</div>
<div v-if="customerA.status === 'done'" class="check-mark"></div>
</div>
<div class="customer" :class="{ 'served': customerB.status === 'done' }">
<div class="customer-avatar">👤</div>
<div class="customer-info">
<div class="customer-name">顾客 B</div>
<div class="customer-order">炒饭 ({{ customerB.time }})</div>
</div>
<div v-if="customerB.status === 'done'" class="check-mark"></div>
</div>
<div class="customer" :class="{ 'served': customerC.status === 'done' }">
<div class="customer-avatar">👤</div>
<div class="customer-info">
<div class="customer-name">顾客 C</div>
<div class="customer-order">烤鱼 ({{ customerC.time }})</div>
</div>
<div v-if="customerC.status === 'done'" class="check-mark"></div>
</div>
</div>
</div>
</div>
<div class="controls">
<button @click="start" :disabled="isRunning" class="btn-start">
{{ isRunning ? '执行中...' : '开始' }}
</button>
<button @click="reset" :disabled="isRunning" class="btn-reset">
重置
</button>
</div>
<div class="comparison" v-if="!isRunning && (customerA.status === 'done' || customerB.status === 'done')">
<div class="comparison-item">
<strong>同步模式</strong> 10 依次执行
</div>
<div class="comparison-item">
<strong>异步模式</strong> 5 同时执行
</div>
<div class="tip">JavaScript 用的就是异步模式遇到耗时操作如网络请求不会傻等而是先去做别的事</div>
</div>
<div class="code-display">
<h4>代码对比</h4>
<div class="code-comparison">
<div class="code-block">
<h5>同步阻塞</h5>
<pre><code>console.log("1")
console.log("2") //
console.log("3")
// 1, 2, 3</code></pre>
</div>
<div class="code-block">
<h5>异步不阻塞</h5>
<pre><code>console.log("1")
setTimeout(() => console.log("2"), 1000)
console.log("3")
// 1, 3, 2</code></pre>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.async-restaurant-demo {
border: 1px solid var(--vp-c-border);
border-radius: 12px;
padding: 24px;
margin: 24px 0;
background: var(--vp-c-bg);
}
h3 {
margin: 0 0 20px 0;
font-size: 18px;
font-weight: 600;
color: var(--vp-c-text-1);
}
.mode-selector {
display: flex;
gap: 12px;
justify-content: center;
margin-bottom: 20px;
}
.mode-btn {
padding: 10px 20px;
border: 2px solid var(--vp-c-border);
border-radius: 8px;
font-size: 14px;
font-weight: 600;
background: var(--vp-c-bg);
color: var(--vp-c-text-1);
cursor: pointer;
transition: all 0.2s ease;
}
.mode-btn:hover:not(:disabled) {
border-color: var(--vp-c-brand-1);
background: var(--vp-c-bg-soft);
}
.mode-btn.active {
border-color: var(--vp-c-brand-1);
background: var(--vp-c-brand-1);
color: white;
}
.mode-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.restaurant-scene {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
margin-bottom: 20px;
}
@media (max-width: 768px) {
.restaurant-scene {
grid-template-columns: 1fr;
}
}
.kitchen, .customers {
border: 2px solid var(--vp-c-border);
border-radius: 8px;
padding: 16px;
background: var(--vp-c-bg-soft);
}
h4 {
margin: 0 0 16px 0;
font-size: 16px;
font-weight: 600;
color: var(--vp-c-text-1);
}
.stoves {
display: flex;
flex-direction: column;
gap: 12px;
}
.stove {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
border: 2px solid var(--vp-c-border);
border-radius: 8px;
background: var(--vp-c-bg);
transition: all 0.3s ease;
}
.stove.cooking {
border-color: #ed8936;
animation: pulse 1s ease infinite;
}
@keyframes pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(237, 137, 54, 0.4); }
50% { box-shadow: 0 0 0 8px rgba(237, 137, 54, 0); }
}
.stove.done {
border-color: #38a169;
}
.stove-label {
font-size: 12px;
font-weight: 600;
color: var(--vp-c-text-2);
min-width: 60px;
}
.stove-content {
flex: 1;
font-size: 13px;
}
.cooking-text {
color: #ed8936;
font-weight: 500;
}
.done-text {
color: #38a169;
font-weight: 600;
}
.waiting-text {
color: var(--vp-c-text-3);
}
.customer-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.customer {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
border: 2px solid var(--vp-c-border);
border-radius: 8px;
background: var(--vp-c-bg);
transition: all 0.3s ease;
}
.customer.served {
border-color: #38a169;
}
.customer-avatar {
font-size: 32px;
}
.customer-info {
flex: 1;
}
.customer-name {
font-size: 14px;
font-weight: 600;
color: var(--vp-c-text-1);
}
.customer-order {
font-size: 12px;
color: var(--vp-c-text-2);
margin-top: 4px;
}
.check-mark {
font-size: 24px;
}
.controls {
display: flex;
gap: 12px;
justify-content: center;
margin-bottom: 20px;
}
button {
padding: 10px 24px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}
button:active {
transform: scale(0.95);
}
.btn-start {
background: var(--vp-c-brand-1);
color: white;
}
.btn-start:hover:not(:disabled) {
background: var(--vp-c-brand-2);
}
.btn-start:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.btn-reset {
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
}
.btn-reset:hover:not(:disabled) {
background: var(--vp-c-bg-soft-hover);
}
.comparison {
background: var(--vp-c-bg-soft);
border-left: 4px solid var(--vp-c-brand-1);
border-radius: 8px;
padding: 16px;
margin-bottom: 20px;
}
.comparison-item {
font-size: 14px;
margin-bottom: 8px;
color: var(--vp-c-text-1);
}
.comparison-item:last-child {
margin-bottom: 0;
}
.tip {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid var(--vp-c-border);
font-size: 13px;
color: var(--vp-c-brand-1);
font-weight: 500;
}
.code-display {
background: #1e1e1e;
border-radius: 8px;
padding: 16px;
overflow-x: auto;
}
.code-display h4 {
color: #d4d4d4;
margin: 0 0 12px 0;
font-size: 14px;
font-weight: 600;
}
.code-comparison {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
@media (max-width: 640px) {
.code-comparison {
grid-template-columns: 1fr;
}
}
.code-block h5 {
color: #d4d4d4;
margin: 0 0 8px 0;
font-size: 13px;
font-weight: 600;
}
.code-block pre {
margin: 0;
}
.code-block code {
font-family: 'Courier New', monospace;
font-size: 12px;
line-height: 1.5;
color: #d4d4d4;
}
</style>
@@ -0,0 +1,309 @@
<script setup>
import { ref } from 'vue'
const title = ref('我的网页')
const items = ref(['项目1', '项目2'])
const paragraphColor = ref('black')
const modifyTitle = () => {
title.value = 'Hello World!'
}
const addItem = () => {
const id = items.value.length + 1
items.value.push(`新项目${id}`)
}
const changeColor = () => {
paragraphColor.value = paragraphColor.value === 'black' ? 'red' : 'black'
}
const removeItem = () => {
if (items.value.length > 0) {
items.value.pop()
}
}
</script>
<template>
<div class="dom-tree-demo">
<h3>DOM JavaScript 看到的网页</h3>
<div class="demo-container">
<!-- 左侧迷你网页 -->
<div class="webpage-preview">
<div class="browser-bar">
<div class="dots">
<span class="dot red"></span>
<span class="dot yellow"></span>
<span class="dot green"></span>
</div>
</div>
<div class="webpage-content">
<h1>{{ title }}</h1>
<p :style="{ color: paragraphColor }">欢迎光临</p>
<ul>
<li v-for="(item, index) in items" :key="index">{{ item }}</li>
</ul>
</div>
</div>
<!-- 右侧DOM -->
<div class="dom-tree">
<div class="tree-node">
<span class="tag">&lt;html&gt;</span>
<div class="tree-children">
<div class="tree-node">
<span class="tag">&lt;body&gt;</span>
<div class="tree-children">
<div class="tree-node" :class="{ 'active': title === 'Hello World!' }">
<span class="tag">&lt;h1&gt;</span>
<span class="text">{{ title }}</span>
</div>
<div class="tree-node" :class="{ 'active': paragraphColor === 'red' }">
<span class="tag">&lt;p&gt;</span>
<span class="text">欢迎光临</span>
</div>
<div class="tree-node">
<span class="tag">&lt;ul&gt;</span>
<div class="tree-children">
<div class="tree-node" v-for="(item, index) in items" :key="index">
<span class="tag">&lt;li&gt;</span>
<span class="text">{{ item }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="controls">
<button @click="modifyTitle" class="btn-primary">修改标题</button>
<button @click="addItem" class="btn-secondary">添加列表项</button>
<button @click="changeColor" class="btn-secondary">改变段落颜色</button>
<button @click="removeItem" class="btn-danger">删除列表项</button>
</div>
<div class="code-display">
<h4>对应代码</h4>
<pre><code v-if="title === 'Hello World!'">document.querySelector('h1').textContent = '{{ title }}'</code>
<code v-else-if="paragraphColor === 'red'">document.querySelector('p').style.color = '{{ paragraphColor }}'</code>
<code v-else>点击上方按钮查看对应代码</code></pre>
</div>
</div>
</template>
<style scoped>
.dom-tree-demo {
border: 1px solid var(--vp-c-border);
border-radius: 12px;
padding: 24px;
margin: 24px 0;
background: var(--vp-c-bg);
}
h3 {
margin: 0 0 20px 0;
font-size: 18px;
font-weight: 600;
color: var(--vp-c-text-1);
}
.demo-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
margin-bottom: 20px;
}
@media (max-width: 768px) {
.demo-container {
grid-template-columns: 1fr;
}
}
.webpage-preview {
border: 2px solid var(--vp-c-border);
border-radius: 8px;
overflow: hidden;
}
.browser-bar {
background: #f0f0f0;
padding: 8px;
border-bottom: 1px solid var(--vp-c-border);
}
.dots {
display: flex;
gap: 6px;
}
.dot {
width: 12px;
height: 12px;
border-radius: 50%;
}
.dot.red {
background: #ff5f56;
}
.dot.yellow {
background: #ffbd2e;
}
.dot.green {
background: #27c93f;
}
.webpage-content {
padding: 16px;
background: white;
color: black;
}
.webpage-content h1 {
margin: 0 0 12px 0;
font-size: 18px;
font-weight: 600;
}
.webpage-content p {
margin: 0 0 12px 0;
font-size: 14px;
}
.webpage-content ul {
margin: 0;
padding-left: 20px;
}
.webpage-content li {
font-size: 14px;
margin-bottom: 4px;
}
.dom-tree {
border: 1px solid var(--vp-c-border);
border-radius: 8px;
padding: 16px;
background: var(--vp-c-bg-soft);
overflow-x: auto;
}
.tree-node {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
}
.tree-children {
margin-left: 20px;
border-left: 2px solid var(--vp-c-border);
padding-left: 12px;
}
.tag {
color: var(--vp-c-brand-1);
font-family: 'Courier New', monospace;
font-size: 13px;
font-weight: 600;
white-space: nowrap;
}
.text {
color: var(--vp-c-text-2);
font-size: 13px;
}
.tree-node.active {
background: rgba(62, 175, 124, 0.1);
border-radius: 4px;
padding: 4px 8px;
animation: highlight 1s ease;
}
@keyframes highlight {
0%, 100% { background: transparent; }
50% { background: rgba(62, 175, 124, 0.2); }
}
.controls {
display: flex;
gap: 8px;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 20px;
}
button {
padding: 8px 16px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
button:active {
transform: scale(0.95);
}
.btn-primary {
background: var(--vp-c-brand-1);
color: white;
}
.btn-primary:hover {
background: var(--vp-c-brand-2);
}
.btn-secondary {
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
}
.btn-secondary:hover {
background: var(--vp-c-bg-soft-hover);
}
.btn-danger {
background: #f56565;
color: white;
}
.btn-danger:hover {
background: #e53e3e;
}
.code-display {
background: #1e1e1e;
border-radius: 8px;
padding: 16px;
overflow-x: auto;
}
.code-display h4 {
color: #d4d4d4;
margin: 0 0 12px 0;
font-size: 14px;
font-weight: 600;
}
.code-display pre {
margin: 0;
}
.code-display code {
font-family: 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
color: #d4d4d4;
}
</style>
@@ -0,0 +1,358 @@
<script setup>
import { ref } from 'vue'
const price = ref(100)
const discount = ref(0.8)
const result = ref(null)
const isRunning = ref(false)
const functionType = ref('arrow') // 'declaration', 'expression', 'arrow'
const functionTypes = [
{ value: 'declaration', label: 'function 声明' },
{ value: 'expression', label: '函数表达式' },
{ value: 'arrow', label: '箭头函数' }
]
const execute = async () => {
if (isRunning.value) return
isRunning.value = true
result.value = null
//
await new Promise(resolve => setTimeout(resolve, 500))
result.value = price.value * discount.value
isRunning.value = false
}
const currentCode = ref(`const calculatePrice = (price, discount) => {
return price * discount
}`)
</script>
<template>
<div class="function-machine-demo">
<h3>函数就像一台机器</h3>
<div class="pipeline">
<!-- 输入区 -->
<div class="pipeline-section input-section">
<h4>参数输入</h4>
<div class="input-group">
<label>
价格:
<input v-model.number="price" type="number" min="0" :disabled="isRunning" />
</label>
<label>
折扣:
<select v-model.number="discount" :disabled="isRunning">
<option :value="0.8">8 (0.8)</option>
<option :value="0.5">5 (0.5)</option>
<option :value="0.7">7 (0.7)</option>
</select>
</label>
</div>
</div>
<!-- 机器区 -->
<div class="pipeline-section machine-section">
<h4>函数</h4>
<div class="machine">
<div class="machine-label">calculatePrice</div>
<div class="machine-code">
<pre v-if="functionType === 'declaration'"><code>return price * discount</code></pre>
<pre v-else-if="functionType === 'expression'"><code>return price * discount</code></pre>
<pre v-else><code>price * discount</code></pre>
</div>
</div>
<div class="function-type-selector">
<button
v-for="type in functionTypes"
:key="type.value"
@click="functionType = type.value"
:class="{ active: functionType === type.value }"
class="type-btn"
>
{{ type.label }}
</button>
</div>
<div class="tip" v-if="functionType !== 'arrow'"> 写法不同但做的事一模一样</div>
</div>
<!-- 输出区 -->
<div class="pipeline-section output-section">
<h4>返回值输出</h4>
<div class="output-display" :class="{ 'processing': isRunning }">
<div v-if="result === null" class="placeholder">?</div>
<div v-else class="result">¥{{ result.toFixed(2) }}</div>
</div>
</div>
</div>
<div class="controls">
<button @click="execute" :disabled="isRunning" class="btn-execute">
{{ isRunning ? '处理中...' : '执行 ▶' }}
</button>
</div>
<div class="code-display">
<h4>当前函数定义</h4>
<pre><code v-if="functionType === 'declaration'">function calculatePrice(price, discount) {
return price * discount
}</code>
<code v-else-if="functionType === 'expression'">const calculatePrice = function(price, discount) {
return price * discount
}</code>
<code v-else>const calculatePrice = (price, discount) => {
return price * discount
}
//
const calculatePrice = (price, discount) => price * discount</code></pre>
</div>
</div>
</template>
<style scoped>
.function-machine-demo {
border: 1px solid var(--vp-c-border);
border-radius: 12px;
padding: 24px;
margin: 24px 0;
background: var(--vp-c-bg);
}
h3 {
margin: 0 0 20px 0;
font-size: 18px;
font-weight: 600;
color: var(--vp-c-text-1);
}
h4 {
margin: 0 0 12px 0;
font-size: 13px;
font-weight: 600;
color: var(--vp-c-text-2);
}
.pipeline {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 20px;
overflow-x: auto;
}
@media (max-width: 768px) {
.pipeline {
flex-direction: column;
}
}
.pipeline-section {
flex: 1;
min-width: 200px;
padding: 16px;
border-radius: 8px;
background: var(--vp-c-bg-soft);
}
.input-group {
display: flex;
flex-direction: column;
gap: 12px;
}
label {
display: flex;
flex-direction: column;
gap: 4px;
font-size: 13px;
color: var(--vp-c-text-2);
}
input, select {
padding: 6px 8px;
border: 1px solid var(--vp-c-border);
border-radius: 4px;
font-size: 14px;
background: var(--vp-c-bg);
color: var(--vp-c-text-1);
}
input:disabled, select:disabled {
opacity: 0.6;
}
.machine {
background: var(--vp-c-brand-1);
border-radius: 8px;
padding: 16px;
color: white;
text-align: center;
}
.machine-label {
font-size: 12px;
font-weight: 600;
margin-bottom: 8px;
opacity: 0.9;
}
.machine-code pre {
margin: 0;
}
.machine-code code {
font-family: 'Courier New', monospace;
font-size: 14px;
color: white;
}
.function-type-selector {
display: flex;
gap: 8px;
margin-top: 12px;
flex-wrap: wrap;
}
.type-btn {
flex: 1;
min-width: 100px;
padding: 6px 12px;
border: 1px solid var(--vp-c-border);
border-radius: 6px;
font-size: 12px;
font-weight: 500;
background: var(--vp-c-bg);
color: var(--vp-c-text-1);
cursor: pointer;
transition: all 0.2s ease;
}
.type-btn:hover {
background: var(--vp-c-bg-soft);
}
.type-btn.active {
background: var(--vp-c-brand-1);
color: white;
border-color: var(--vp-c-brand-1);
}
.tip {
margin-top: 8px;
font-size: 12px;
color: var(--vp-c-brand-1);
text-align: center;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.output-display {
width: 100%;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid var(--vp-c-border);
border-radius: 8px;
background: var(--vp-c-bg);
font-size: 24px;
font-weight: 600;
font-family: 'Courier New', monospace;
transition: all 0.3s ease;
}
.output-display.processing {
border-color: var(--vp-c-brand-1);
animation: pulse 1s ease infinite;
}
@keyframes pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(62, 175, 124, 0.4); }
50% { box-shadow: 0 0 0 8px rgba(62, 175, 124, 0); }
}
.placeholder {
color: var(--vp-c-text-3);
font-size: 32px;
}
.result {
color: var(--vp-c-brand-1);
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.controls {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
.btn-execute {
padding: 10px 24px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 600;
background: var(--vp-c-brand-1);
color: white;
cursor: pointer;
transition: all 0.2s ease;
}
.btn-execute:hover:not(:disabled) {
background: var(--vp-c-brand-2);
transform: scale(1.05);
}
.btn-execute:active:not(:disabled) {
transform: scale(0.95);
}
.btn-execute:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.code-display {
background: #1e1e1e;
border-radius: 8px;
padding: 16px;
overflow-x: auto;
}
.code-display h4 {
color: #d4d4d4;
margin-bottom: 12px;
}
.code-display pre {
margin: 0;
}
.code-display code {
font-family: 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
color: #d4d4d4;
}
</style>
@@ -0,0 +1,475 @@
<script setup>
import { ref } from 'vue'
const isPlaying = ref(false)
const currentStep = ref(0)
const codeQueue = ref([
{ id: 1, code: 'console.log("1")', type: 'sync', output: '1' },
{ id: 2, code: 'setTimeout(() => console.log("2"), 0)', type: 'async', output: '2' },
{ id: 3, code: 'console.log("3")', type: 'sync', output: '3' },
{ id: 4, code: 'fetch("/api").then(() => console.log("4"))', type: 'async', output: '4' },
{ id: 5, code: 'console.log("5")', type: 'sync', output: '5' }
])
const taskQueue = ref([])
const outputLog = ref([])
const steps = [
{ description: '执行 console.log("1")', output: '1' },
{ description: '遇到 setTimeout,把回调贴到便签栏', output: null },
{ description: '执行 console.log("3")', output: '3' },
{ description: '遇到 fetch,把回调贴到便签栏', output: null },
{ description: '执行 console.log("5")', output: '5' },
{ description: '执行 setTimeout 的回调', output: '2' },
{ description: '执行 fetch 的回调', output: '4' }
]
const reset = () => {
currentStep.value = 0
taskQueue.value = []
outputLog.value = []
isPlaying.value = false
}
const nextStep = () => {
if (currentStep.value >= steps.length) return
const step = steps[currentStep.value]
if (currentStep.value === 1) {
taskQueue.value.push({ id: 2, code: 'console.log("2")', status: 'pending' })
} else if (currentStep.value === 3) {
taskQueue.value.push({ id: 4, code: 'console.log("4")', status: 'pending' })
} else if (currentStep.value === 4) {
taskQueue.value[0].status = 'ready'
} else if (currentStep.value === 5) {
outputLog.value.push({ output: '2', source: 'setTimeout' })
taskQueue.value.shift()
taskQueue.value[0].status = 'ready'
} else if (currentStep.value === 6) {
outputLog.value.push({ output: '4', source: 'fetch' })
}
if (step.output) {
outputLog.value.push({ output: step.output, source: '同步代码' })
}
currentStep.value++
}
const play = async () => {
if (isPlaying.value) return
isPlaying.value = true
while (currentStep.value < steps.length && isPlaying.value) {
nextStep()
await new Promise(resolve => setTimeout(resolve, 1000))
}
isPlaying.value = false
}
const stop = () => {
isPlaying.value = false
}
</script>
<template>
<div class="event-loop-demo">
<h3>事件循环JavaScript 的执行机制</h3>
<div class="workspace">
<!-- 代码队列 -->
<div class="code-queue-section">
<h4>代码队列</h4>
<div class="queue">
<div
v-for="(item, index) in codeQueue"
:key="item.id"
class="code-item"
:class="{
'active': currentStep === index,
'processed': currentStep > index
}"
>
<div class="item-index">{{ item.id }}</div>
<div class="item-code">{{ item.code }}</div>
<div v-if="currentStep === index" class="executing">执行中</div>
</div>
</div>
</div>
<!-- 工位 -->
<div class="worker-section">
<h4>工位单线程</h4>
<div class="worker">
<div class="worker-emoji">👨💻</div>
<div class="worker-status">
{{ currentStep < steps.length ? '正在执行' : '执行完成' }}
</div>
<div v-if="currentStep < steps.length" class="current-task">
{{ steps[currentStep]?.description }}
</div>
</div>
</div>
<!-- 便签栏 -->
<div class="task-queue-section">
<h4>便签栏任务队列</h4>
<div class="task-queue">
<div
v-for="task in taskQueue"
:key="task.id"
class="task-item"
:class="{ 'ready': task.status === 'ready' }"
>
<div class="task-code">{{ task.code }}</div>
<div class="task-status">
{{ task.status === 'ready' ? '✅ 就绪' : '⏳ 等待中...' }}
</div>
</div>
<div v-if="taskQueue.length === 0" class="empty-queue">
暂无待办任务
</div>
</div>
</div>
</div>
<!-- 输出日志 -->
<div class="output-section">
<h4>输出日志</h4>
<div class="output-log">
<div v-if="outputLog.length === 0" class="empty-log">等待输出...</div>
<div
v-for="(log, index) in outputLog"
:key="index"
class="log-entry"
>
<span class="log-output">{{ log.output }}</span>
<span class="log-source">({{ log.source }})</span>
</div>
</div>
</div>
<!-- 控制按钮 -->
<div class="controls">
<button @click="play" :disabled="isPlaying || currentStep >= steps.length" class="btn-play">
{{ isPlaying ? '执行中...' : '▶ 自动播放' }}
</button>
<button @click="nextStep" :disabled="isPlaying || currentStep >= steps.length" class="btn-step">
单步执行
</button>
<button @click="stop" :disabled="!isPlaying" class="btn-stop">
停止
</button>
<button @click="reset" class="btn-reset">
🔄 重置
</button>
</div>
<!-- 说明 -->
<div class="explanation">
<p><strong>执行顺序</strong>{{ outputLog.map(l => l.output).join(', ') || '还未开始' }}</p>
<p><strong>代码书写顺序</strong>1, 2, 3, 4, 5</p>
<p class="highlight">代码从上到下写的但执行顺序不一定从上到下因为异步操作会被"推迟"到当前代码执行完之后</p>
</div>
</div>
</template>
<style scoped>
.event-loop-demo {
border: 1px solid var(--vp-c-border);
border-radius: 12px;
padding: 24px;
margin: 24px 0;
background: var(--vp-c-bg);
}
h3 {
margin: 0 0 20px 0;
font-size: 18px;
font-weight: 600;
color: var(--vp-c-text-1);
}
h4 {
margin: 0 0 12px 0;
font-size: 14px;
font-weight: 600;
color: var(--vp-c-text-2);
}
.workspace {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 16px;
margin-bottom: 20px;
}
@media (max-width: 1024px) {
.workspace {
grid-template-columns: 1fr;
}
}
.code-queue-section,
.worker-section,
.task-queue-section {
border: 1px solid var(--vp-c-border);
border-radius: 8px;
padding: 16px;
background: var(--vp-c-bg-soft);
min-height: 300px;
}
.queue,
.task-queue {
display: flex;
flex-direction: column;
gap: 8px;
}
.code-item,
.task-item {
display: flex;
align-items: center;
gap: 8px;
padding: 10px;
border: 2px solid var(--vp-c-border);
border-radius: 6px;
background: var(--vp-c-bg);
transition: all 0.3s ease;
}
.code-item.active {
border-color: var(--vp-c-brand-1);
box-shadow: 0 0 0 3px rgba(62, 175, 124, 0.1);
animation: highlight 1s ease infinite;
}
@keyframes highlight {
0%, 100% { background: var(--vp-c-bg); }
50% { background: rgba(62, 175, 124, 0.1); }
}
.code-item.processed {
opacity: 0.5;
}
.item-index {
font-size: 12px;
font-weight: 600;
color: var(--vp-c-text-2);
min-width: 20px;
}
.item-code,
.task-code {
flex: 1;
font-family: 'Courier New', monospace;
font-size: 12px;
color: var(--vp-c-text-1);
}
.executing {
font-size: 11px;
font-weight: 600;
color: var(--vp-c-brand-1);
white-space: nowrap;
}
.task-item.ready {
border-color: #38a169;
animation: pulse 1s ease infinite;
}
@keyframes pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(56, 161, 105, 0.4); }
50% { box-shadow: 0 0 0 6px rgba(56, 161, 105, 0); }
}
.task-status {
font-size: 11px;
font-weight: 600;
white-space: nowrap;
}
.empty-queue {
text-align: center;
padding: 20px;
color: var(--vp-c-text-3);
font-size: 13px;
}
.worker {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 200px;
}
.worker-emoji {
font-size: 48px;
margin-bottom: 12px;
}
.worker-status {
font-size: 14px;
font-weight: 600;
color: var(--vp-c-text-1);
margin-bottom: 8px;
}
.current-task {
text-align: center;
font-size: 13px;
color: var(--vp-c-text-2);
padding: 8px;
background: var(--vp-c-bg);
border-radius: 6px;
}
.output-section {
margin-bottom: 20px;
}
.output-log {
display: flex;
flex-wrap: wrap;
gap: 8px;
min-height: 60px;
padding: 12px;
border: 1px solid var(--vp-c-border);
border-radius: 8px;
background: var(--vp-c-bg);
}
.empty-log {
color: var(--vp-c-text-3);
font-size: 13px;
}
.log-entry {
padding: 8px 12px;
background: var(--vp-c-brand-1);
color: white;
border-radius: 6px;
font-size: 14px;
font-weight: 600;
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.log-output {
font-family: 'Courier New', monospace;
}
.log-source {
margin-left: 8px;
font-size: 12px;
opacity: 0.8;
}
.controls {
display: flex;
gap: 8px;
justify-content: center;
margin-bottom: 20px;
flex-wrap: wrap;
}
button {
padding: 8px 16px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
button:active {
transform: scale(0.95);
}
.btn-play {
background: var(--vp-c-brand-1);
color: white;
}
.btn-play:hover:not(:disabled) {
background: var(--vp-c-brand-2);
}
.btn-step {
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
}
.btn-step:hover:not(:disabled) {
background: var(--vp-c-bg-soft-hover);
}
.btn-stop {
background: #ed8936;
color: white;
}
.btn-stop:hover:not(:disabled) {
background: #dd6b20;
}
.btn-reset {
background: #f56565;
color: white;
}
.btn-reset:hover {
background: #e53e3e;
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.explanation {
background: var(--vp-c-bg-soft);
border-left: 4px solid var(--vp-c-brand-1);
border-radius: 8px;
padding: 16px;
}
.explanation p {
margin: 0 0 8px 0;
font-size: 14px;
line-height: 1.6;
color: var(--vp-c-text-1);
}
.explanation p:last-child {
margin-bottom: 0;
}
.explanation strong {
color: var(--vp-c-brand-1);
}
.explanation .highlight {
padding: 12px;
background: rgba(62, 175, 124, 0.1);
border-radius: 6px;
font-weight: 500;
color: var(--vp-c-brand-1);
}
</style>
@@ -0,0 +1,377 @@
<script setup>
import { ref } from 'vue'
//
const basicA = ref(10)
const basicB = ref(null)
const basicStep = ref(0)
const basicMessage = ref('')
//
const obj1Data = ref({ name: '张三', age: 25 })
const obj2Exists = ref(false)
const obj2Age = ref('')
const refMessage = ref('')
const basicCopy = () => {
basicB.value = basicA.value
basicStep.value = 1
basicMessage.value = '✅ 基本类型复制的是值本身'
}
const basicModify = () => {
if (basicB.value === null) {
basicMessage.value = '⚠️ 请先复制'
return
}
basicB.value = 20
basicMessage.value = '✅ 修改 b 不影响 a'
}
const refCopy = () => {
obj2Exists.value = true
obj2Age.value = obj1Data.value.age
refMessage.value = '⚠️ 两个变量指向同一份数据'
}
const refModify = () => {
if (!obj2Exists.value) {
refMessage.value = '⚠️ 请先复制'
return
}
obj1Data.value.age = 30
obj2Age.value = 30
refMessage.value = '❌ 两个变量指向同一份数据,改了一个另一个也变了!'
}
const refSpreadCopy = () => {
obj2Exists.value = true
obj2Age.value = 25
refMessage.value = '✅ 用展开运算符创建真正的副本,现在互不影响'
}
</script>
<template>
<div class="reference-demo">
<h3> vs 引用</h3>
<div class="demo-container">
<!-- 左侧基本类型 -->
<div class="demo-section basic-section">
<h4>基本类型复制值</h4>
<div class="visualization">
<div class="box" :class="{ 'active': basicA !== null }">
<div class="box-label">a</div>
<div class="box-value">{{ basicA }}</div>
</div>
<div class="arrow" v-if="basicStep >= 1">
<div class="arrow-line"></div>
<div class="arrow-head"></div>
</div>
<div class="box" :class="{ 'active': basicB !== null }" v-if="basicStep >= 1">
<div class="box-label">b</div>
<div class="box-value">{{ basicB }}</div>
</div>
</div>
<div class="message" v-if="basicMessage">{{ basicMessage }}</div>
<div class="controls">
<button @click="basicCopy" class="btn-primary">let b = a复制</button>
<button @click="basicModify" class="btn-secondary">b = 20</button>
</div>
</div>
<!-- 右侧引用类型 -->
<div class="demo-section reference-section">
<h4>引用类型复制地址</h4>
<div class="visualization">
<!-- 数据区 -->
<div class="data-area">
<div class="data-label">数据区</div>
<div class="data-content">
<div>{{ `{ name: "${obj1Data.name}", age: ${obj1Data.age} }` }}</div>
</div>
</div>
<div class="pointers">
<div class="pointer">
<div class="pointer-label">obj1</div>
<div class="arrow-line-down"></div>
</div>
<div class="pointer" v-if="obj2Exists">
<div class="pointer-label">obj2</div>
<div class="arrow-line-down"></div>
</div>
</div>
</div>
<div class="message" v-if="refMessage">{{ refMessage }}</div>
<div class="controls">
<button @click="refCopy" class="btn-primary">let obj2 = obj1复制</button>
<button @click="refModify" class="btn-danger">obj2.age = 30</button>
<button @click="refSpreadCopy" class="btn-success">用展开运算符创建副本</button>
</div>
</div>
</div>
<div class="code-display">
<h4>代码</h4>
<pre><code>//
let a = {{ basicA }}
{{ basicB !== null ? `let b = ${basicB}` : '' }}
{{ basicB !== null ? `b = ${basicB}` : '' }}
console.log(a) // {{ basicA }}
//
let obj1 = { name: "{{ obj1Data.name }}", age: {{ obj1Data.age }} }
{{ obj2Exists ? 'let obj2 = obj1 // 指向同一份数据' : '' }}
{{ obj2Exists ? `obj2.age = ${obj1Data.age}` : '' }}
console.log(obj1.age) // {{ obj1Data.age }}
</code></pre>
</div>
</div>
</template>
<style scoped>
.reference-demo {
border: 1px solid var(--vp-c-border);
border-radius: 12px;
padding: 24px;
margin: 24px 0;
background: var(--vp-c-bg);
}
h3 {
margin: 0 0 20px 0;
font-size: 18px;
font-weight: 600;
color: var(--vp-c-text-1);
}
h4 {
margin: 0 0 16px 0;
font-size: 14px;
font-weight: 600;
color: var(--vp-c-text-2);
}
.demo-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
margin-bottom: 24px;
}
@media (max-width: 768px) {
.demo-container {
grid-template-columns: 1fr;
}
}
.demo-section {
border: 1px dashed var(--vp-c-border);
border-radius: 8px;
padding: 20px;
background: var(--vp-c-bg-soft);
}
.visualization {
display: flex;
align-items: center;
justify-content: center;
gap: 20px;
margin-bottom: 16px;
min-height: 120px;
}
.box {
width: 80px;
height: 80px;
border: 2px solid var(--vp-c-border);
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: var(--vp-c-bg);
transition: all 0.3s ease;
}
.box.active {
border-color: var(--vp-c-brand-1);
box-shadow: 0 0 0 3px rgba(62, 175, 124, 0.1);
}
.box-label {
font-size: 12px;
font-weight: 600;
color: var(--vp-c-text-2);
margin-bottom: 4px;
}
.box-value {
font-size: 24px;
font-weight: 600;
font-family: 'Courier New', monospace;
color: var(--vp-c-brand-1);
}
.arrow {
display: flex;
align-items: center;
gap: 4px;
}
.arrow-line {
width: 40px;
height: 2px;
background: var(--vp-c-brand-1);
}
.arrow-head {
font-size: 24px;
color: var(--vp-c-brand-1);
}
.data-area {
text-align: center;
}
.data-label {
font-size: 12px;
font-weight: 600;
color: var(--vp-c-text-2);
margin-bottom: 8px;
}
.data-content {
border: 2px solid var(--vp-c-brand-1);
border-radius: 8px;
padding: 12px;
background: var(--vp-c-bg);
font-family: 'Courier New', monospace;
font-size: 12px;
color: var(--vp-c-text-1);
}
.pointers {
display: flex;
gap: 24px;
margin-top: 12px;
}
.pointer {
text-align: center;
}
.pointer-label {
font-size: 12px;
font-weight: 600;
color: var(--vp-c-text-2);
margin-bottom: 4px;
}
.arrow-line-down {
width: 2px;
height: 30px;
background: var(--vp-c-brand-1);
margin: 0 auto;
}
.message {
text-align: center;
padding: 8px;
border-radius: 6px;
margin-bottom: 12px;
font-size: 13px;
font-weight: 500;
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
}
.controls {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
button {
padding: 6px 12px;
border: none;
border-radius: 6px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
button:active {
transform: scale(0.95);
}
.btn-primary {
background: var(--vp-c-brand-1);
color: white;
}
.btn-primary:hover {
background: var(--vp-c-brand-2);
}
.btn-secondary {
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
}
.btn-secondary:hover {
background: var(--vp-c-bg-soft-hover);
}
.btn-danger {
background: #f56565;
color: white;
}
.btn-danger:hover {
background: #e53e3e;
}
.btn-success {
background: #38a169;
color: white;
}
.btn-success:hover {
background: #2f855a;
}
.code-display {
background: #1e1e1e;
border-radius: 8px;
padding: 16px;
overflow-x: auto;
}
.code-display h4 {
color: #d4d4d4;
margin-bottom: 12px;
}
.code-display pre {
margin: 0;
}
.code-display code {
font-family: 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
color: #d4d4d4;
}
</style>
@@ -0,0 +1,284 @@
<script setup>
import { ref } from 'vue'
const activeScope = ref('block') // 'global', 'function', 'block'
const explanation = ref('')
const scopes = [
{
id: 'global',
name: '全局作用域',
color: '#a0aec0',
variables: ['appName = "Todo"'],
canSee: ['appName']
},
{
id: 'function',
name: '函数 greet() 作用域',
color: '#4299e1',
variables: ['message = "你好"'],
canSee: ['appName', 'message']
},
{
id: 'block',
name: 'if 块作用域',
color: '#38a169',
variables: ['greeting = message + appName'],
canSee: ['appName', 'message', 'greeting']
}
]
const updateExplanation = () => {
const scope = scopes.find(s => s.id === activeScope.value)
if (scope) {
const visible = scope.canSee.map(v => `${v}`).join('、')
explanation.value = `在这个位置,你能使用这些变量:${visible}`
}
}
updateExplanation()
</script>
<template>
<div class="scope-demo">
<h3>作用域变量的"可见范围"</h3>
<div class="scopes-container">
<!-- 全局作用域 -->
<div
class="scope global-scope"
:class="{ 'active': activeScope === 'global' }"
@click="activeScope = 'global'; updateExplanation()"
>
<div class="scope-header">全局作用域</div>
<div class="scope-content">
<div class="variable" :class="{ 'visible': activeScope === 'global', 'dimmed': activeScope !== 'global' }">
appName = "Todo"
</div>
<!-- 函数作用域 -->
<div class="nested-scope">
<div
class="scope function-scope"
:class="{ 'active': activeScope === 'function' }"
@click.stop="activeScope = 'function'; updateExplanation()"
>
<div class="scope-header">函数 greet() 作用域</div>
<div class="scope-content">
<div class="variable" :class="{ 'visible': ['global', 'function'].includes(activeScope), 'dimmed': !['global', 'function'].includes(activeScope) }">
appName = "Todo"
</div>
<div class="variable" :class="{ 'visible': activeScope === 'function', 'dimmed': activeScope !== 'function' }">
message = "你好"
</div>
<!-- 块级作用域 -->
<div class="nested-scope">
<div
class="scope block-scope"
:class="{ 'active': activeScope === 'block' }"
@click.stop="activeScope = 'block'; updateExplanation()"
>
<div class="scope-header">if 块作用域</div>
<div class="scope-content">
<div class="variable" :class="{ 'visible': true, 'dimmed': false }">
appName = "Todo"
</div>
<div class="variable" :class="{ 'visible': true, 'dimmed': false }">
message = "你好"
</div>
<div class="variable" :class="{ 'visible': activeScope === 'block', 'dimmed': activeScope !== 'block' }">
greeting = message + appName
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="explanation" v-if="explanation">
{{ explanation }}
</div>
<div class="code-display">
<h4>对应代码</h4>
<pre><code>const appName = "Todo" //
function greet() {
const message = "你好" //
if (true) {
const greeting = message + appName //
console.log(greeting)
}
console.log(greeting) //
}</code></pre>
</div>
</div>
</template>
<style scoped>
.scope-demo {
border: 1px solid var(--vp-c-border);
border-radius: 12px;
padding: 24px;
margin: 24px 0;
background: var(--vp-c-bg);
}
h3 {
margin: 0 0 20px 0;
font-size: 18px;
font-weight: 600;
color: var(--vp-c-text-1);
}
.scopes-container {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
.scope {
border: 3px solid var(--vp-c-border);
border-radius: 12px;
padding: 20px;
cursor: pointer;
transition: all 0.3s ease;
background: var(--vp-c-bg-soft);
}
.scope:hover {
border-color: var(--vp-c-brand-1);
transform: scale(1.02);
}
.scope.active {
border-width: 4px;
box-shadow: 0 0 0 4px rgba(62, 175, 124, 0.1);
}
.global-scope {
border-color: #a0aec0;
}
.global-scope.active {
border-color: #a0aec0;
box-shadow: 0 0 0 4px rgba(160, 174, 192, 0.2);
}
.function-scope {
border-color: #4299e1;
}
.function-scope.active {
border-color: #4299e1;
box-shadow: 0 0 0 4px rgba(66, 153, 225, 0.2);
}
.block-scope {
border-color: #38a169;
}
.block-scope.active {
border-color: #38a169;
box-shadow: 0 0 0 4px rgba(56, 161, 105, 0.2);
}
.scope-header {
font-size: 12px;
font-weight: 600;
margin-bottom: 12px;
text-align: center;
}
.scope-content {
display: flex;
flex-direction: column;
gap: 8px;
}
.nested-scope {
display: flex;
justify-content: center;
margin-top: 12px;
}
.variable {
padding: 8px 12px;
border-radius: 6px;
font-family: 'Courier New', monospace;
font-size: 12px;
font-weight: 500;
background: var(--vp-c-bg);
transition: all 0.3s ease;
}
.variable.visible {
color: var(--vp-c-text-1);
font-weight: 600;
}
.variable.dimmed {
color: var(--vp-c-text-3);
opacity: 0.5;
}
.explanation {
text-align: center;
padding: 12px;
border-radius: 8px;
margin-bottom: 20px;
font-size: 14px;
font-weight: 500;
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.code-display {
background: #1e1e1e;
border-radius: 8px;
padding: 16px;
overflow-x: auto;
}
.code-display h4 {
color: #d4d4d4;
margin: 0 0 12px 0;
font-size: 14px;
font-weight: 600;
}
.code-display pre {
margin: 0;
}
.code-display code {
font-family: 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
color: #d4d4d4;
}
@media (max-width: 768px) {
.scopes-container {
flex-direction: column;
align-items: center;
}
.scope {
min-width: 280px;
}
}
</style>
@@ -0,0 +1,278 @@
<script setup>
import { ref } from 'vue'
const name = ref('张三')
const age = ref(25)
const isStudent = ref(true)
const showMessage = ref('')
const showSuccess = ref(false)
const modifyAge = () => {
age.value = 26
showMessage.value = '✅ let 变量可以修改值'
showSuccess.value = true
setTimeout(() => {
showMessage.value = ''
showSuccess.value = false
}, 2000)
}
const modifyName = () => {
showMessage.value = '❌ const 不能重新赋值'
showSuccess.value = false
setTimeout(() => {
showMessage.value = ''
}, 2000)
}
const reset = () => {
name.value = '张三'
age.value = 25
isStudent.value = true
showMessage.value = ''
}
const codeLines = ref([
`const name = "张三"`,
`let age = 25`,
`const isStudent = true`
])
const executeCode = ref([])
</script>
<template>
<div class="variable-box-demo">
<h3>变量就像带名字的盒子</h3>
<div class="boxes-container">
<!-- 盒子 1: const name -->
<div class="variable-box const-box">
<div class="box-label">const name</div>
<div class="box-value">{{ name }}</div>
<div class="box-icon">🔒</div>
</div>
<!-- 盒子 2: let age -->
<div class="variable-box let-box" :class="{ 'success': showSuccess && age === 26 }">
<div class="box-label">let age</div>
<div class="box-value">{{ age }}</div>
<div class="box-icon">🔓</div>
</div>
<!-- 盒子 3: const isStudent -->
<div class="variable-box const-box">
<div class="box-label">const isStudent</div>
<div class="box-value">{{ isStudent }}</div>
<div class="box-icon">🔒</div>
</div>
</div>
<div class="message-bubble" :class="{ 'error': !showSuccess, 'success': showSuccess }" v-if="showMessage">
{{ showMessage }}
</div>
<div class="controls">
<button @click="modifyAge" class="btn-primary">修改 age 26</button>
<button @click="modifyName" class="btn-danger">修改 name 为李四</button>
<button @click="reset" class="btn-secondary">重置</button>
</div>
<div class="code-display">
<pre><code>const name = "张三"
let age = 25
const isStudent = true
{{ executeCode.join('\n') }}</code></pre>
</div>
</div>
</template>
<style scoped>
.variable-box-demo {
border: 1px solid var(--vp-c-border);
border-radius: 12px;
padding: 24px;
margin: 24px 0;
background: var(--vp-c-bg);
}
h3 {
margin: 0 0 16px 0;
font-size: 18px;
font-weight: 600;
color: var(--vp-c-text-1);
}
.boxes-container {
display: flex;
gap: 16px;
justify-content: center;
margin-bottom: 20px;
flex-wrap: wrap;
}
.variable-box {
position: relative;
width: 120px;
height: 120px;
border: 2px solid var(--vp-c-border);
border-radius: 12px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.variable-box.success {
border-color: #3eaf7c;
animation: pulse 0.5s ease;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.box-label {
position: absolute;
top: -12px;
left: 50%;
transform: translateX(-50%);
background: var(--vp-c-brand-1);
color: white;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
white-space: nowrap;
}
.let-box .box-label {
background: #42b983;
}
.box-value {
font-size: 24px;
font-weight: 600;
font-family: 'Courier New', monospace;
color: var(--vp-c-text-1);
margin-bottom: 8px;
}
.box-icon {
font-size: 16px;
}
.message-bubble {
text-align: center;
padding: 12px;
border-radius: 8px;
margin-bottom: 20px;
font-size: 14px;
font-weight: 500;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.message-bubble.error {
background: #fee;
color: #c00;
}
.message-bubble.success {
background: #e8f5e9;
color: #2e7d32;
}
.controls {
display: flex;
gap: 12px;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 20px;
}
button {
padding: 8px 16px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
button:active {
transform: scale(0.95);
}
.btn-primary {
background: var(--vp-c-brand-1);
color: white;
}
.btn-primary:hover {
background: var(--vp-c-brand-2);
}
.btn-danger {
background: #f56565;
color: white;
}
.btn-danger:hover {
background: #e53e3e;
}
.btn-secondary {
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
}
.btn-secondary:hover {
background: var(--vp-c-bg-soft-hover);
}
.code-display {
background: #1e1e1e;
border-radius: 8px;
padding: 16px;
overflow-x: auto;
}
.code-display pre {
margin: 0;
}
.code-display code {
font-family: 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
color: #d4d4d4;
}
@media (max-width: 640px) {
.boxes-container {
flex-direction: column;
align-items: center;
}
.variable-box {
width: 200px;
}
.controls {
flex-direction: column;
}
button {
width: 100%;
}
}
</style>
+15 -10
View File
@@ -480,9 +480,16 @@ import RequestStructureDemo from './components/appendix/api-design/RequestStruct
import ResponseStructureDemo from './components/appendix/api-design/ResponseStructureDemo.vue' import ResponseStructureDemo from './components/appendix/api-design/ResponseStructureDemo.vue'
// JavaScript Intro Components // JavaScript Intro Components
import VariableBoxDemo from './components/appendix/javascript-intro/VariableBoxDemo.vue'
import ReferenceDemo from './components/appendix/javascript-intro/ReferenceDemo.vue'
import FunctionMachineDemo from './components/appendix/javascript-intro/FunctionMachineDemo.vue'
import ScopeDemo from './components/appendix/javascript-intro/ScopeDemo.vue'
import ClosureDemo from './components/appendix/javascript-intro/ClosureDemo.vue'
import DOMTreeDemo from './components/appendix/javascript-intro/DOMTreeDemo.vue'
import AsyncRestaurantDemo from './components/appendix/javascript-intro/AsyncRestaurantDemo.vue'
import JSEventLoopDemo from './components/appendix/javascript-intro/JSEventLoopDemo.vue'
import VariableScopeDemo from './components/appendix/javascript-intro/VariableScopeDemo.vue' import VariableScopeDemo from './components/appendix/javascript-intro/VariableScopeDemo.vue'
import DataTypeDemo from './components/appendix/javascript-intro/DataTypeDemo.vue' import DataTypeDemo from './components/appendix/javascript-intro/DataTypeDemo.vue'
import ClosureDemo from './components/appendix/javascript-intro/ClosureDemo.vue'
import ThisContextDemo from './components/appendix/javascript-intro/ThisContextDemo.vue' import ThisContextDemo from './components/appendix/javascript-intro/ThisContextDemo.vue'
import PrototypeDemo from './components/appendix/javascript-intro/PrototypeDemo.vue' import PrototypeDemo from './components/appendix/javascript-intro/PrototypeDemo.vue'
import AsyncDemo from './components/appendix/javascript-intro/AsyncDemo.vue' import AsyncDemo from './components/appendix/javascript-intro/AsyncDemo.vue'
@@ -642,15 +649,6 @@ export default {
app.component('ImperativeVsDeclarativeDemo', ImperativeVsDeclarativeDemo) app.component('ImperativeVsDeclarativeDemo', ImperativeVsDeclarativeDemo)
app.component('ComponentReusabilityDemo', ComponentReusabilityDemo) app.component('ComponentReusabilityDemo', ComponentReusabilityDemo)
// Frontend Evolution Components Registration
app.component('FrontendEvolutionDemo', FrontendEvolutionTimelineDemo)
app.component('EvolutionSliceRequestDemo', EvolutionSliceRequestDemo)
app.component('EvolutionResponsiveGridDemo', EvolutionResponsiveGridDemo)
app.component('EvolutionJQueryVsStateDemo', EvolutionJQueryVsStateDemo)
app.component('RoutingModeDemo', EvolutionRoutingModeDemo)
app.component('RenderingStrategyDemo', EvolutionRenderingStrategyDemo)
app.component('ImperativeVsDeclarativeDemo', EvolutionImperativeVsDeclarativeDemo)
app.component('BackendEvolutionDemo', BackendEvolutionDemo) app.component('BackendEvolutionDemo', BackendEvolutionDemo)
app.component('BackendQuickStartDemo', BackendQuickStartDemo) app.component('BackendQuickStartDemo', BackendQuickStartDemo)
app.component('EvolutionIntroDemo', EvolutionIntroDemo) app.component('EvolutionIntroDemo', EvolutionIntroDemo)
@@ -975,12 +973,19 @@ export default {
app.component('MQComparisonDemo', MQComparisonDemo) app.component('MQComparisonDemo', MQComparisonDemo)
// JavaScript Intro Components Registration // JavaScript Intro Components Registration
app.component('VariableBoxDemo', VariableBoxDemo)
app.component('ReferenceDemo', ReferenceDemo)
app.component('FunctionMachineDemo', FunctionMachineDemo)
app.component('ScopeDemo', ScopeDemo)
app.component('VariableScopeDemo', VariableScopeDemo) app.component('VariableScopeDemo', VariableScopeDemo)
app.component('DataTypeDemo', DataTypeDemo) app.component('DataTypeDemo', DataTypeDemo)
app.component('ClosureDemo', ClosureDemo) app.component('ClosureDemo', ClosureDemo)
app.component('ThisContextDemo', ThisContextDemo) app.component('ThisContextDemo', ThisContextDemo)
app.component('PrototypeDemo', PrototypeDemo) app.component('PrototypeDemo', PrototypeDemo)
app.component('AsyncDemo', AsyncDemo) app.component('AsyncDemo', AsyncDemo)
app.component('DOMTreeDemo', DOMTreeDemo)
app.component('AsyncRestaurantDemo', AsyncRestaurantDemo)
app.component('JSEventLoopDemo', JSEventLoopDemo)
}, },
setup() { setup() {
const route = useRoute() const route = useRoute()
+1 -1
View File
@@ -10,7 +10,7 @@ Deeply master the MCP protocol and Claude Code advanced techniques to improve de
<NavGrid> <NavGrid>
<NavCard <NavCard
href="#" href="#"
title="Advanced 1: MCP & ClaudeCode Skills" title="Advanced 1: MCP & Claude Code Skills"
description="Master Model Context Protocol (MCP) to extend the capabilities of AI programming tools" description="Master Model Context Protocol (MCP) to extend the capabilities of AI programming tools"
/> />
<NavCard <NavCard
+1 -1
View File
@@ -10,7 +10,7 @@ Maîtriser en profondeur le protocole MCP et les techniques avancées de Claude
<NavGrid> <NavGrid>
<NavCard <NavCard
href="#" href="#"
title="Avancé 1 : Compétences MCP et ClaudeCode" title="Avancé 1 : Compétences MCP et Claude Code"
description="Maîtriser Model Context Protocol (MCP) pour étendre les capacités des outils de programmation IA" description="Maîtriser Model Context Protocol (MCP) pour étendre les capacités des outils de programmation IA"
/> />
<NavCard <NavCard
File diff suppressed because it is too large Load Diff
@@ -722,13 +722,13 @@ RLS 正是为解决这类数据安全与隔离需求而生。它允许开发者
## 3.1 Clone and Run Supabase Demos ## 3.1 Clone and Run Supabase Demos
要开展实操,首先需要获取配套的演示代码仓库。你可以让 Trae 或 ClaudeCode 协助 git clone 以下仓库:https://github.com/THU-SIGS-AIID/Project5-Supabase-Demos 要开展实操,首先需要获取配套的演示代码仓库。你可以让 Trae 或 Claude Code 协助 git clone 以下仓库:https://github.com/THU-SIGS-AIID/Project5-Supabase-Demos
若已配置 SSH 密钥,建议使用 SSH 地址进行 clonegit@github.com:THU-SIGS-AIID/Project5-Supabase-Demos.git)以提升安全性;若 SSH 或 HTTPS 连接遇到网络问题,可以直接点击仓库页面的 “Download ZIP”,获取压缩包后解压即可看到完整代码。 若已配置 SSH 密钥,建议使用 SSH 地址进行 clonegit@github.com:THU-SIGS-AIID/Project5-Supabase-Demos.git)以提升安全性;若 SSH 或 HTTPS 连接遇到网络问题,可以直接点击仓库页面的 “Download ZIP”,获取压缩包后解压即可看到完整代码。
![](images/image36.png) ![](images/image36.png)
Clone 后,你同样可以让 Trae 或者是 ClaudeCode 帮你启动项目,例如直接在 Agent 界面中说明: `帮我直接启动这个项目里面的 project 1 `,或者复制对应想启动 project 的绝对路径,粘贴给大模型让大模型直接启动。 Clone 后,你同样可以让 Trae 或者是 Claude Code 帮你启动项目,例如直接在 Agent 界面中说明: `帮我直接启动这个项目里面的 project 1 `,或者复制对应想启动 project 的绝对路径,粘贴给大模型让大模型直接启动。
## 3.2 Project1 - burger-shop-menu-crud ## 3.2 Project1 - burger-shop-menu-crud
@@ -1,3 +1,3 @@
# 高级一:MCP 与 ClaudeCode Skills # 高级一:MCP 与 Claude Code Skills
> 本章节正在编写中,敬请期待... > 本章节正在编写中,敬请期待...
+2 -2
View File
@@ -10,8 +10,8 @@
<NavGrid> <NavGrid>
<NavCard <NavCard
href="/easy-vibe/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/" href="/easy-vibe/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/"
title="高级一:MCP 与 ClaudeCode Skills" title="高级一:MCP 与 Claude Code Skills"
description="掌握 Model Context Protocol (MCP),扩展 AI 编程工具的能力边界" description="掌握 Model Context Protocol (MCP),扩展 AI 编程工具的能力边界"
/> />
<NavCard <NavCard
+1 -1
View File
@@ -10,7 +10,7 @@
<NavGrid> <NavGrid>
<NavCard <NavCard
href="#" href="#"
title="高級一:MCP 與 ClaudeCode Skills" title="高級一:MCP 與 Claude Code Skills"
description="掌握 Model Context Protocol (MCP),擴展 AI 編程工具的能力邊界" description="掌握 Model Context Protocol (MCP),擴展 AI 編程工具的能力邊界"
/> />
<NavCard <NavCard
+36
View File
@@ -0,0 +1,36 @@
import js from '@eslint/js'
import pluginVue from 'eslint-plugin-vue'
import vueParser from 'vue-eslint-parser'
export default [
{
ignores: ['node_modules/**', 'docs/.vitepress/dist/**', 'docs/.vitepress/cache/**']
},
js.configs.recommended,
...pluginVue.configs['flat/recommended'],
{
files: ['**/*.vue', '**/*.js'],
languageOptions: {
parser: vueParser,
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module'
}
},
rules: {
'vue/no-ref-as-operand': 'error',
'vue/no-setup-props-destructure': 'error',
'vue/no-template-shadow': 'error',
'vue/require-v-for-key': 'error',
'vue/no-use-v-if-with-v-for': 'error',
'vue/require-valid-default-prop': 'error',
'vue/no-mutating-props': 'error',
'vue/return-in-computed-property': 'error',
'vue/no-side-effects-in-computed-properties': 'error',
'vue/no-async-in-computed-properties': 'error',
'no-undef': 'error',
'no-unused-vars': 'warn',
'vue/multi-word-component-names': 'off'
}
}
]
+1630 -586
View File
File diff suppressed because it is too large Load Diff
+8 -2
View File
@@ -5,10 +5,12 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vitepress dev docs", "dev": "vitepress dev docs",
"build": "vitepress build docs --force", "build": "npm run lint && vitepress build docs --force",
"preview": "vitepress preview docs", "preview": "vitepress preview docs",
"format": "prettier --write .", "format": "prettier --write .",
"verify": "bash scripts/verify.sh" "verify": "bash scripts/verify.sh",
"lint": "eslint docs/.vitepress/theme",
"lint:fix": "eslint docs/.vitepress/theme --fix"
}, },
"keywords": [ "keywords": [
"easy-vibe", "easy-vibe",
@@ -21,6 +23,10 @@
}, },
"license": "CC-BY-NC-SA-4.0", "license": "CC-BY-NC-SA-4.0",
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.0.0",
"eslint": "^9.0.0",
"eslint-plugin-vue": "^9.30.0",
"vue-eslint-parser": "^9.4.3",
"markdown-it-katex": "^2.0.3", "markdown-it-katex": "^2.0.3",
"prettier": "^3.7.4" "prettier": "^3.7.4"
}, },