2024-08-23

泛型是TypeScript的一个核心特性,它允许在写函数、接口或类的时候,不预先指定其类型,而是在使用的时候再去指定。这样可以编写更加通用和灵活的代码。

以下是一个使用泛型的简单例子:




function identity<T>(arg: T): T {
    return arg;
}
 
let output = identity<string>("myString");  // output 类型为 string
let output2 = identity("myString");          // 类型推断

在这个例子中,identity 函数被定义为泛型函数,其中 T 是一个类型变量。当我们调用 identity<string> 时,T 被指定为 string 类型。

泛型接口和泛型类的定义也类似:




interface GenericIdentityFn<T> {
    (arg: T): T;
}
 
class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}
 
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

在这个例子中,GenericIdentityFn 是一个泛型接口,而 GenericNumber 是一个泛型类。创建 GenericNumber 类的实例时,需要指定一个类型参数来代替 T

泛型的一个常见用途是创建可复用的数据结构。泛型集合类型如 Array<T>Dictionary<T> 可以用于创建具有任何类型项的数组或字典:




let list: Array<number> = [1, 2, 3];
 
let dict: { [key: string]: number } = {
    "key1": 1,
    "key2": 2,
};

泛型也可以用于定义函数类型,如下所示:




let myGenericFunction: <T>(arg: T) => T = function<T>(arg: T): T {
    return arg;
}

泛型是TypeScript中一个强大而灵活的特性,可以帮助开发者编写更加清晰和可重用的代码。

2024-08-23

在Vite项目中配置环境变量,你可以使用.env文件来设置环境变量。Vite支持加载项目根目录下的.env文件中的变量,以及根据NODE_ENV的值加载.env.local.env.development.env.production等文件。

  1. 在项目根目录下创建.env文件。
  2. .env文件中添加环境变量,例如:



VITE_API_URL=https://api.example.com
  1. 在代码中通过import.meta.env访问环境变量,例如:



console.log(import.meta.env.VITE_API_URL); // 输出:https://api.example.com

对于开发环境和生产环境有不同的环境变量配置,你可以创建.env.development.env.production文件来分别设置。

如果你需要在代码中根据不同环境动态设置环境变量,可以使用import.meta.env.MODE来判断当前的环境,然后导入相应的配置文件。




const env = process.env.NODE_ENV;
 
// 根据不同的环境导入不同的配置文件
if (env === 'development') {
  import devConfig from './config.dev';
} else if (env === 'production') {
  import prodConfig from './config.prod';
}

请注意,.env文件中的变量名不能以VITE_开头,除非你想覆盖Vite的预设变量。

2024-08-23

在Vue 3 + TypeScript 项目中,你可以使用 vue-router 来传递参数。query 用于传递可选的查询参数,而 params 通常用于传递必须的路由参数,这取决于你的路由配置。

以下是如何使用 queryparams 的例子:

首先,确保你已经安装并设置了 vue-router

  1. 定义路由:



// router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
 
const routes: Array<RouteRecordRaw> = [
  {
    path: '/user/:id',
    name: 'User',
    component: () => import('@/components/User.vue'),
  },
  // 其他路由...
];
 
const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
});
 
export default router;
  1. 使用 query 传参:



// 在组件中
import { useRouter } from 'vue-router';
 
export default defineComponent({
  setup() {
    const router = useRouter();
 
    function goToUserPage() {
      router.push({ name: 'User', query: { plan: 'premium' } });
    }
 
    return { goToUserPage };
  },
});
  1. 使用 params 传参:



// 在组件中
import { useRouter } from 'vue-router';
 
export default defineComponent({
  setup() {
    const router = useRouter();
 
    function goToUserPage() {
      router.push({ name: 'User', params: { id: '1234' } });
    }
 
    return { goToUserPage };
  },
});

注意:当使用 params 时,你需要在路由定义中指定参数的占位符(例如 /user/:id),这样才能在路由正确地使用它。使用 query 不需要在路由中预定义参数。

2024-08-23

在TypeScript中设置环境并进行代码调试,通常需要以下步骤:

  1. 安装Node.js和npm。
  2. 使用npm安装TypeScript编译器:

    
    
    
    npm install -g typescript
  3. 初始化一个新的npm项目(如果你的项目还没有):

    
    
    
    npm init -y
  4. 安装TypeScript本地依赖:

    
    
    
    npm install --save-dev typescript
  5. 创建一个tsconfig.json文件,该文件定义了TypeScript编译选项:

    
    
    
    tsc --init
  6. 编写你的TypeScript文件,比如index.ts
  7. 使用tsc编译器编译TypeScript文件:

    
    
    
    tsc

    或者使用tsc的监听模式,它会在你保存文件时自动编译:

    
    
    
    tsc --watch
  8. 安装Node.js的调试器:

    
    
    
    npm install --save-dev node-inspector
  9. 启动node-inspector服务:

    
    
    
    node-inspector
  10. 启动Node.js的调试模式,并连接到node-inspector:

    
    
    
    node --inspect-brk ./node_modules/.bin/ts-node index.ts

    或者如果你已经编译了JavaScript文件:

    
    
    
    node --inspect-brk index.js

