首页 > 其他分享 >Vue3 + TypeScript:从环境搭建到组件通信的完整前端开发教程

Vue3 + TypeScript:从环境搭建到组件通信的完整前端开发教程

时间:2024-10-21 15:46:25浏览次数:3  
标签:vue const number TypeScript Vue3 类型 import 前端开发

在前端开发领域,Vue3 与 TypeScript 的组合备受青睐。Vue3 带来高效灵活的开发体验,TypeScript 则提供强大的类型安全和可维护性。本文将详细介绍如何使用 Vue3 和 TypeScript 进行开发,文章内容将按照以下顺序展开:

一、环境准备

1.安装 Node.js:

2.创建 Vue 项目:

  • 使用 Vue CLI 创建新的 Vue3 项目,并选择 TypeScript 作为语言选项。在终端执行以下命令:
     npm install -g @vue/cli
     vue create my-vue3-ts-project
  • 创建项目时,选择 “Manually select features”,然后勾选 “TypeScript” 选项。

二、项目结构

典型的 Vue3 + TypeScript 项目结构如下:

my-vue3-ts-project/
├── node_modules/
├── public/
│   ├── favicon.ico
│   └── index.html
├── src/
│   ├── assets/
│   ├── components/
│   ├── composables/
│   ├── router/
│   ├── store/
│   ├── types/
│   ├── views/
│   ├── App.vue
│   └── main.ts
├──.browserslistrc
├──.eslintrc.js
├──.gitignore
├── babel.config.js
├── package-lock.json
├── package.json
├── README.md
└── tsconfig.json

三、TypeScript 的类型系统详解及基本语法和高级语法介绍

TypeScript 是一种强类型的编程语言,它的类型系统和语法为开发者提供了强大的工具来确保代码的正确性和可维护性。

(一)基本类型

包括booleannumberstringnullundefinedsymbol

   let isDone: boolean = false;
   let decimal: number = 6;
   let name: string = "Alice";
   let u: undefined = undefined;
   let n: null = null;
   let sym: symbol = Symbol();

(二)数组类型

可用类型加方括号或泛型数组类型表示。

   let list: number[] = [1, 2, 3];
   let list: Array<number> = [1, 2, 3];

(三)元组类型

表示已知元素数量和类型的数组,各元素类型不必相同。

   let tuple: [string, number];
   tuple = ["hello", 42];

(四)枚举类型

定义一组命名常量,成员值可默认递增或手动指定。

   enum Color {
     Red,
     Green,
     Blue,
   }

   let c: Color = Color.Green;

   enum Color {
     Red = 1,
     Green = 2,
     Blue = 4,
   }

(五)函数类型

指定参数和返回值类型,也可用类型别名定义函数类型。

   function add(a: number, b: number): number {
     return a + b;
   }

   type AddFunction = (a: number, b: number) => number;
   let addFunc: AddFunction = add;

(六)对象类型

用接口或类型别名定义。

   interface Person {
     name: string;
     age: number;
   }

   let person: Person = {
     name: "Alice",
     age: 30,
   };

   type Person = {
     name: string;
     age: number;
   };

   let person: Person = {
     name: "Alice",
     age: 30,
   };

(七)可选属性和只读属性

?表示可选属性,readonly表示只读属性。

   interface Person {
     name: string;
     age?: number;
     readonly id: number;
   }

(八)联合类型和交叉类型

联合类型表示值可为多种类型之一,交叉类型将多个类型合并为一个。

   let value: string | number;
   value = "hello";
   value = 42;

   interface A {
     a: number;
   }

   interface B {
     b: string;
   }

   type C = A & B;

   let c: C = { a: 1, b: "hello" };

(九)类型断言

当比 TypeScript 更了解值的类型时,可使用类型断言告诉编译器具体类型。

   let someValue: any = "hello";
   let strLength: number = (someValue as string).length;
   let strLength: number = (<string>someValue).length;

(十)类型推断

TypeScript 可根据上下文自动推断变量类型。

   let x = 3; // 推断 x 的类型为 number

   function add(a, b) {
     return a + b;
   }

   let result = add(1, 2); // 推断 result 的类型为 number

(十一)高级类型操作

包括索引类型、映射类型和条件类型。

   interface Person {
     name: string;
     age: number;
   }

   type PersonKeys = keyof Person; // "name" | "age"

   type ReadonlyPerson = { readonly [K in keyof Person]: Person[K] };

   type IsString<T> = T extends string? "yes" : "no";

   type Result = IsString<string>; // "yes"
   type Result2 = IsString<number>; // "no"

高级语法补充:

(十二)装饰器(Decorators)

TypeScript 支持装饰器语法,可添加到类、方法、属性或参数上以修改行为或添加功能。

   function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
     const originalMethod = descriptor.value;

     descriptor.value = function (...args: any[]) {
       console.log(`Calling method ${propertyKey} with arguments: ${JSON.stringify(args)}`);
       const result = originalMethod.apply(this, args);
       console.log(`Method ${propertyKey} returned: ${JSON.stringify(result)}`);
       return result;
     };

     return descriptor;
   }

   class MyClass {
     @log
     myMethod(arg1: number, arg2: string): string {
       return `Result: ${arg1} and ${arg2}`;
     }
   }

   const instance = new MyClass();
   instance.myMethod(10, "hello");

