14、Nuxt3中Composables组合API详解 —— 完整篇

2,283 阅读5分钟

在本章节我们来了解一下 Composables 在项目开发中的作用及如何使用。Composables是一种利用 Vue 的组合 API 来封装和重用有状态逻辑的函数。在构建前端应用程序时,我们经常需要为常见任务重用逻辑,所以我们为此提取了一个可重用的函数。这个格式化函数封装了无状态逻辑:它接受一些输入并立即返回预期的输出。有许多库可用于重用无状态逻辑 - 例如 lodashdate-fns 。

<script setup lang='ts'>
 /*
 *   佛曰:
 *        写字楼里写字间,写字间里程序员;
 *        程序人员写程序,又拿程序换酒钱。
 *        酒醒只在网上坐,酒醉还来网下眠;
 *        酒醉酒醒日复日,网上网下年复年。
 *        但愿老死电脑间,不愿鞠躬老板前;
 *        奔驰宝马贵者趣,公交自行程序员。
 *        别人笑我忒疯癫,我笑自己命太贱;
 *        不见满街漂亮妹,哪个归得程序员?
 *
 * @Description: 布局组件
 * @version:1.2.0
 * @Date: 2022-09-14 17:55:25
 * @Author: wenBin
 */
 
 /****
 * Nuxt3组合API
 *    prefetchComponents
 *    preloadComponents
 *    setPageLayout
 *    etResponseStatus
 *    updateAppConfig
 *    useAppConfig
 *    useAsyncData
 *    useCookie
 *    useError
 *    useFetch
 *    useHead、
 *    useNuxtApp
 *    useRequestHeaders
 *    useRouter
 *    useRuntimeConfig
 *    useState
 *
 *****/
 
</script>

1、prefetchComponents可以对预取组件进行控制

使用prefetchComponents手动预取已在 Nuxt 应用程序中全局注册的各个组件。例如:

await prefetchComponents('MyGlobalComponent')

await prefetchComponents(['MyGlobalComponent1', 'MyGlobalComponent2'])

2、preloadComponents可以对预加载组件进行控制

使用preloadComponents手动预取已在 Nuxt 应用程序中全局注册的各个组件。例如:

await preloadComponents('MyGlobalComponent')

await preloadComponents(['MyGlobalComponent1', 'MyGlobalComponent2'])

3、setPageLayout允许动态更改页面的布局。它依赖于对 Nuxt 上下文的访问,并且只能在组件的设置函数、插件和路由中间件中调用。例如

export default defineNuxtRouteMiddleware((to) => {
  
  setPageLayout('other')
})

4、setResponseStatus 设置响应状态

您可以使用setResponseStatus设置响应的 statusCode(以及可选的 statusMessage)。 setResponseStatus只能在组件设置函数、插件和路由中间件中调用。例如:

// 404状态
setResponseStatus(404)
//or
setResponseStatus(404, 'Page Not Found')  // 设置状态信息

5、 updateAppConfig更新配置,现有属性被保留。例如:

const appConfig = useAppConfig() // { foo: 'bar' }

const newAppConfig = { foo: 'baz' }

updateAppConfig(newAppConfig)

console.log(appConfig) // { foo: 'baz' }

6、useAppConfig访问配置。例如:

const appConfig = useAppConfig()

console.log(appConfig)

7、 useAsyncData访问异步数据。例如

function useAsyncData(
  handler: (nuxtApp?: NuxtApp) => Promise<DataT>,
  options?: AsyncDataOptions<DataT>
): AsyncData<DataT>
function useAsyncData(
  key: string, //唯一键
  handler: (nuxtApp?: NuxtApp) => Promise<DataT>, //返回值异步函数
  options?: AsyncDataOptions<DataT>
): Promise<AsyncData<DataT>>

type AsyncDataOptions<DataT> = {
  server?: boolean, //是否获取服务器上的数据
  lazy?: boolean, //默认false,获取数据之前是否阻塞路由
  /**
  * 
  * default异步函数解析之前设置数据默认值的工厂函数 - 特别适用于该`lazy: true`选项
  *
  ****/
  default?: () => DataT | Ref<DataT> | null,
  transform?: (input: DataT) => DataT, //  可用于`handler`在解析后更改函数结果 的函数
  pick?: string[], //只从函数结果 中选择这个数组中的指定键
  watch?: WatchSource[], //自动刷新
  initialCache?: boolean, //是否跳过有效负载缓存以进行初始提取,默认false
  immediate?: boolean //阻止请求立即触发,默认true
}

interface RefreshOptions {
  _initial?: boolean
}

