Skip to content

1. compostion API VS Option API

optionsAPI

compositionAPI

compositionAPI2

理解自定义 Hook

  • 作用: 对多个组件重复的功能进行提取封装
  • 在 vue2 中, 可以使用 mixin 技术, 在 vue3 中使用自定义 hooks 函数

需求 1

  • 收集用户鼠标点击的页面坐标

  • hooks/useMousePosition.ts

ts
/* 
自定义hooks: 收集用户鼠标点击的页面坐标
*/
import { ref, onMounted, onUnmounted } from "vue";

export default function useMousePosition() {
  // 初始化坐标数据
  const x = ref(-1);
  const y = ref(-1);

  // 用于收集点击事件坐标的函数
  const updatePosition = (e: MouseEvent) => {
    x.value = e.pageX;
    y.value = e.pageY;
  };

  // 挂载后绑定点击监听
  onMounted(() => {
    document.addEventListener("click", updatePosition);
  });

  // 卸载前解绑点击监听
  onUnmounted(() => {
    document.removeEventListener("click", updatePosition);
  });

  return { x, y };
}

需求 2:

ts
/* 
使用axios发送异步ajax请求
*/
import { ref } from "vue";
import axios from "axios";

export default function useUrlLoader(url: string) {
  const result = ref();
  const loading = ref(true);
  const errorMsg = ref();

  axios
    .get(url)
    .then((response) => {
      loading.value = false;
      result.value = response.data;
    })
    .catch((e) => {
      loading.value = false;
      errorMsg.value = e.message || "未知错误";
    });

  return {
    loading,
    result,
    errorMsg,
  };
}
  • 在组件中使用自定义 hooks

    vue
    <template>
      <div class="about">
        <h2>x: {{ x }}, y: {{ y }}</h2>
        <hr />
        <h2 v-if="loading">LOADING...</h2>
        <h2 v-else-if="errorMsg">{{ errorMsg }}</h2>
        <img v-if="result" :src="result.message" alt="" />
      </div>
    </template>
    
    <script lang="ts">
    import { ref } from "vue";
    import useMousePosition from "../hooks/useMousePosition";
    import useUrlLoader from "../hooks/useUrlLoader";
    export default {
      setup() {
        const { x, y } = useMousePosition();
        const { loading, result, errorMsg } = useUrlLoader(
          "https://dog.ceo/api/breeds/image/random"
        );
    
        return {
          x,
          y,
          loading,
          result,
          errorMsg,
        };
      },
    };
    </script>

泛型强化类型检查

ts
export default function useUrlLoader<T>(url: string) {

  const result = ref<T>()
  ...
}
ts
<template>
<div class="about">
  <h2>x: {{x}}, y: {{y}}</h2>
  <hr>
  <h2 v-if="loading">LOADING...</h2>
  <h2 v-else-if="errorMsg">{{errorMsg}}</h2>
  <img v-if="result" :src="result[0].url" alt="">
</div>
</template>

<script lang="ts">

import {
  ref, watch
} from "vue"
import useMousePosition from '../hooks/useMousePosition'
import useUrlLoader from '../hooks/useUrlLoader'

interface DogResult {
  message: string
  status: string
}

interface CatResult {
  id: string
  url: string
  width: number
  height: number
}

export default {
  setup() {

    const {x, y} = useMousePosition()
    // const {loading, result, errorMsg} = useUrlLoader<DogResult>('https://dog.ceo/api/breeds/image/random')
    const {loading, result, errorMsg} = useUrlLoader<CatResult[]>('https://api.thecatapi.com/v1/images/search')

    return {
      x,
      y,
      loading,
      result,
      errorMsg
    }
  }
}
</script>