OveUI博客
老前端的戎码生涯

Vite+Vue3.2+TS 相关API归纳总结

Vite+Vue3.2+TS 相关API归纳总结

前言

Vue3已经发布的有些日子了。目前也处于稳定发展阶段再加上官方文档目前也逐步更新了Vue3的技术文档,所以在22年之后各位打工仔也应该学习起来了,并且也会有许多开发团队选择Vue3+TS这一套体系,所以目前开始全面使用拥抱Vue3+TS。

在此之前呢,也只是简单的体验了一遍CompositionApi以及setup语法糖的写法。

接下来呢就是会去全面使用Vite + Vue3.2 + TS、setup语法糖的形式来学习并且记录相关写法,以便日后查阅 ,同时也会不断的更新记录

Vite项目快速搭建

一条命令即可快速搭建项目

npm create vite@latest

yarn create vite

pnpm create vite
复制代码

接下来就是介绍相关API的写法

常用响应式API介绍

ref

通常使用ref方法来声明一个基本数据类型响应式变量

<template>
     <div>ref变量:{{ count }}</div>
</template>

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

const count = ref<number>(5); // 类型是:Ref<number>
// 在script当中访问值的方式:
console.log(count.value)
</script>
复制代码

isRef

检查参数是否是Ref类型的,返回boolean值

unref

如果参数是一个Ref类型的,则返回内部值即 xx.value 否则返回参数本身。 实际就是 isRef(val) ? val.value : val 这样的判断而已。

toRef

可以为一个源响应式对象的某个属性去创建一个 ref 并且会保持源响应式对象上的属性 和 ref的响应式连接。

import { ref, reactive, toRef } from "vue";

const state = reactive({
    foo: 1,
    text: "我是reactive"
})

const toRefText = toRef(state, "text")
console.log("Old-Text", toRefText.value) // 我是reactive
state.text = "我是reactive-ToRef"
console.log("New-Text", toRefText.value) // 我是reactive-ToRef
复制代码

toRefs

将响应式对象解构为一个个Ref类型的响应式变量

import { reactive, toRefs } from "vue";

const state = reactive({
    foo: 1,
    text: "我是reactive"
})

const { foo, text } = toRefs(state)
// foo: Ref<number>
// text:Ref<string>
复制代码

reactive

创建一个响应式对象副本

import { reactive } from "vue";

interface IState {
    foo: number;
    text: string
}

const state = reactive<IState>({
    foo: 1,
    text: "我是reactive"
})
复制代码

readonly

接受一个响应式对象、普通对象或Ref 并且返回其只读代理

import { reactive, readonly } from "vue";

interface IState {
    foo: number;
    text: string
}

let state = reactive<IState>({
    foo: 1,
    text: "我是reactive"
})

const copy = readonly(state)
/**
 * copy:{ readonly foo: number; readonly text: string;}
 */
复制代码

computed

第一种: 接收一个getter函数,并且根据函数的返回值返回一个不可变的响应式ref对象

import { ref, computed } from "vue";

const count = ref<number>(5);

const computedCount1 = computed(() => {
    return count.value * 10
})
复制代码

第二种: 接收一个具有get 和set函数的对象,用来创建可写的ref对象

import { ref, computed } from "vue";

const count = ref<number>(5);

const computedCount2 = computed<number>({
    get() {
        return count.value + 1
    },
    set(val) {
        console.log("value", val)
        count.value = val + 5
    }
})
// 我们给计算属性computedCount2赋值时会执行set函数,访问使用computedCount2时会执行get函数
computedCount2.value = 5
复制代码

watchEffect

立即执行传入的函数,同时响应式的追踪函数内部其依赖,并在依赖发生变化时重新运行该函数。作用类似与监听器watch,不在过多介绍其写法了。

停止监听:watchEffect在组件的setup或生命周期当中被使用,在组件卸载时会自动停止。当然我们也可以手动停止监听,直接调用返回值来停止监听。

const stopEffect = watchEffect(()=>{
    // 相关代码
})

// 停止监听
stopEffect()
复制代码