type AsyncData<DataT, ErrorT> = {
  data: Ref<DataT | null>, //传递参数
  pending: Ref<boolean>, //是否仍在获取数据,booolean
  execute: () => Promise<void>, //刷新`handler`函数 返回的数据 , fun
  refresh: (opts?: RefreshOptions) => Promise<void>,//刷新`handler`函数 返回的数据, fun
  error: Ref<ErrorT | null>  //数据获取失败时的错误对象
}


//使用
const { data, pending, error, refresh } = await useAsyncData(
  'mountains',
  () => $fetch('https://api.nuxtjs.dev/mountains')
)

8、useCookie读写 cookie。例如:

const cookie = useCookie(name, options)

//使用
<template>
  <div>
    <h1> Counter: {{ counter || '-' }}</h1>
    <button @click="counter = null">
      reset
    </button>
    <button @click="counter--">
      -
    </button>
    <button @click="counter++">
      +
    </button>
  </div>
</template>

<script setup>
const counter = useCookie('counter')

//如果 cookie 不存在,则最初将其设置为随机值
counter.value = counter.value || Math.round(Math.random() * 1000)
</script>

9、 useError捕获全局错误。例如:

const error = useError()

10、useFetch 获取数据

这个可组合提供了一个方便的包装器useAsyncData$fetch. 它会根据 URL 和 fetch 选项自动生成密钥,根据服务器路由为请求 url 提供类型提示,并推断 API 响应类型。

//类型
function useFetch(
  url: string | Request | Ref<string | Request> | () => string | Request, //要获取的 URL
  options?: UseFetchOptions<DataT> //可选参数
): Promise<AsyncData<DataT>>

type UseFetchOptions = {
  key?: string, //唯一的key,
  method?: string, //请求方法
  params?: SearchParams, //查询参数
  body?: RequestInit['body'] | Record<string, any>, //请求正文 - 自动字符串化(如果传递了一个对象)
  headers?: { key: string, value: string }[], //请求标头
  baseURL?: string, //请求的基本 URL
  server?: boolean, //是否获取服务器上的数据
  lazy?: boolean, ////默认false,获取数据之前是否阻塞路由
  immediate?: boolean, //当设置为 时`false`,将阻止请求立即触发。默认true
  /**
  * 
  * default异步函数解析之前设置数据默认值的工厂函数 - 特别适用于该`lazy: true`选项
  *
  ****/
  default?: () => DataT,
  transform?: (input: DataT) => DataT, //解析后 可用于改变函数结果的函数
  pick?: string[], //仅从`handler`函数结果中选择此数组中的指定键
  watch?: WatchSource[], //自动刷新
  initialCache?: boolean //当设置为 时`false`,将跳过有效负载缓存以获取初始数据
}

type AsyncData<DataT> = {
  data: Ref<DataT>, //传入参数
  pending: Ref<boolean>, //布尔值,指示是否仍在获取数据
  refresh: () => Promise<void>, //一个函数,可以用来刷新`handler`函数返回的数据
  execute: () => Promise<void>, //一个函数,可以用来刷新`handler`函数返回的数据
  error: Ref<Error | boolean> //一个函数,可以用来刷新`handler`函数返回的数据
}

//例如:
const { data, pending, error, refresh } = await useFetch('https://api.nuxtjs.dev/mountains',{
    pick: ['title']
})

//使用拦截器
const { data, pending, error, refresh } = await useFetch('/api/auth/login', {
  onRequest({ request, options }) {
    // 设置请求头
    options.headers = options.headers || {}
    options.headers.authorization = '...'
  },
  onRequestError({ request, options, error }) {
    // 请求数据错误回调
  },
  onResponse({ request, response, options }) {
    // 获取响应数据回调
    return response._data
  },
  onResponseError({ request, response, options }) {
    //返回响应数据数据错误回调

  }
})

11、 useHead添加自定义各个页面的头部属性。具体如下:

//类型

useHead(meta: Computable<MetaObject>): void

interface MetaObject extends Record<string, any> {
  charset?: string,   //文档的字符编码。
  viewport?: string,  //配置视口
  meta?: Array<Record<string, any>>,  //**默认值**:`width=device-width, initial-scale=1`
  link?: Array<Record<string, any>>, //<link>标签
  style?: Array<Record<string, any>>, //<style>标签
  script?: Array<Record<string, any>>, //<script>标签
  noscript?: Array<Record<string, any>>, //<noscript>标签
  titleTemplate?: string | ((title: string) => string), //配置动态模板以自定义单个页面上的页面标题
  title?: string, //单个页面上设置静态页面标题
  bodyAttrs?: Record<string, any>, //<body>
  htmlAttrs?: Record<string, any> // <html>
}

//使用方法

//自定义元素
<script setup lang  = 'ts'>
  const title = ref('My App')
  const description = ref('My amazing Nuxt app')

  useHead({
    title,
    meta: [
      {
        name: 'description',
        content: description
      }
    ]
  })
