diff --git "a/cn/Zadig v4.0/21.\345\274\200\345\217\221\350\200\205\344\270\255\345\277\203/02.idp-manual.md" "b/cn/Zadig v4.0/21.\345\274\200\345\217\221\350\200\205\344\270\255\345\277\203/02.idp-manual.md" index e488dc232..cbbca7b3c 100644 --- "a/cn/Zadig v4.0/21.\345\274\200\345\217\221\350\200\205\344\270\255\345\277\203/02.idp-manual.md" +++ "b/cn/Zadig v4.0/21.\345\274\200\345\217\221\350\200\205\344\270\255\345\277\203/02.idp-manual.md" @@ -210,42 +210,42 @@ export default { ```javascript // src/index.js -import React, { useState, useEffect } from 'react'; import './styles.css'; -function MyPluginPage() { - const [data, setData] = useState([]); - const [loading, setLoading] = useState(true); - - useEffect(() => { - fetchData(); - }, []); - - const fetchData = async () => { - try { - const response = await fetch('/api/data'); - const result = await response.json(); - setData(result); - } catch (error) { - console.error('Error fetching data:', error); - } finally { - setLoading(false); +const MyPluginPage = { + name: 'MyPluginPage', + data() { + return { + data: [], + loading: true + }; + }, + async mounted() { + await this.fetchData(); + }, + methods: { + async fetchData() { + try { + const response = await fetch('/api/data'); + const result = await response.json(); + this.data = result; + } catch (error) { + console.error('Error fetching data:', error); + } finally { + this.loading = false; + } } - }; - - return ( -
+ }, + template: ` +

我的插件

- {loading ? ( -
加载中...
- ) : ( -
- {/* 业务逻辑 */} -
- )} +
加载中...
+
+ +
- ); -} + ` +}; export default { name: 'my-plugin', @@ -274,44 +274,52 @@ export default { ```javascript // src/index.js -import React, { useState, useEffect } from 'react'; import './styles.css'; -function MyTabComponent({ context }) { - // context 包含父页面的上下文信息 - // 如:项目名称、环境信息等 - const { projectName, envName } = context || {}; - const [info, setInfo] = useState(null); - - useEffect(() => { - if (projectName) { - loadProjectInfo(projectName); +const MyTabComponent = { + name: 'MyTabComponent', + props: { + context: { + type: Object, + default: () => ({}) } - }, [projectName]); - - const loadProjectInfo = async (name) => { - try { - const response = await fetch(`/api/project/${name}`); - const data = await response.json(); - setInfo(data); - } catch (error) { - console.error('Error:', error); + }, + data() { + return { + info: null + }; + }, + watch: { + 'context.projectName': { + handler(newProjectName) { + if (newProjectName) { + this.loadProjectInfo(newProjectName); + } + }, + immediate: true } - }; - - return ( -
+ }, + methods: { + async loadProjectInfo(name) { + try { + const response = await fetch(`/api/project/${name}`); + const data = await response.json(); + this.info = data; + } catch (error) { + console.error('Error:', error); + } + } + }, + template: ` +

项目信息

- {info ? ( -
- {/* 展示项目相关信息 */} -
- ) : ( -
暂无数据
- )} +
+ +
+
暂无数据
- ); -} + ` +}; export default { name: 'my-tab-plugin', @@ -367,8 +375,8 @@ module.exports = { `src/index.js` 是插件的入口文件: ```javascript -import React from 'react'; -import App from './App'; +import Vue from 'vue'; +import App from './App.vue'; import './styles/index.css'; // 导出插件配置和组件 @@ -397,21 +405,29 @@ export default { #### 组件开发 ```javascript -// 使用函数组件和 Hooks -import React, { useState, useEffect } from 'react'; - -function MyComponent() { - const [data, setData] = useState([]); - - useEffect(() => { +// 使用Vue2组件和Options API +export default { + name: 'MyComponent', + data() { + return { + data: [] + }; + }, + async mounted() { // 数据加载逻辑 - fetchData(); - }, []); - - return
{/* 组件内容 */}
; -} - -export default MyComponent; + await this.fetchData(); + }, + methods: { + async fetchData() { + // 数据获取逻辑 + } + }, + template: ` +
+ +
+ ` +}; ``` #### 样式管理 @@ -472,80 +488,109 @@ async function fetchData() { #### 懒加载 ```javascript -// 使用 React.lazy 进行组件懒加载 -const HeavyComponent = React.lazy(() => import('./HeavyComponent')); - -function App() { - return ( - 加载中...
}> +// 使用Vue异步组件进行懒加载 +export default { + name: 'App', + components: { + HeavyComponent: () => import('./HeavyComponent.vue') + }, + template: ` +
- - ); -} +
+ ` +}; ``` #### 防抖与节流 ```javascript -import { useState, useCallback } from 'react'; - // 使用 debounce 优化搜索输入 -function SearchInput() { - const [query, setQuery] = useState(''); - - const handleSearch = useCallback( - debounce((value) => { - // 执行搜索 - performSearch(value); - }, 300), - [] - ); - - return ( +export default { + name: 'SearchInput', + data() { + return { + query: '', + timer: null + }; + }, + methods: { + handleSearch(value) { + // 清除上一次的定时器 + if (this.timer) { + clearTimeout(this.timer); + } + // 设置新的定时器 + this.timer = setTimeout(() => { + this.performSearch(value); + }, 300); + }, + performSearch(value) { + // 执行搜索逻辑 + console.log('搜索:', value); + } + }, + template: ` { - setQuery(e.target.value); - handleSearch(e.target.value); - }} + v-model="query" + @input="handleSearch(query)" + placeholder="输入搜索关键词" /> - ); -} + ` +}; ``` ### 5. 用户体验 #### 加载状态 ```javascript -function DataList() { - const [loading, setLoading] = useState(true); - const [data, setData] = useState([]); - - return ( +export default { + name: 'DataList', + data() { + return { + loading: true, + data: [] + }; + }, + template: `
- {loading ? ( -
加载中...
- ) : ( -
{/* 数据展示 */}
- )} +
+ 加载中... +
+
+ +
- ); -} + ` +}; ``` #### 空状态提示 ```javascript -function DataList({ data }) { - if (data.length === 0) { - return ( -
+export default { + name: 'DataList', + props: { + data: { + type: Array, + default: () => [] + } + }, + methods: { + handleRefresh() { + this.$emit('refresh'); + } + }, + template: ` +
+

暂无数据

- +
- ); - } - - return
{/* 数据列表 */}
; -} +
+ +
+
+ ` +}; ``` ### 6. 数据持久化 diff --git a/en/Zadig v4.0/21.Developer Guide/02.idp-manual.md b/en/Zadig v4.0/21.Developer Guide/02.idp-manual.md index 5b1cb64b5..f9114674a 100644 --- a/en/Zadig v4.0/21.Developer Guide/02.idp-manual.md +++ b/en/Zadig v4.0/21.Developer Guide/02.idp-manual.md @@ -210,42 +210,42 @@ export default { ```javascript // src/index.js -import React, { useState, useEffect } from 'react'; import './styles.css'; -function MyPluginPage() { - const [data, setData] = useState([]); - const [loading, setLoading] = useState(true); - - useEffect(() => { - fetchData(); - }, []); - - const fetchData = async () => { - try { - const response = await fetch('/api/data'); - const result = await response.json(); - setData(result); - } catch (error) { - console.error('Error fetching data:', error); - } finally { - setLoading(false); +const MyPluginPage = { + name: 'MyPluginPage', + data() { + return { + data: [], + loading: true + }; + }, + async mounted() { + await this.fetchData(); + }, + methods: { + async fetchData() { + try { + const response = await fetch('/api/data'); + const result = await response.json(); + this.data = result; + } catch (error) { + console.error('Error fetching data:', error); + } finally { + this.loading = false; + } } - }; - - return ( -
+ }, + template: ` +

My Plugin

- {loading ? ( -
Loading...
- ) : ( -
- {/* Business logic */} -
- )} +
Loading...
+
+ +
- ); -} + ` +}; export default { name: 'my-plugin', @@ -274,44 +274,52 @@ export default { ```javascript // src/index.js -import React, { useState, useEffect } from 'react'; import './styles.css'; -function MyTabComponent({ context }) { - // context contains parent page context information - // Such as: project name, environment info, etc. - const { projectName, envName } = context || {}; - const [info, setInfo] = useState(null); - - useEffect(() => { - if (projectName) { - loadProjectInfo(projectName); +const MyTabComponent = { + name: 'MyTabComponent', + props: { + context: { + type: Object, + default: () => ({}) } - }, [projectName]); - - const loadProjectInfo = async (name) => { - try { - const response = await fetch(`/api/project/${name}`); - const data = await response.json(); - setInfo(data); - } catch (error) { - console.error('Error:', error); + }, + data() { + return { + info: null + }; + }, + watch: { + 'context.projectName': { + handler(newProjectName) { + if (newProjectName) { + this.loadProjectInfo(newProjectName); + } + }, + immediate: true } - }; - - return ( -
+ }, + methods: { + async loadProjectInfo(name) { + try { + const response = await fetch(`/api/project/${name}`); + const data = await response.json(); + this.info = data; + } catch (error) { + console.error('Error:', error); + } + } + }, + template: ` +

Project Information

- {info ? ( -
- {/* Display project related information */} -
- ) : ( -
No data available
- )} +
+ +
+
No data available
- ); -} + ` +}; export default { name: 'my-tab-plugin', @@ -367,8 +375,8 @@ module.exports = { `src/index.js` is the plugin's entry file: ```javascript -import React from 'react'; -import App from './App'; +import Vue from 'vue'; +import App from './App.vue'; import './styles/index.css'; // Export plugin configuration and component @@ -397,21 +405,29 @@ export default { #### Component Development ```javascript -// Use functional components and Hooks -import React, { useState, useEffect } from 'react'; - -function MyComponent() { - const [data, setData] = useState([]); - - useEffect(() => { +// Use Vue2 components and Options API +export default { + name: 'MyComponent', + data() { + return { + data: [] + }; + }, + async mounted() { // Data loading logic - fetchData(); - }, []); - - return
{/* Component content */}
; -} - -export default MyComponent; + await this.fetchData(); + }, + methods: { + async fetchData() { + // Data fetching logic + } + }, + template: ` +
+ +
+ ` +}; ``` #### Style Management @@ -472,80 +488,109 @@ async function fetchData() { #### Lazy Loading ```javascript -// Use React.lazy for component lazy loading -const HeavyComponent = React.lazy(() => import('./HeavyComponent')); - -function App() { - return ( - Loading...
}> +// Use Vue async components for lazy loading +export default { + name: 'App', + components: { + HeavyComponent: () => import('./HeavyComponent.vue') + }, + template: ` +
- - ); -} +
+ ` +}; ``` #### Debounce and Throttle ```javascript -import { useState, useCallback } from 'react'; - // Use debounce to optimize search input -function SearchInput() { - const [query, setQuery] = useState(''); - - const handleSearch = useCallback( - debounce((value) => { - // Perform search - performSearch(value); - }, 300), - [] - ); - - return ( +export default { + name: 'SearchInput', + data() { + return { + query: '', + timer: null + }; + }, + methods: { + handleSearch(value) { + // Clear previous timer + if (this.timer) { + clearTimeout(this.timer); + } + // Set new timer + this.timer = setTimeout(() => { + this.performSearch(value); + }, 300); + }, + performSearch(value) { + // Search logic + console.log('Searching:', value); + } + }, + template: ` { - setQuery(e.target.value); - handleSearch(e.target.value); - }} + v-model="query" + @input="handleSearch(query)" + placeholder="Enter search keywords" /> - ); -} + ` +}; ``` ### 5. User Experience #### Loading State ```javascript -function DataList() { - const [loading, setLoading] = useState(true); - const [data, setData] = useState([]); - - return ( +export default { + name: 'DataList', + data() { + return { + loading: true, + data: [] + }; + }, + template: `
- {loading ? ( -
Loading...
- ) : ( -
{/* Data display */}
- )} +
+ Loading... +
+
+ +
- ); -} + ` +}; ``` #### Empty State ```javascript -function DataList({ data }) { - if (data.length === 0) { - return ( -
+export default { + name: 'DataList', + props: { + data: { + type: Array, + default: () => [] + } + }, + methods: { + handleRefresh() { + this.$emit('refresh'); + } + }, + template: ` +
+

No data available

- +
- ); - } - - return
{/* Data list */}
; -} +
+ +
+
+ ` +}; ``` ### 6. Data Persistence