注:3.2版本还新增了两个watchPostEffectwatchSyncEffect,但只是参数上的不同。具体使用细节还是得看文档呀~

watch

watch是惰性的-即回调只在监听源发生变化才会执行。说明监听源在初始赋值时是不会去执行的。

监听单源

const count = ref<number>(5);
const changeCountValue = () => {
    count.value = count.value + 5;
}
watch(() => count.value, (newVal, oldVal) => {
    console.log("newVal", newVal);
    console.log("oldVal:", oldVal);
})
复制代码

监听多源

第一个参数可以传入一个数组来同时监听对个源

watch([foo, bar], ([newFoo, newBar], [oldFoo, oldBar]) => {
  /* ... */
})
复制代码

组件通信-defineProps和defineEmits

Vue给我们提供了defineProps和defineEmits两个途径去定义props和emits。它们只在setup中才能使用的编译器宏,不需要我们导入可以直接写。

父组件向子组件传值Props

子组件定义Props的方法,withDefaults则是写Props的默认值

<template>
    <div>{{ text }}</div>
    <div>{{ totalValue }}</div>
</template>

<script setup lang='ts'>
interface IPropPrams {
    text: string;
    totalValue: number
}
/**
 * 提供的默认值
 */
withDefaults(defineProps<IPropPrams>(), {
    text: "2",
    totalValue: 6
})
</script>
复制代码

子组件向父组件传值或触发父组件时间Emits

<template>
    <div @click="triggerEmit">点击触发emits</div>
</template>

<script setup lang='ts'>
interface IEmitFun {
    (e: 'update:change', id: number): void
}

const emits = defineEmits<IEmitFun>()

const triggerEmit = () => {
    emits('update:change', 2)
}
</script>
复制代码

获取某组件实例-defineExpose

在使用setup语法糖时,组件是默认关闭,无法访问到组件的公开实例的。需要使用defineExpose在组件中定义需要被暴露出去的值或方法。

子组件暴露可访问的值或方法:

<script setup lang='ts'>
import { ref } from 'vue';

const exposeValue = ref(20)
const exposeFun = (data: number) => {
    console.log("defineProp", data)
}

defineExpose({
    val: exposeValue.value,
    fun: exposeFun
})
</script>
复制代码

父组件使用子组件暴露的值或方法

<template>
  <ChildCom
    ref="comp"
  ></ChildCom>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
const comp = ref<any>(null)

onMounted(() => {
  comp.value.fun(comp.value.val)
})
</script>
复制代码

注意:setup的代码会在每次组件被创建时执行,还无法获取到子组件实例。需要在mounted时调用

自定义指令的使用

自定义指令在进行DOM节点操作时显得格外的重要

// 注册
app.directive('my-directive', {
  // 指令具有一组生命周期钩子:
  // 在绑定元素的 attribute 或事件监听器被应用之前调用
  created() {},
  // 在绑定元素的父组件挂载之前调用
  beforeMount() {},
  // 在绑定元素的父组件挂载之后调用
  mounted() {},
  // 在包含组件的 VNode 更新之前调用
  beforeUpdate() {},
  // 在包含组件的 VNode 及其子组件的 VNode 更新之后调用
  updated() {},
  // 在绑定元素的父组件卸载之前调用
  beforeUnmount() {},
  // 在绑定元素的父组件卸载之后调用
  unmounted() {}
})
复制代码

下面有个copy文本到剪贴板的例子:

app.directive("copy", {
  beforeMount(el: HTMLButtonElement, binding) {
    el.textContent = binding.value;
    const copySuccess: any = binding.arg;

    el.addEventListener("click", () => {
      if (!el.textContent) return console.log("没有需要复制的内容");

      // 创建textarea标签
      const textarea = document.createElement("textarea");
      // 设置标签的相关属性
      //   textarea.style.position = "fixed";
      textarea.style.top = "-999999px";
      // 将目标内容复制个textarea标签
      textarea.value = el.textContent;
      // 插入到页面中
      document.body.appendChild(textarea);
      // 调用onselect方法a
      textarea.select();
      // 把目标内容复制进剪贴板, 该API会返回一个Boolean
      const res = document.execCommand("Copy");
      res && copySuccess
        ? copySuccess(el.textContent)
        : console.log("复制成功,剪贴板内容:" + el.textContent);
      // 移除textarea标签
      document.body.removeChild(textarea);
    });
  },
  updated(el, binding) {
    // 实时更新最新的目标内容
    el.textContent = binding.value;
  },
  unmounted(el) {
    el.removeEventListener("click", () => {});
  },
});
复制代码