现在你可以在浏览器中打开 http://127.0.0.1:8080/(node-inspector的默认Web界面)并开始调试。

2024-08-23

在TypeScript中,模块是一种将变量、函数等代码组织在一起的方式,以避免全局变量冲突。TypeScript支持两种模块:CommonJS和ES6模块。

  1. CommonJS模块:

在CommonJS模块中,exports对象用于导出模块成员,require函数用于导入其他模块。




// math.ts
let sum = (a: number, b: number) => {
    return a + b;
}
 
export { sum };
 
// app.ts
let { sum } = require('./math');
console.log(sum(1, 2));  // 输出:3
  1. ES6模块:

在ES6模块中,使用import和export语法导入和导出模块。




// math.ts
export let sum = (a: number, b: number) => {
    return a + b;
}
 
// app.ts
import { sum } from './math';
console.log(sum(1, 2));  // 输出:3

注意:在使用ES6模块时,确保在tsconfig.json文件中设置"module": "ESNext",以便TypeScript能够正确地编译ES6模块语法。




{
  "compilerOptions": {
    "module": "ESNext"
    // ...其他配置
  }
}

以上是TypeScript中模块的基本使用方法。

2024-08-23

在Vue 3 + TypeScript + Vite项目中实现图片移动,可以使用Vue的内置指令v-for结合v-draggable指令来实现。这里假设你已经实现了v-draggable指令。

首先,确保你已经安装并设置好了Vite与必要的Vue插件。

然后,创建一个Vue组件,例如ImageList.vue




<template>
  <div>
    <div
      v-for="(image, index) in images"
      :key="index"
      class="draggable-item"
      v-draggable
      @dragstart="dragStart(index)"
      @dragend="dragEnd"
      @dragover.prevent
      @drop="dragDrop(index)"
      :style="{ backgroundImage: `url(${image})` }"
    ></div>
  </div>
</template>
 
<script lang="ts">
import { defineComponent, reactive, toRefs } from 'vue';
 
export default defineComponent({
  setup() {
    const state = reactive({
      images: [
        'image1.jpg',
        'image2.jpg',
        // ... 更多图片路径
      ],
      draggedItem: null,
      draggedOverItem: null,
    });
 
    const dragStart = (index: number) => {
      state.draggedItem = index;
    };
 
    const dragEnd = () => {
      state.draggedItem = null;
      state.draggedOverItem = null;
    };
 
    const dragDrop = (index: number) => {
      if (state.draggedItem !== null && state.draggedOverItem !== index) {
        const temp = state.images[state.draggedItem];
        state.images.splice(state.draggedItem, 1);
        state.images.splice(index, 0, temp);
      }
      state.draggedOverItem = index;
    };
 
    return { ...toRefs(state), dragStart, dragEnd, dragDrop };
  },
});
</script>
 
<style scoped>
.draggable-item {
  width: 100px;
  height: 100px;
  margin: 10px;
  background-size: cover;
  border: 1px solid #000;
  cursor: move;
}
</style>

在这个组件中,images数组包含了所有待排序的图片路径。draggable-item类定义了图片展示的样式,并且应用了自定义指令v-draggabledragStartdragEnddragDrop方法用于处理拖拽事件,更新images数组的顺序。

请确保你已经定义了v-draggable指令的实现,这通常涉及监听dragoverdrop事件来调整列表的顺序。

这个组件可以被添加到Vue应用的任何地方,以提供图片移动的功能。

2024-08-23



// 定义一个枚举类型,表示不同的日志等级
enum LogLevel {
  DEBUG = "DEBUG",
  INFO = "INFO",
  WARNING = "WARNING",
  ERROR = "ERROR"
}
 
// 使用枚举来确保日志函数接收合法的等级
function log(message: string, level: LogLevel) {
  switch (level) {
    case LogLevel.DEBUG:
      console.log(`[DEBUG] ${message}`);
      break;
    case LogLevel.INFO:
      console.log(`[INFO] ${message}`);
      break;
    case LogLevel.WARNING:
      console.log(`[WARNING] ${message}`);
      break;
    case LogLevel.ERROR:
      console.error(`[ERROR] ${message}`);
      break;
    default:
      console.log(message);
      break;
  }
}
 
// 使用枚举来记录不同类型的事件
enum EventType {
  CLICK = "click",
  SUBMIT = "submit",
  RESIZE = "resize"
}
 
// 假设有一个函数用来监听不同的事件
function listenToEvent(eventType: EventType) {
  switch (eventType) {
    case EventType.CLICK:
      document.addEventListener('click', () => console.log('Click event triggered'));
      break;
    case EventType.SUBMIT:
      document.addEventListener('submit', (event) => console.log('Submit event triggered', event));
      break;
    case EventType.RESIZE:
      window.addEventListener('resize', () => console.log('Resize event triggered'));
      break;
    // 默认处理其他事件
    default:
      console.log(`Listening to event: ${eventType}`);
      break;
  }
}
 
