Merge branch 'mvp-step1' of https://dev.azure.com/alicorn-dev/KintoneAppBuilder/_git/KintoneAppBuilder into mvp-step1
This commit is contained in:
@@ -47,3 +47,7 @@ quasar build
|
|||||||
|
|
||||||
### Customize the configuration
|
### Customize the configuration
|
||||||
See [Configuring quasar.config.js](https://v2.quasar.dev/quasar-cli-vite/quasar-config-js).
|
See [Configuring quasar.config.js](https://v2.quasar.dev/quasar-cli-vite/quasar-config-js).
|
||||||
|
|
||||||
|
## VUE3.0编程规范
|
||||||
|
1. [VUE3.0编程概要](./VUE3.0概要.md)
|
||||||
|
2. [VUE3.0编程规范](./VUE3.0-coding-rule.md)
|
||||||
|
|||||||
241
frontend/VUE3.0-coding-rule.md
Normal file
241
frontend/VUE3.0-coding-rule.md
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
以下是一份 Vue 3 和 TypeScript 的编程规范:
|
||||||
|
|
||||||
|
**1. 组件定义**
|
||||||
|
|
||||||
|
- 推荐使用 `defineComponent` 来定义组件,以获取 TypeScript 的类型支持。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
// 组件选项
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. 数据定义**
|
||||||
|
|
||||||
|
- 使用 `reactive` 定义响应式对象。
|
||||||
|
- 使用 `ref` 定义响应式单值。
|
||||||
|
- 使用 `computed` 定义计算属性。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { reactive, ref, computed } from 'vue'
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
count: 0,
|
||||||
|
message: 'Hello Vue 3'
|
||||||
|
})
|
||||||
|
|
||||||
|
const count = ref(0)
|
||||||
|
|
||||||
|
const doubledCount = computed(() => state.count * 2)
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. 生命周期钩子**
|
||||||
|
|
||||||
|
- 使用 `onMounted`、`onUpdated` 等生命周期钩子,而不是 `beforeCreate`、`created`、`beforeMount`、`mounted`、`beforeUpdate`、`updated`、`beforeUnmount`、`unmounted`。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { onMounted } from 'vue'
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('Component is mounted.')
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. 组件通信**
|
||||||
|
|
||||||
|
- 使用 `props` 和 `emit` 实现父子组件通信。
|
||||||
|
- 使用 `provide` 和 `inject` 实现祖先和后代组件通信。
|
||||||
|
- 不再推荐使用 `event bus` 进行任意组件间的通信,可以使用 Vuex 或者全局 `provide`/`inject` 替代。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 父组件
|
||||||
|
<ChildComponent @my-event="handleEvent" />
|
||||||
|
|
||||||
|
// 子组件
|
||||||
|
this.$emit('my-event', eventData)
|
||||||
|
```
|
||||||
|
|
||||||
|
**5. 异步处理**
|
||||||
|
|
||||||
|
- 使用 `async/await` 进行异步处理。
|
||||||
|
- 使用 `Suspense` 和 `async setup()` 处理异步依赖。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const response = await axios.get('https://api.example.com/data')
|
||||||
|
data.value = response.data
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**6. Vue Router 和 Vuex**
|
||||||
|
|
||||||
|
- 使用 Vue Router 4 和 Vuex 4,它们是为 Vue 3 重新设计的。
|
||||||
|
- 使用 `useRouter` 和 `useRoute` 钩子函数在组件中使用 router。
|
||||||
|
- 使用 `useStore` 钩子函数在组件中使用 Vuex store。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
const router = useRouter()
|
||||||
|
```
|
||||||
|
|
||||||
|
**7. 组件模板**
|
||||||
|
|
||||||
|
- 使用 `v-model` 代替 `.sync` 修饰符进行双向绑定。
|
||||||
|
- 使用 `v-for` 和 `:key` 渲染列表。
|
||||||
|
- 使用 `v-if` 和 `v-else`、`v-else-if` 进行条件渲染。
|
||||||
|
- 使用 `v-on` 或者 `@` 监听事件。
|
||||||
|
- 使用 `v-bind` 或者 `:` 绑定属性。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<template>
|
||||||
|
<div v-if="condition">If block</div>
|
||||||
|
<div v-else>Else block</div>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li v-for="(item, index) in list" :key="index">{{ item }}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button @click="handleClick">Click me</button>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
8. **使用类型注解和接口**
|
||||||
|
|
||||||
|
在 TypeScript 中,尽可能使用类型注解和接口来提供更完善的类型信息和类型检查。这将有助于发现和预防错误。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface User {
|
||||||
|
name: string;
|
||||||
|
age: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user: User = {
|
||||||
|
name: 'John',
|
||||||
|
age: 30
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
9. **模块化和组件化**
|
||||||
|
|
||||||
|
尽可能将功能和逻辑模块化和组件化,使得代码更易于理解和维护。特别是使用 Composition API 时,可以将公共的逻辑封装成 composable 函数。
|
||||||
|
|
||||||
|
下面是一个使用 `Suspense` 和 `axios` 的示例,这个示例将会从一个 JSON Placeholder API 获取数据:
|
||||||
|
|
||||||
|
首先,我们创建一个 composable 函数,用于获取数据:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export function useAsyncData(url: string) {
|
||||||
|
const data = ref(null)
|
||||||
|
const error = ref(null)
|
||||||
|
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(url)
|
||||||
|
data.value = response.data
|
||||||
|
} catch (e) {
|
||||||
|
error.value = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { data, error, fetchData }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
然后,我们创建一个 Vue 组件来使用这个函数:
|
||||||
|
|
||||||
|
```js
|
||||||
|
<template>
|
||||||
|
<Suspense>
|
||||||
|
<template #default>
|
||||||
|
<div v-if="error">{{ error.message }}</div>
|
||||||
|
<div v-else>{{ data }}</div>
|
||||||
|
</template>
|
||||||
|
<template #fallback>
|
||||||
|
<div>Loading...</div>
|
||||||
|
</template>
|
||||||
|
</Suspense>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, onMounted } from 'vue'
|
||||||
|
import { useAsyncData } from './composables/useAsyncData'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
const { data, error, fetchData } = useAsyncData('https://jsonplaceholder.typicode.com/posts/1')
|
||||||
|
|
||||||
|
onMounted(fetchData)
|
||||||
|
|
||||||
|
return { data, error }
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 在这里添加 CSS 样式 */
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
在这个示例中,我们在 `useAsyncData` 函数中获取数据。当 `onMounted` 钩子函数被调用时(也就是当组件挂载完成后),我们开始获取数据。这个过程是异步的,因此我们在 `Suspense` 组件的 `#fallback` 插槽中显示一个 "Loading..." 的提示。一旦数据加载完成,`Suspense` 组件的 `#default` 插槽就会被渲染,并显示获取到的数据。
|
||||||
|
|
||||||
|
10. **良好的代码风格**
|
||||||
|
|
||||||
|
遵循一致的代码风格和代码质量规则,例如使用 ESLint 和 Prettier 来检查和格式化代码。
|
||||||
|
|
||||||
|
11. **单元测试和端到端测试**
|
||||||
|
|
||||||
|
对关键的组件和函数编写单元测试,对用户的主要操作路径编写端到端测试,确保功能的正确性。
|
||||||
|
|
||||||
|
12. **注释和文档**
|
||||||
|
|
||||||
|
对复杂的逻辑和函数编写注释,提供必要的项目文档,帮助其他开发者理解和使用你的代码。
|
||||||
|
|
||||||
|
13. **以下是 Vue 2 中被废弃或改变的部分API,以及在 Vue 3 中的替代方案:**
|
||||||
|
|
||||||
|
| Vue 2.x | Vue 3.0 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Vue.set` / `this.$set` | 响应式数据现在是默认的,无需使用这些方法 | Vue 3 的响应式系统是从头开始构建的,所有的对象和数组都是响应式的 |
|
||||||
|
| `Vue.delete` / `this.$delete` | 无需使用这些方法 | 在 Vue 3 中,你只需要使用 `delete` 操作符即可 |
|
||||||
|
| `filters` | 无对应项 | Vue 3 不再支持过滤器,建议使用计算属性或方法替代 |
|
||||||
|
| `Vue.observable` | `reactive` | 用 `reactive` 替代 `Vue.observable`,实现数据的响应式 |
|
||||||
|
| `Vue.prototype` | `app.config.globalProperties` | 在 Vue 3 中,全局 API 已经改变,`Vue.prototype` 被 `app.config.globalProperties` 替代 |
|
||||||
|
| `Vue.component`, `Vue.directive`, `Vue.mixin`, `Vue.use` | `app.component`, `app.directive`, `app.mixin`, `app.use` | 全局注册的 API 改变,如 `Vue.component` 变为 `app.component` |
|
||||||
|
| `beforeDestroy` 和 `destroyed` 生命周期钩子 | `beforeUnmount` 和 `unmounted` | 生命周期钩子名字变化,`beforeDestroy` 和 `destroyed` 分别改为 `beforeUnmount` 和 `unmounted` |
|
||||||
|
| `$on`, `$off`, `$once` | 无对应项 | Event Bus方法被移除,需要用户自行实现或者使用第三方库 |
|
||||||
|
| `v-model` 在自定义组件上使用 | 需要明确的 `modelValue` 和 `update:modelValue` | Vue 3 对 `v-model` 的改动使其在自定义组件上更具灵活性 |
|
||||||
|
| `functional` 选项 | 无对应项 | Vue 3 不再支持函数式组件的写法,而是推荐使用 `render` 函数或 `setup` 函数 |
|
||||||
|
| 异步组件的 `functional` 写法 | `defineAsyncComponent` | 异步组件的创建方式更改,通过 `defineAsyncComponent` 方法创建 |
|
||||||
|
| `destroyed` 和 `beforeDestroy` 钩子函数 | `unmounted` 和 `beforeUnmount` | 生命周期钩子的名称已改为更直观的名称,以更好地表示其在组件实例生命周期中的角色 |
|
||||||
|
| `Vue.extend` | `defineComponent` | Vue 3 使用 `defineComponent` 方法定义组件,有更好的类型推断 |
|
||||||
|
|
||||||
|
注意:Vue 3 对于 Options API 和 Composition API 提供了完全的支持,你可以在一个组件中混合使用这两种 API。不过,为了代码的一致性和可读性,建议在一个项目中选择一种 API 并坚持使用。
|
||||||
|
|
||||||
|
|
||||||
|
- **以下是 Vue 3.0 中的 Composition API 函数的基本说明,以及与 Options API 的对比**
|
||||||
|
|
||||||
|
| Composition API | 说明 | 对应的 Options API |
|
||||||
|
| --------------- | ---- | ------------------ |
|
||||||
|
| `setup` | `setup` 是一个新引入的组件选项,用于使用 Composition API。它是组件内部使用 Composition API 的入口。| 无 |
|
||||||
|
| `ref` | `ref` 函数用于创建一个响应式的数据。它接收一个参数,返回一个响应式的 Ref 对象。| `data` |
|
||||||
|
| `reactive` | `reactive` 函数用于创建一个响应式的对象。它接收一个普通对象,返回一个响应式的对象。| `data` |
|
||||||
|
| `computed` | `computed` 函数用于创建一个计算属性。它接收一个 getter 函数或者一个具有 getter 和 setter 的对象,返回一个响应式的 Ref 对象。| `computed` |
|
||||||
|
| `watch` | `watch` 函数用于响应式地跟踪和触发副作用。它接收一个响应式的源和一个执行副作用的回调函数。| `watch` |
|
||||||
|
| `watchEffect` | `watchEffect` 函数用于立即执行传入的一个函数,并响应式地追踪其依赖,并在其依赖变更时重新运行该函数。 | 无 |
|
||||||
|
| `onMounted` | `onMounted` 函数在组件被挂载时调用。它接收一个在组件挂载后执行的回调函数。 | `mounted` |
|
||||||
|
| `onUnmounted` | `onUnmounted` 函数在组件被卸载时调用。它接收一个在组件卸载后执行的回调函数。 | `beforeDestroy`/`unmounted` |
|
||||||
|
| `onUpdated` | `onUpdated` 在组件更新后调用。它接收一个在组件更新后执行的回调函数。| `updated` |
|
||||||
|
| `provide` | `provide` 函数用于在组件上定义一个可以被后代组件注入的值。它接收一个提供的键和值。 | 有,与 `provide/inject` 相似但是属性而不是函数 |
|
||||||
|
| `inject` | `inject` 函数用于在组件中注入一个由祖先组件提供的值。它接收一个注入的键。 | 有,但与 `provide/inject` 相似但是属性而不是函数 |
|
||||||
|
|
||||||
|
值得注意的是,虽然一些 Composition API 函数与 Options API 的某些选项有相似之处,但它们的工作方式和使用方式可能有所不同。在实际使用中,你需要根据具体的使用场景和需求选择合适的 API。
|
||||||
1075
frontend/vue3.0概要.md
Normal file
1075
frontend/vue3.0概要.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user