四、Vue3 的新特性

1.Composition API

  • 允许将相关逻辑组合在一起,提高代码可维护性和复用性。
   import { ref, onMounted } from 'vue';

   export default {
     setup() {
       const count = ref(0);

       const increment = () => {
         count.value++;
       };

       onMounted(() => {
         console.log('Component mounted');
       });

       return {
         count,
         increment,
       };
     },
   };

2.Teleport

  • 可将组件模板内容渲染到指定 DOM 节点。
   <template>
     <Teleport to="#modal">
       <div>Modal content</div>
     </Teleport>
   </template>

3.Suspense

  • 在异步组件加载时显示加载状态,提升用户体验。
   <template>
     <Suspense>
       <template #default>
         <AsyncComponent />
       </template>
       <template #fallback>
         Loading...
       </template>
     </Suspense>
   </template>

五、TypeScript 与 Vue3 的结合

1.类型声明

  • 增强代码类型安全。
   import { defineComponent } from 'vue';

   interface Props {
     message: string;
   }

   export default defineComponent({
     props: {
       message: {
         type: String,
         required: true,
       },
     },
   });

2.函数和方法的类型声明

  • 确保参数和返回值类型正确。
   import { defineComponent } from 'vue';

   export default defineComponent({
     setup() {
       const addNumbers = (a: number, b: number): number => {
         return a + b;
       };

       return {
         addNumbers,
       };
     },
   });

3.类型推断

  • 根据上下文自动推断变量类型。
   import { ref } from 'vue';

   const count = ref(0);
   // TypeScript 可推断出 count 的类型为 Ref<number>

六、路由和状态管理

1.Vue Router with TypeScript

  • 安装vue-router@types/vue-router
   npm install vue-router @types/vue-router

  • 创建路由模块并定义路由。在项目中创建一个新的文件,例如router/index.ts,用于定义路由:
   import { createRouter, createWebHistory } from 'vue-router';
   import Home from '../views/Home.vue';
   import About from '../views/About.vue';

   const routes = [
     {
       path: '/',
       name: 'Home',
       component: Home,
     },
     {
       path: '/about',
       name: 'About',
       component: About,
     },
   ];

   const router = createRouter({
     history: createWebHistory(),
     routes,
   });

   export default router;

在上述代码中,导入了createRoutercreateWebHistory函数,分别用于创建路由实例和使用 HTML5 历史模式的路由历史。然后定义了两个路由,分别指向HomeAbout组件。最后,创建路由实例并导出。

  • 确保你的组件文件(如Home.vueAbout.vue)存在于项目的views目录下或者相应的位置。

2.Vuex with TypeScript

  • 安装vuex@types/vuex
   npm install vuex @types/vuex
  • 创建 store 模块并定义状态和 mutations。
   import { createStore } from 'vuex';

   interface State {
     count: number;
   }

   const store = createStore<State>({
     state: {
       count: 0,
     },
     mutations: {
       increment(state) {
         state.count++;
       },
     },
   });

   export default store;

  • Vuex 的模块化管理(知识点补充)
  • 创建模块。
     import { Module } from 'vuex';

     interface ModuleState {
       moduleCounter: number;
     }

     const module: Module<ModuleState, any> = {
       namespaced: true,
       state: {
         moduleCounter: 0,
       },
       mutations: {
         incrementModuleCounter(state) {
           state.moduleCounter++;
         },
       },
       actions: {
         incrementModuleCounterAsync({ commit }) {
           setTimeout(() => {
             commit('incrementModuleCounter');
           }, 1500);
         },
       },
       getters: {
         doubleModuleCounter(state): number {
           return state.moduleCounter * 2;
         },
       },
     };

     export default module;

  • 在 store 中引入模块。
     import { createStore } from 'vuex';
     import module from './module';

     interface RootState {
       counter: number;
     }

     const store = createStore<RootState>({
       state: {
         counter: 0,
       },
       mutations: {
         increment(state) {
           state.counter++;
         },
         decrement(state) {
           state.counter--;
         },
       },
       actions: {
         incrementAsync({ commit }) {
           setTimeout(() => {
             commit('increment');
           }, 1000);
         },
       },
       getters: {
         doubleCounter(state): number {
           return state.counter * 2;
         },
       },
       modules: {
         moduleName: module,
       },
     });

     export default store;

  • 在组件中访问模块状态。
     <template>
       <div>
         <p>Counter: {{ counter }}</p>
         <button @click="increment">Increment</button>
         <button @click="decrement">Decrement</button>
         <button @click="incrementAsync">Increment Async</button>
         <p>Double Counter: {{ doubleCounter }}</p>
         <p>Module Counter: {{ moduleCounter }}</p>
         <button @click="incrementModuleCounter">Increment Module Counter</button>
         <button @click="incrementModuleCounterAsync">Increment Module Counter Async</button>
         <p>Double Module Counter: {{ doubleModuleCounter }}</p>
       </div>
     </template>

     <script lang="ts">
     import { defineComponent, computed } from 'vue';
     import { useStore } from 'vuex';

     export default defineComponent({
       setup() {
         const store = useStore();

         const counter = computed(() => store.state.counter);
         const doubleCounter = computed(() => store.getters.doubleCounter);

         const increment = () => store.commit('increment');
         const decrement = () => store.commit('decrement');
         const incrementAsync = () => store.dispatch('incrementAsync');

         const moduleCounter = computed(() => store.state.moduleName.moduleCounter);
         const doubleModuleCounter = computed(() => store.getters['moduleName/doubleModuleCounter']);

         const incrementModuleCounter = () => store.commit('moduleName/incrementModuleCounter');
         const incrementModuleCounterAsync = () => store.dispatch('moduleName/incrementModuleCounterAsync');

         return {
           counter,
           doubleCounter,
           increment,
           decrement,
           incrementAsync,
           moduleCounter,
           doubleModuleCounter,
           incrementModuleCounter,
           incrementModuleCounterAsync,
         };
       },
     });
     </script>