</script>

//动态标题
<script setup lang  = 'ts'>
 /****
 *
 *`titleTemplate`设置为带有`%s`占位符的字符串或设置为`function`。
 * 注意:nuxt.config中只能设置静态属性
 *
 *****/
  useHead({
    // 字符串,
    // where `%s` is replaced with the title
    titleTemplate: '%s - Site Title',
    // 函数
    titleTemplate: (productCategory) => {
      return productCategory
        ? `${productCategory} - Site Title`
        : 'Site Title'
    }
  })
</script>

//添加外部CSS
<script setup lang  = 'ts'>  
  useHead({
    link: [
      { 
        rel: 'preconnect', 
        href: 'https://fonts.googleapis.com'
      },
      { 
        rel: 'stylesheet', 
        href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', 
        crossorigin: '' 
      }
    ]
  })
</script>

//添加第三方脚本
<script setup lang  = 'ts'>
  useHead({
    script: [
      {
        src: 'https://third-party-script.com',
        body: true
      }
    ]
  })
</script>

12、useNuxtApp获取上下文的方法,它在客户端和服务器端都可用。可以使用这些属性来扩展和自定义您的应用程序以及共享状态、数据和变量。例如:

<script setup lang  = 'ts'>
  const nuxtApp = useNuxtApp()
  
  
  //方法
  
  //1、通过 provide(name,value) 创建插件
  const nuxtApp = useNuxtApp()
  nuxtApp.provide('hello', (name) => `Hello ${name}!`)

  console.log(nuxtApp.$hello('name'))
   
  //2、通过 `hook(name,cb)` 创建插件
  export default defineNuxtPlugin((nuxtApp) => {
    nuxtApp.hook('page:start', () => {
        //业务逻辑存放处
    })
    nuxtApp.hook('vue:error', (..._args) => {
      console.log('vue:error')
      //
      如果是客户端
      if (process.client) {
       console.log(..._args)
      }
    })
  })
  
  //3、callhook(name,...args)使用任何现有钩子调用时返回结果
  await nuxtApp.callHook('my-plugin:init')
  
  
  //useNuxtApp包含一下属性和方法
  /****
  *
  * 1、component()
  * 2、directive()
  * 3、use()
  * 4、ssrContext:url,event,payload
  * 5、payload
  * 6、isHydrating
  *
  ****/
  
</script>

13、useRequestHeaders来访问传入的请求标头。例如:

// 获取所有请求头
const headers = useRequestHeaders()

// 仅获取请求头 cookie
const headers = useRequestHeaders(['cookie'])

14、 useRouter获取路由器实例。例如:

const router = useRouter();
router.back();
router.forward();
router.go();
router.push({ path: "/home" });
router.replace({ hash: "#bio" });

15、useRuntimeConfig公共配置变量。使用如下:

//客户端
<script setup lang="ts">
const config = useRuntimeConfig()
</script>

//服务端
export default defineEventHandler((event) => {
  const config = useRuntimeConfig()
})

//定义运行时配置
export default defineNuxtConfig({
  runtimeConfig: {
    // 端口
    apiSecret: '123',

    // 公共请求地址
    public: {
      apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api'
    }
  }
})

16、useState。详细如下:

/*                       _oo0oo_
 *                       o8888888o
 *                       88" . "88
 *                       (| -_- |)
 *                       0\  =  /0
 *                     ___/`---'\___
 *                   .' \\|     |// '.
 *                  / \\|||  :  |||// \
 *                 / _||||| -:- |||||- \
 *                |   | \\\  - /// |   |
 *                | \_|  ''\---/''  |_/ |
 *                \  .-\__  '-'  ___/-. /
 *              ___'. .'  /--.--\  `. .'___
 *           ."" '<  `.___\_<|>_/___.' >' "".
 *          | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 *          \  \ `_.   \_ __\ /__ _/   .-` /  /
 *      =====`-.____`.___ \_____/___.-`___.-'=====
 *                        `=---='
 *      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *          佛祖保佑       永不宕机     永无BUG
 * @Description: 组合API
 * @version:1.2.0
 * @Date: 2022-09-14 16:24:57
 * @Author: wenBin
 */
// key:确保数据获取在请求之间正确重复数据删除的唯一键
// init:一个在未启动时为状态提供初始值的函数。这个函数也可以返回一个`Ref`
// T:指定状态的类型

useState<T>(init?: () => T | Ref<T>): Ref<T>
useState<T>(key: string, init?: () => T | Ref<T>): Ref<T>

总结:以上就是Nuxt3中常用的组合API,有极个别API在开发中很少使用,因此,我们只需要详细了解我们开发中常用的那些即可。