模块化结合typescript - 泛型改造
// 为函数添加泛型 function useURLLoader<T>(url: string) { const result = ref<T | null>(null) 复制代码
// 在应用中的使用,可以定义不同的数据类型 interface DogResult { message: string; status: string; } interface CatResult { id: string; url: string; width: number; height: number; } // 免费猫图片的 API https://api.thecatapi.com/v1/images/search?limit=1 const { result, loading, loaded } = useURLLoader<CatResult[]>('https://api.thecatapi.com/v1/images/search?limit=1') 复制代码
使用 defineComponent 包裹组件
Teleport - 瞬间移动 第一部分
vue3 新添加了一个默认的组件就叫 Teleport,我们可以拿过来直接使用,它上面有一个 to 的属性,它接受一个css query selector 作为参数,这就是代表要把这个组件渲染到哪个 dom 元素中
<template> <teleport to="#modal"> <div id="center"> <h1>this is a modal</h1> </div> </teleport> </template> <style> #center { width: 200px; height: 200px; border: 2px solid black; background: white; position: fixed; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; } </style> 复制代码
Teleport - 瞬间移动 第二部分
Modal 组件
<template> <teleport to="#modal"> <div id="center" v-if="isOpen"> <h2><slot>this is a modal</slot></h2> <button @click="buttonClick">Close</button> </div> </teleport> </template> <script lang="ts"> import { defineComponent } from 'vue' export default defineComponent({ props: { isOpen: Boolean, }, emits: { 'close-modal': null }, setup(props, context) { const buttonClick = () => { context.emit('close-modal') } return { buttonClick } } }) </script> <style> #center { width: 200px; height: 200px; border: 2px solid black; background: white; position: fixed; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; } </style> 复制代码
在 App 组件中使用
const modalIsOpen = ref(false) const openModal = () => { modalIsOpen.value = true } const onModalClose = () => { modalIsOpen.value = false } <button @click="openModal">Open Modal</button><br/> <modal :isOpen="modalIsOpen" @close-modal="onModalClose"> My Modal !!!!</modal> 复制代码
Suspense - 异步请求好帮手第二部分
使用 async await 改造一下异步请求, 新建一个 DogShow.vue 组件
<template> <img :src="result && result.message"> </template> <script lang="ts"> import axios from 'axios' import { defineComponent } from 'vue' export default defineComponent({ async setup() { const rawData = await axios.get('https://dog.ceo/api/breeds/image') return { result: rawData.data } } }) </script> 复制代码
Suspense 中可以添加多个异步组件
<Suspense> <template #default> <async-show /> <dog-show /> </template> <template #fallback> <h1>Loading !...</h1> </template> </Suspense> 复制代码
全局 API 修改
- Vue2 的全局配置
import Vue from 'vue' import App from './App.vue' Vue.config.ignoredElements = [/^app-/] Vue.use(/* ... */) Vue.mixin(/* ... */) Vue.component(/* ... */) Vue.directive(/* ... */) Vue.prototype.customProperty = () => {} new Vue({ render: h => h(App) }).$mount('#app') 复制代码
Vue2 这样写在一定程度上修改了 Vue 对象的全局状态。
- 第一,在单元测试中,全局配置非常容易污染全局环境,用户需要在每次 case 之间,保存和恢复配置。有一些 > api (vue use vue mixin)甚至没有方法恢复配置,这就让一些插件的测试非常的困难。
- 第二,在不同的 APP 中,如果想共享一份有不同配置的 vue 对象,也变得非常困难。
- Vue3 的修改
import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) // 这个时候 app 就是一个 App 的实例,现在再设置任何的配置是在不同的 app 实例上面的,不会像vue2 一样发生任何的冲突。 app.config.isCustomElement = tag => tag.startsWith('app-') app.use(/* ... */) app.mixin(/* ... */) app.component(/* ... */) app.directive(/* ... */) app.config.globalProperties.customProperty = () => {} // 当配置结束以后,我们再把 App 使用 mount 方法挂载到固定的 DOM 的节点上。 app.mount(App, '#app')