Vue3+TypeScript初体验-学习笔记②

223 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

image.png Vue3+TypeScript学习笔记第二篇,上一篇点【传送门】。本文是在学习技术胖的课程后写下的学习笔记,方便以后查阅。好记性不如烂笔头,写过笔记印象深刻很多。这是基础入门篇,不喜轻喷。

第一至第七点(回顾上一篇

八. Vue3中watch的使用和注意事项

监听单个值,引入后编写watch函数,它接受两个参数,第一个是要监听的值,这里是course,然后是一个回调函数。在函数中你可以获得到新值和旧值。

<template>
  <div>当前课程:{{ course }}</div>
  <button @click="changeCourseState">修改课程状态</button>
</template>

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

export default defineComponent({
  name: "HomeView",
  setup() {
    const course = ref("Javascript");
    const changeCourseState = () => {
      course.value = course.value + "学习完成|";
    };
    watch(course, (newValue, oldValue) => {
      //使用watch监听course变化,在回调函数中获取新旧值
      console.log(`new--->${newValue}`);
      console.log(`old--->${oldValue}`);
    });
    return {
      course,
      changeCourseState,
    };
  },
});
</script>

GIF.gif

监听多个值,当你要监听多个值的时候,不是写多个watch函数,而是要传入数组的形式。

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

export default defineComponent({
  name: "HomeView",
  setup() {
    interface DataProps {
      //给data增加类型注解
      courseList: string[];
      selectCourse: string;
      selectCourseFun: (index: number) => void;
    }
    const data: DataProps = reactive({
      courseList: ["vue3初识", "Node.js进阶", "css世界"],
      selectCourse: "vue3初识",
      selectCourseFun: (index: number) => {
        data.selectCourse = data.courseList[index];
      },
    });
    const course = ref("Javascript");
    const changeCourseState = () => {
      course.value = course.value + "学习完成|";
    };
    ////不是直接data.selectCourse,因为watch不能监听没有getter/effect方法。可以使用箭头函数直接返回。
    watch([course, () => data.selectCourse], (newValue, oldValue) => {
      console.log(`new--->${newValue}`);
      console.log(`old--->${oldValue}`);
    });
    return {
      ...toRefs(data),
      course,
      changeCourseState,
    };
  },
});
</script>

可以看到监听多个值时候,新旧值会以逗号隔开。

watch3.gif

九. Vue3中模块化介绍

//模块 useNowTime.ts
import { ref } from 'vue'
const nowTime = ref("00:00:00");
const getNowTime = () => {
    const now = new Date();
    const hour = now.getHours() < 10 ? String(now.getHours()).padStart(2, "0") : now.getHours();
    const minu = now.getMinutes() < 10 ? "0" + now.getMinutes() : now.getMinutes();
    const sec = now.getSeconds() < 10 ? "0" + now.getSeconds() : now.getSeconds();
    nowTime.value = hour + ":" + minu + ":" + sec;
    setTimeout(getNowTime, 1000); //每一秒执行一次这个方法
}
export { nowTime, getNowTime } //导出
<template>
  <div>{{ nowTime }}</div>
  <div><button @click="getNowTime">显示时间</button></div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { nowTime, getNowTime } from "../hooks/useNowTime"; //引入模块
export default defineComponent({
  name: "HomeView",
  setup() {
    return {
      nowTime,
      getNowTime,
    };
  },
});
</script>

time.gif

使用axios获取图片

// 模块useUrlAxios.js
import { ref } from 'vue'
import axios from 'axios' //需要先安装依赖 yarn add axios 或 cnpm i axios -S
function useUrlAxios(url: string) {
    const result = ref(null)
    const loading = ref(true)
    const loaded = ref(false)
    const error = ref(null)
    axios.get(url).then((res) => {
        loading.value = false;
        loaded.value = true;
        result.value = res.data;
    }).catch(e => {
        error.value = e;
        loading.value = false;
    })
    return {
        result,
        loading,
        loaded,
        error
    }
}
export default useUrlAxios
<template>
  <div>
    <div v-if="loading">Loading.....</div>
    <img v-if="loaded" :src="result.message" />
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import useUrlAxios from "../hooks/useUrlAxios"; //引入模块
export default defineComponent({
  name: "HomeView",
  setup() {
    const { result, loading, loaded } = useUrlAxios(
      "https://dog.ceo/api/breeds/image/random"
    );
    return { result, loading, loaded };
  },
});
</script>

dog.gif

十. Teleport瞬间移动函数的使用(独立函数)

Teleport在国内大部分都翻译成了瞬间移动组件,个人觉得不太好理解。我把这个函数叫独立组件,它可以把你写的组件挂载到任何你想挂载的DOM上,所以说是很自由很独立的。 在使用Vue2的时候是作不到的。

 // 新建组件 newDialog.vue
 <template>
  <teleport to="#modal">
    //组件挂载在modal节点上
    <h2>自定义Dialog组件</h2>
  </teleport>
</template>
// 在public/index.html增加一个Modal节点
<div id="app"></div> <div id="modal"></div>
<template>
  <div>
    //组件挂载在app节点上
    <h2>原节点</h2>
  </div>
  <new-dialog></new-dialog>
</template>
<script lang="ts">
import newDialog from "@/components/newDialog.vue"; //引入组件
const app = {
  name: "HomeView",
  components: {
    newDialog,
  },
};
export default app;
</script>

Teleport方法,可以把Dialog组件渲染到你任意想渲染的外部Dom上,不必嵌套再#app里了,这样就不会互相干扰了。你可以把Teleport看成一个传送门,把你的组件传送到你需要的地方。 teleport组件和其它组件没有任何其它的差异,用起来都是一样的。

image.png

十一. Suspense 初识异步请求组件

在Vue2.x时代,判断异步请求的状态是一件必须的事情,但是这些状态都要自己处理,根据请求是否完毕展示不同的界面。尤大神深知民间饥苦,在Vue3.x中给我们提供了Suspense组件。

<suspense> 组件有两个插槽。它们都只接收一个直接子节点。default 插槽里的节点会尽可能展示出来。如果不能,则展示 fallback 插槽里的节点。

Demo1

 //新建组件 AsyncShow.vue
 <template>
  <h1>{{ result }}</h1>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
  setup() {
    return new Promise((resolve, reject) => {
      //模拟异步请求数据
      setTimeout(() => {
        return resolve({ result: "已经延迟两秒了,我要出来了" });
      }, 2000);
    });
  },
});
</script>
<template>
  <div>
    <Suspense>
      <template #default>  
        <AsyncShow></AsyncShow>
      </template>
      <template #fallback>
        <h1>loading....</h1>
      </template>
    </Suspense>
  </div>
