vue3 script setup + ts 实践

3,450 阅读1分钟

ts + setup

本文是对vue3.x 语法的实践,不会单独的介绍某个具体的 API 语法,详细语法请参考 vue官网;此次文章中使用的是 script setup + ts 的用法,个人比较喜欢的一种语法,感觉是 vue3 关于 ts 的终极实践。

顶层属性

任何在 script setup 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用; 但仅仅是使用,由于不是响应式数据,没有双向绑定,所以不会在页面上同步更新。

<template>
  <div>
    <h1>{{ hello }}</h1>
    <p>
      {{ count }}
      <button @click="handleClick">add</button>  
    </p>
  </div>
</template>

<script lang="ts" setup>
// 如果只是单类型,则 vue 会自动推到,不用加类型
let hello: string | undefined = "hello, vue";

// vue 根据后面的值,自动推导。
let count = 0;

function handleClick(): void {
  console.log(count);
  count++;
}
</script>

响应式数据

  • ref: 用来给 基本数据类型 绑定响应式数据,访问时需要通过 .value 的形式, tamplate 不需要 .value,会被解析。
  • reactive: 用来给 复杂数据类型 绑定响应式数据,直接访问即可。
<template>
  <div>
    <h1>{{ title }}</h1>
    <p>
      当前等级:{{ count }}
      <button @click="handleAdd">升级</button>  
    </p>

    <p>宠物:{{ userInfo.pet }}</p>
  </div>
</template>

<script lang="ts" setup>
import { ref, reactive } from "vue";

// 设置基本数据类型时,使用 ref
const title = ref<string>("响应式数据");

// 也可以根据设置的默认数据推导当前类型
let count = ref(0);

// 用户信息 --- reactive 用来绑定复杂数据类型
interface IUserInfo {
  name: string,
  pet: string | undefined,
  level: number
}
const userInfo = reactive<IUserInfo>({
  name: "zs",
  level: 0,
  pet: undefined,
})

// 升级
function handleAdd(): void {
  count.value++;

  // 复杂数据类型,不需要通过 .value 的形式获取数据
  userInfo.level = count.value;
  userInfo.pet = count.value >= 5 ? '马' : undefined; // 达到 5 级 解锁宠物
}
</script>

使用 watch 优化上面的例子

  1. vue 中结构 watch;
  2. watch 是一个函数,可以一次写多个,也可以一次性监听多个例子;
<template>
  <div>
    <h1>{{ title }}</h1>
    <p>
      当前等级:{{ count }}
      <button @click="handleAdd">升级</button>  
    </p>

    <p>宠物:{{ userInfo.pet }}</p>
  </div>
</template>

<script lang="ts" setup>
import { ref, reactive, watch } from "vue";

// 设置基本数据类型时,使用 ref
const title = ref<string>("响应式数据");

// 也可以根据设置的默认数据推导当前类型
let count = ref(0);

// 用户信息 --- reactive 用来绑定复杂数据类型
interface IUserInfo {
  name: string,
  pet: string | undefined,
  level: number
}
const userInfo = reactive<IUserInfo>({
  name: "zs",
  level: 0,
  pet: undefined,
})

// 使用 watch 监听 count 的变化
watch(count, (nl, od) => {
  if (nl >= 5) {
  userInfo.level = count.value;
  userInfo.pet = count.value >= 5 ? '马' : undefined; // 达到 5 级 解锁宠物
  }
})

// 升级
function handleAdd(): void {
  count.value++;
}
</script>

使用 computed

<template>
  <div>
    <h1>{{ title }}</h1>
    <p>
      当前等级:{{ count }}
      <button @click="handleAdd">升级</button>  
    </p>

    <p>宠物:{{ userInfo.pet }}</p>

    <p>{{ showAddictionPrevention }}</p>
  </div>
</template>

<script lang="ts" setup>
import { ref, reactive, watch, computed } from "vue";

// 设置基本数据类型时,使用 ref
const title = ref<string>("响应式数据");

// 也可以根据设置的默认数据推导当前类型
let count = ref(0);

// 用户信息 --- reactive 用来绑定复杂数据类型
interface IUserInfo {
  name: string,
  pet: string | undefined,
  level: number
}
const userInfo = reactive<IUserInfo>({
  name: "zs",
  level: 0,
  pet: undefined,
})

// 是否显示防沉迷
const showAddictionPrevention = computed(() => {
  if (count.value === 0) return "Welcome";
  if (count.value >= 5) return "登录时间过长";
  return '';
})

// watch: 监听一个属性;
watch(count, (nl, od) => {
  if (nl >= 5) {
    userInfo.level = count.value;
    userInfo.pet = count.value >= 5 ? '马' : undefined; // 达到 5 级 解锁宠物
  }
})

// 升级
function handleAdd(): void {
  count.value++;
}
</script>

使用生命周期

生命周期方法vue 结构后,它是一个函数,传入 callback 后即可执行。

<template>
  <div>
    <h1>{{ title }}</h1>
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted } from "vue";

// 设置基本数据类型时,使用 ref
const title = ref<string>("Props And Emits");

onMounted(() => {
  console.log("加载完成...");
});
</script>

props and emit

这是基于 ts 的写法,所以按照泛型的形式传入,如果不是 ts ,可以按照 vue 的语法进行实现。

<!-- Father.vue -->
<template>
  <div>
    <h1>{{ title }}</h1>
    <Child :count="count" @change="handleChange"/>
  </div>
</template>

<script lang="ts" setup>
import { ref, } from "vue";
// 子组件不需要注册,可以直接使用
import Child from "./Child.vue";

// 设置基本数据类型时,使用 ref
const title = ref<string>("Props And Emits");
const count = ref<number>(1);

function handleChange(val: number):void {
  count.value = val;
}
</script>

<!-- Child.vue -->
<template>
  <div>
    <h2>Child</h2>
    <p>{{ props.count }}</p>
    <button @click="handleAdd">add</button>
  </div>
</template>


<script lang="ts" setup>
import { defineProps, defineEmits } from "vue";

// 使用 
interface IProps {
  count: number
}
const props = defineProps<IProps>();

const emit = defineEmits<{
  (event: 'change', total: number): void
}>()


function handleAdd(): void {
  emit("change", props.count + 1);
}
</script>