使用方式:

<template>
  <button v-copy:[copySuccess]="'点击复制'">点击复制</button>
</template>

<script setup lang="ts">
const copySuccess = (value: string) => {
  console.log("copy的值为:", value);
}
</script>
复制代码

插槽的使用

匿名插槽

子组件:

<template>
    <div>
        <slot>默认内容</slot>
    </div>
</template>
复制代码

父组件:

<template>
  <SlotUse>匿名插槽</SlotUse>
</template>
复制代码

匿名插槽

  • 写法:v-slot:name, 简写:#name

子组件:

<template>
    <div>
        <header>
            <slot name="header">默认头部</slot>
        </header>
        <main>
            <slot>默认内容</slot>
        </main>
        <footer>
            <slot name="footer">默认底部</slot>
        </footer>
    </div>
</template>
复制代码

父组件:

<template>
    <!-- 写法:v-slot:name、简写:#name -->
    <template v-slot:header>头部内容</template>
    插槽内容
    <template #footer>底部内容</template>
  </SlotUse>
</template>
复制代码

作用域插槽

作用域插槽的作用是:可以将子组件的数据通过插槽的方式传给父组件,提供给插槽内容使用

子组件:

<template>
    <div>
        <ul>
            <li v-for="(item, index) in todoList" :key="index">
                <!-- 是已通过Props的形式传出去 -->
                <slot :item="item" :index="index"></slot>
            </li>
        </ul>
    </div>
</template>

<script setup lang='ts'>
import { ref } from 'vue';
const todoList = ref(['Feed a cat', 'Buy milk'])
</script>
复制代码

父组件:

<template>
  <SlotUse>
    <template #default="slotProps">
      <span>{{ slotProps.index }}:{{ slotProps.item }}</span>
    </template>
  </SlotUse>
</template>

// 当组件当中只定义了默认插槽时 可以简写如下方式:
// 组件中如果还包含了匿名插槽时 则需要上面这种方式
<template>
  <SlotUse v-slot="slotProps">
    <span>{{ slotProps.index }}:{{ slotProps.item }}</span>
  </SlotUse>
</template>

// 同时还支持解构插槽Prop
<template>
  <SlotUse>
    <template #default="{ item, index }">
      <span>{{ index }}:{{ item }}</span>
    </template>
  </SlotUse>
</template>

<template>
    <SlotUse v-slot="{ item, index }">
      <span>{{ index }}:{{ item }}</span>
    </SlotUse>
</template>
复制代码

绑定在 <slot> 元素上的 attribute 被称为插槽 prop。而在父级作用域中,可以使用带值的 v-slot 来定义提供的插槽 prop 的名字。

Provide 和 Inject

一个组件如果嵌套了多层子组件,那么互相传递props会显得相当麻烦。这时候可考虑使用Provide和Inject来传递值给更深层的组件中。

父组件:

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

const propsTotalValue = ref(6)
const copySuccess = (value: string) => {
  console.log("copy的值为:", value);
}

provide('number', propsTotalValue)
provide('copySuccess', copySuccess)
</script>
复制代码

子组件或更深层的子组件:

<script setup lang='ts'>
import { ref, inject, Ref } from 'vue';

const number = inject('number') as Ref<number>
const copySuccess: any = inject('copySuccess')
console.log("number->>>>", number.value);
copySuccess(78787)
</script>
赞(2)
未经允许不得转载:UI树欲静 » Vite+Vue3.2+TS 相关API归纳总结