</template>
<script lang="ts">
import AsyncShow from "@/components/AsyncShow.vue"; //引入组件
export default {
  name: "HomeView",
  components: { AsyncShow },
  setup() {
    return {};
  },
};
</script>

async.gif

Demo2

//新建组件 DogShow.vue
<template>
  <img :src="result" alt="" />
</template>
<script lang="ts">
import axios from "axios";
import { defineComponent } from "vue";
export default defineComponent({
  async setup() {
    //使用async await代替promise
    const rowData = await axios.get("https://dog.ceo/api/breeds/image/random");
    return { result: rowData.data.message };
  },
});
</script>
<template>
  <div>
    <Suspense>
      <template #default>
        <DogShow></DogShow>
      </template>
      <template #fallback>
        <h1>loading....</h1>
      </template>
    </Suspense>
  </div>
</template>
<script lang="ts">
import DogShow from "@/components/DogShow.vue"; //引入组件
export default {
  name: "HomeView",
  components: { DogShow },
  setup() {
    return {};
  },
};
</script>

dog.gif

onErrorCaptured钩子函数

在捕获一个来自后代组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。【传送门】 Demo2 组件DogShow.vue稍微修改一下,故意把接口写错"dog.ceo/api/breeds/…" 。

<template>
  <div>
    <Suspense>
      <template #default>
        <DogShow></DogShow>
      </template>
      <template #fallback>
        <h1>{{ currentState }}</h1>
      </template>
    </Suspense>
  </div>
</template>
<script lang="ts">
import { ref, onErrorCaptured } from "vue";
import DogShow from "@/components/DogShow.vue";
export default {
  name: "HomeView",
  components: { DogShow },
  setup() {
    const currentState = ref("loading....");
    //捕获后代组件报错信息
    onErrorCaptured((error, instance, info) => {
      console.log(`error====>`, error);
      console.log(`instance====>`, instance);
      console.log(`info====>`, info);
      currentState.value = "异步数据请求失败!";
      return true;
    });
    return {
      currentState,
    };
  },
};
</script>

image.png

errror.gif

后续会再Vue3学习笔记第③篇。 image.png