// 测试枚举的使用
log("Hello, world!", LogLevel.INFO);
listenToEvent(EventType.CLICK);

这段代码展示了如何在TypeScript中使用枚举类型来增强代码的可读性和健壮性。枚举提供了一种有效的方法来定义在程序中使用的常量集合,这有助于确保在程序的不同部分中使用的值是预定义且具有特殊含义的。在这个例子中,log函数通过接收一个枚举作为参数,来确保输入的日志等级是预定义的值之一,从而避免了可能的错误。同时,listenToEvent函数通过使用枚举来避免硬编码字符串,从而使代码更加清晰和易于维护。

2024-08-23

在 Vue 3 和 TypeScript 的环境下,你可以通过组合式 API 的 onMountedonUnmounted 生命周期钩子函数来监听页面滚动事件,并通过 ref 来获取子组件的引用,然后调用子组件的方法。以下是一个简单的示例:




<template>
  <ChildComponent ref="child" />
</template>
 
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
 
const child = ref<InstanceType<typeof ChildComponent>>();
 
const handleScroll = () => {
  if (window.scrollY > 100) {
    child.value?.setStyle(); // 调用子组件的 setStyle 方法
  }
};
 
onMounted(() => {
  window.addEventListener('scroll', handleScroll);
});
 
onUnmounted(() => {
  window.removeEventListener('scroll', handleScroll);
});
</script>

在这个例子中,我们首先导入了子组件 ChildComponent,并使用 ref 创建了一个引用 child。在 onMounted 钩子中,我们添加了一个滚动事件监听器,它会在用户滚动页面时调用 handleScroll 函数。在 handleScroll 函数中,我们检查了页面的滚动位置,并且如果滚动超过了 100 像素,我们通过 child.value?.setStyle() 调用了子组件的 setStyle 方法。最后,在 onUnmounted 钩子中移除了滚动事件监听器,避免在组件卸载后发生内存泄露。

确保子组件 ChildComponent 有一个 setStyle 方法供你调用。如果子组件是由单文件组件定义的,那么它应该有一个导出的方法 setStyle。如果子组件是通过 script setup 定义的,那么你可以直接在子组件内部定义方法,并在父组件中通过 ref 调用。

2024-08-23

在 TypeScript 中,enum 是用来定义一组命名常量的数据类型。这些常量可以用来表示一组有限的值,使得代码更具可读性和可维护性。

下面是一个简单的 enum 使用示例:




enum Color {
  Red,
  Green,
  Blue
}
 
function printColor(color: Color) {
  switch (color) {
    case Color.Red:
      console.log('Red');
      break;
    case Color.Green:
      console.log('Green');
      break;
    case Color.Blue:
      console.log('Blue');
      break;
    default:
      console.log('Unknown color');
      break;
  }
}
 
printColor(Color.Red); // 输出: Red
printColor(Color.Green); // 输出: Green
printColor(Color.Blue); // 输出: Blue

在这个例子中,我们定义了一个名为 Colorenum,它包含三个成员:RedGreenBlue。然后我们定义了一个 printColor 函数,它接受一个 Color 类型的参数,并根据传入的参数在控制台输出对应的颜色名称。

enum 成员的默认值是从 0 开始的整数,你也可以手动为每个成员赋予一个初始值:




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

在这种情况下,Red 的值为 1,Green 的值为 2,Blue 的值为 3。

你还可以使用 enum 来创建更具有表达性的代码,使得代码更易于理解,尤其是在处理像颜色、方向、状态等有限的固定值时。

2024-08-23



// 定义一个函数,接收一个字符串参数,并返回一个对象
// 对象中包含字符串的常见操作的结果
function performStringOperations(input: string): { [key: string]: any } {
    return {
        // substring(start, end) 方法用于提取字符串的一部分,并返回新的子字符串
        subString: input.substring(1, 4),
 
        // indexOf(searchValue, fromIndex) 方法返回指定值在字符串中首次出现的索引位置
        indexOfA: input.indexOf('A', 2),
 
        // slice(start, end) 方法提取字符串的一部分,并返回新的子字符串
        slicedString: input.slice(2, 5),
 
        // replace(regexp/substr, newSubstr|function) 方法返回一个新的字符串,
        // 其中出现的匹配原字符串中的一些或所有匹配都被替换了
        replacedString: input.replace(/A/g, 'B')
    };
}
 
// 测试函数
const testString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const result = performStringOperations(testString);
 
console.log(result);

这段代码定义了一个performStringOperations函数,它接收一个字符串作为参数,并返回一个对象,该对象包含了字符串的substringindexOfslicereplace操作的结果。然后,我们创建了一个测试字符串并调用了该函数,打印出返回的结果对象。这个例子展示了如何在TypeScript中使用字符串操作方法,并且提供了一个简单的参考实现。