七、组件通信

在 Vue3 + TypeScript 项目中,组件通信是构建复杂应用的关键部分。以下介绍两种主要的组件通信方式:Props 和 Emits 以及 Provide / Inject。

(一)Props 和 Emits

  • 定义和使用 Props:Props 用于父组件向子组件传递数据。在子组件中,可以使用defineProps来明确地定义接收的 props。defineProps是一个在setup函数内部使用的函数,它接收一个参数,用于描述 props 的类型和约束。
   import { defineComponent, defineProps } from 'vue';

   const ChildComponent = defineComponent({
     setup(props) {
       // 使用 defineProps 定义接收的 props
       const { message } = defineProps({
         message: {
           type: String,
           required: true,
         },
       });
       // 在这里可以使用 props.message
       return {
         receivedMessage: message,
       };
     },
   });

   export default ChildComponent;
  • 在父组件中,可以像这样向子组件传递 prop:
   <template>
     <ChildComponent :message="parentMessage" />
   </template>

   <script lang="ts">
   import { defineComponent } from 'vue';
   import ChildComponent from './ChildComponent.vue';

   export default defineComponent({
     components: {
       ChildComponent,
     },
     data() {
       return {
         parentMessage: 'Hello from parent',
       };
     },
   });
   </script>
  • 定义和触发 Emits:Emits 用于子组件向父组件发送自定义事件。在子组件中,可以使用defineEmits来定义可触发的事件。
   import { defineComponent, defineEmits } from 'vue';

   const ChildComponent = defineComponent({
     emits: ['customEvent'],
     setup(props, { emit }) {
       const handleClick = () => {
         emit('customEvent', 'Hello from child component');
       };

       return {
         handleClick,
       };
     },
   });

   export default ChildComponent;
  • 在父组件中,可以监听子组件触发的事件:
   <template>
     <ChildComponent @customEvent="handleChildEvent" />
   </template>

   <script lang="ts">
   import { defineComponent } from 'vue';
   import ChildComponent from './ChildComponent.vue';

   export default defineComponent({
     components: {
       ChildComponent,
     },
     methods: {
       handleChildEvent(message) {
         console.log(message);
       },
     },
   });

(二)Provide / Inject

  • 使用 Provide 提供数据:在父组件中,可以使用provide函数来提供数据,这些数据可以在后代组件中通过inject获取。
   import { provide } from 'vue';

   const ParentComponent = defineComponent({
     setup() {
       provide('message', 'Hello from parent component');
     },
   });

   export default ParentComponent;
  • 使用 Inject 获取数据:在子组件中,可以使用inject函数来获取父组件提供的数据。
   import { defineComponent, inject } from 'vue';

   const ChildComponent = defineComponent({
     setup() {
       const message = inject('message');
       return {
         receivedMessage: message,
       };
     },
   });

   export default ChildComponent;

通过以上两种方式,可以在 Vue3 + TypeScript 项目中实现组件之间的有效通信,根据不同的场景选择合适的通信方式可以使代码更加清晰和易于维护。

八、开发工具和调试

  1. Vue Devtools:安装浏览器扩展,便于开发过程中的检查和调试。
  2. TypeScript 支持:现代代码编辑器通常提供语法高亮、类型检查和自动补全等功能,确保编辑器配置正确以充分利用 TypeScript 的优势。

九、总结

Vue3 和 TypeScript 的组合带来诸多好处,如更好的类型安全、可维护性和开发效率。通过本文介绍,应初步了解如何使用 Vue3 和 TypeScript 进行开发。在实际项目中,可根据需求进一步探索和应用 Vue3 的更多特性及 TypeScript 的强大功能。

希望本教程对你有所帮助!如有问题或建议,欢迎在评论区留言。

标签:vue,const,number,TypeScript,Vue3,类型,import,前端开发
From: https://blog.csdn.net/weimengen/article/details/143110529

相关文章