目录
一、ts的自定义泛型
1、什么是泛型
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
泛型使用<T>来定义类型,<T>中的T,也可以是U也可以是其他合法的字母,建议大写。
泛型可以理解为不确定单独类型,函数中使用泛型,可以约束函数的参数和返回值类型相同。
2、如何使用泛型
ts定义泛型
// 定义泛型:用于限制person对象的具体属性
export interface PersonInter {
id: string,
name: string,
age: number
}
export type Persons = Array<PersonInter>
vue使用泛型
<template>
<div>
{{ person.id }}
</div>
</template>
<script setup lang="ts">
// import * as mock from "@/types";
// 引人泛型
import { type PersonInter,type Persons } from "@/types"
// 释义:变量 变量规范 严格检查PersonInter,如果不符合规范PersonInter,就报错
let person: PersonInter = { id: 'adadadd', name: '张三', age: 60 }
// 定义一个符合泛型的数组:定义一个personList变量,他必须是数组,并且,他的每一项必须符合PersonInter泛型规范
// 复杂写法:
let personList: Array<PersonInter> = [
{ id: 'adadadd1', name: '李四', age: 60 },
{ id: 'adadadd32', name: '王五', age: 61 },
{ id: 'adadadd3', name: '赵六', age: 62 }
]
// 简单写法:(直接在ts中定义好泛型)
let persons: Persons = [
{ id: 'adadadd1', name: '李四', age: 60 },
{ id: 'adadadd32', name: '王五', age: 61 },
{ id: 'adadadd3', name: '赵六', age: 62 }
]
</script>
<style lang="scss" scoped></style>
二、vue3的生命周期
1、什么是生命周期(组件的一生)
在Vue中,生命周期指的是Vue实例从创建到销毁的过程。在这个过程中,Vue实例会经历一系列的阶段,包括数据观测、模板编译、挂载DOM、更新DOM、卸载等等。在这些阶段,Vue提供了一些生命周期钩子函数,让我们可以在特定的时机执行某些代码。
总结一下,就是四个阶段:创建、挂载、更新、销毁
2、vue2和vue3的生命周期函数对比
vue2的生命周期
创建阶段:beforeCreate、created
挂载阶段:beforeMount、mounted
更新阶段:beforeUpdate、updated
销毁阶段:beforeDestroy、destroyed
vue3的生命周期
创建阶段:setup
挂载阶段:onBeforeMount、onMounted(挂载阶段:先挂载子组件,再挂载父组件)
更新阶段:onBeforeUpdate、onUpdated
卸载阶段:onBeforeUnmount、onUnmounted
- vue3常用的生命周期函数有:onMounted(挂载完毕)、onUpdated(更新完毕)、onBeforeUnmount(卸载前)
面试题:vue2和vue3的生命周期有什么区别?
vue2 vue3 说明 beforeCreate setup() 开始创建组件之前,实例被创建,还没有初始化好data和methods等属性 created setup() 已初始化好data和method等,但还没有开始编译模板 beforeMount onBeforeMount 模板编译完成,但还没有挂载到页面中 mounted onMounted 把编译好的模板挂载到页面容器中显示,此周期用的较多 beforeUpdate onBeforeUpdate 把data渲染到界面之前执行 updated onUpdated 把data数据更新到UI完成后 beforeDestroy onBeforeUnmount 销毁实例之前执行 destroyed onUnmounted 销毁实例完成后执行 activated onActivated 被 keep-alive 缓存激活时调用 deactivated onDeactivated 被 keep-alive 缓存睡眠时调用 rorCaptured onErrorCaptured 捕获子孙组件的错误时被调用此钩子包含三个参数:错误对象、组件实例、一个包含错误来源信息的字符串。可以返回 false 以阻止该错误继续向上传播。
插入一个题外话:
如何在项目中引入axios?
1、下载依赖:npm i axios
2、引入axios:import axios from "axios";
3、使用axios:
try { let result = await axios.get('https://dog.ceo/api/breeds/image/random') console.log('result.data', result.data) dogList.push(result.data.message) } catch (error) { alert(error) }
三、自定义Hooks
1、什么是Hooks?
Hooks 是 Vue3 Composition API 中的一种函数,用于封装可复用的逻辑。Hooks 允许开发者将组件的逻辑拆分为更小的、可复用的函数,从而提高代码的可维护性和可读性。
在 Vue2 中,我们通常使用 Mixins 来复用逻辑,但 Mixins 存在命名冲突、难以追踪数据来源等问题。而 Hooks 通过函数的方式来组织逻辑,避免了这些问题。
2、Hooks 的特点
- 复用性:Hooks 可以将逻辑封装为独立的函数,方便在不同的组件中复用。
- 可组合性:多个 Hooks 可以组合在一起,形成更复杂的逻辑。
- 清晰的依赖关系:Hooks 通过函数参数和返回值来明确依赖关系,避免了 Mixins 中的隐式依赖问题。
3、Hooks 的原理
3.1 Composition API 基础
在 Vue3 中,Composition API 提供了一组函数,如 ref
、reactive
、computed
、watch
等,用于在组件中定义响应式数据、计算属性和副作用。Hooks 就是基于这些函数来封装逻辑的。
3.2 Hooks 的实现
一个典型的 Hooks 函数通常会使用 ref
、reactive
、computed
、watch
等 Composition API 来定义和管理状态。Hooks 函数可以返回状态、方法或其他需要在组件中使用的内容。
例如,下面是一个简单的 Hooks 函数,用于管理一个计数器的状态:
import { ref } from 'vue';
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
function increment() {
count.value++;
}
function decrement() {
count.value--;
}
return {
count,
increment,
decrement,
};
}
在这个例子中,useCounter
是一个 Hooks 函数,它封装了计数器的逻辑,并返回了 count
、increment
和 decrement
,供组件使用。
4、Hooks 的生命周期
Hooks 函数中的逻辑可以访问组件的生命周期钩子。例如,可以在 Hooks 中使用 onMounted
、onUpdated
、onUnmounted
等生命周期钩子来执行相应的操作。
import { ref, onMounted, onUnmounted } from 'vue';
export function useMousePosition() {
const x = ref(0);
const y = ref(0);
function updatePosition(event) {
x.value = event.pageX;
y.value = event.pageY;
}
onMounted(() => {
window.addEventListener('mousemove', updatePosition);
});
onUnmounted(() => {
window.removeEventListener('mousemove', updatePosition);
});
return { x, y };
}
在这个例子中,useMousePosition
Hooks 函数在组件挂载时监听鼠标移动事件,并在组件卸载时移除事件监听器。
5、Hooks 的实际应用场景
5.1 表单处理
表单处理是前端开发中常见的需求。通过 Hooks,我们可以将表单的逻辑封装为一个可复用的函数。
定义Hooks
import { ref } from 'vue'; export function useForm(initialState) { const formState = ref({ ...initialState }); function updateField(field, value) { formState.value[field] = value; } function resetForm() { formState.value = { ...initialState }; } return { formState, updateField, resetForm, }; }
在组件中使用这个 Hooks
import { useForm } from './useForm'; export default { setup() { const { formState, updateField, resetForm } = useForm({ username: '', password: '', }); return { formState, updateField, resetForm, }; }, };
5.2 数据请求
数据请求是另一个常见的场景。我们可以通过 Hooks 封装数据请求的逻辑,使得组件更加简洁。
定义Hooks:
import { ref, onMounted } from 'vue'; import axios from 'axios'; export function useFetch(url) { const data = ref(null); const loading = ref(true); const error = ref(null); onMounted(async () => { try { const response = await axios.get(url); data.value = response.data; } catch (err) { error.value = err; } finally { loading.value = false; } }); return { data, loading, error, }; }
在组件中使用这个 Hooks
import { useFetch } from './useFetch'; export default { setup() { const { data, loading, error } = useFetch('https://api.example.com/data'); return { data, loading, error, }; }, };
5.3 状态管理
在复杂的应用中,状态管理是一个重要的课题。通过 Hooks,我们可以将状态管理的逻辑封装为独立的函数,从而简化组件的代码。
定义Hooks
import { reactive } from 'vue'; export function useStore() { const state = reactive({ count: 0, todos: [], }); function increment() { state.count++; } function addTodo(todo) { state.todos.push(todo); } return { state, increment, addTodo, }; }
在组件中使用这个 Hooks
import { useStore } from './useStore'; export default { setup() { const { state, increment, addTodo } = useStore(); return { state, increment, addTodo, }; }, };
6、总结
Vue3 中的 Hooks 是 Composition API 的重要组成部分,它提供了一种灵活、强大的方式来组织和复用逻辑。通过 Hooks,开发者可以将组件的逻辑拆分为更小的、可复用的函数,从而提高代码的可维护性和可读性。
在实际开发中,Hooks 可以应用于表单处理、数据请求、状态管理等多个场景,帮助开发者更好地管理复杂的逻辑。
四、Vue3的路由
1、安装路由器
(1)安装路由器依赖:npm i vue-router
(2)在src下面创建router文件夹,下面新建一个index.ts文件
(3)在src/router/index.ts文件中创建一个路由器,并暴露
// 引入 import { createRouter, createWebHistory } from 'vue-router'; // 创建路由器router const router = createRouter({ // 路由 route routes:[ { path:'路径', component: } ] }) // 暴露路由器 router export default router
(4)在main.ts中注册路由器组件
// 引入路由器 import router from "./router"; // 安装路由器 app.use(router)
2、使用路由器
RouterLink:路由的跳转链接,相当于Vue自己封装的a标签
组件属性:
to:目标路由地址
active-class:被激活时,标签的类名
RouterView:路由的展示位置
<template>
<div class="box">
<h2 class="title">vue路由测试</h2>
<!-- 导航区 -->
<div class="navigate">
<!-- to: 目标路由地址 -->
<!-- active-class: 被激活时,标签的类名 -->
<RouterLink to="/home" active-class="active">首页</RouterLink>
<RouterLink to="/news" active-class="active">新闻</RouterLink>
<RouterLink to="/about" active-class="active">关于</RouterLink>
</div>
<!-- 展示区 -->
<div class="main-content">
<RouterView/>
</div>
</div>
</template>
<script lang="ts" setup>
// 引入组件
import {RouterView,RouterLink} from "vue-router"
</script>
注意:
1、路由组件通常存放在pages或views文件夹,一般组件通常存放在components文件夹。
2、通过点击导航,视觉效果上“消失”了的路由组件,默认是被卸载掉的,需要的时候再去挂载。
3、路由器的工作模式
路由器有两种工作模式:hsitory和hash模式
(1)history模式
使用场景:官网、前端展示网站 一般用的比较多
写法:vue2 - mode:'hsitory'
vue3 - history: createWebHistory()
优点:URL更加美观,不带#,更接近创痛网站的URL
缺点:后期项目上线,需要服务器配合处理路径问题,否则刷新会有404错误
export default createRouter({ // 路由模式:history history: createWebHistory(), })
(2)hash模式
使用场景:后台管理系统 一般用的比较多
优点:兼容性更好,因为不需要服务器端处理路径
缺点:URL带有#不太美观,且在SEO优化方面相对较差
export default createRouter({ // 路由模式:hash history:createWebHashHistory() })
4、to的两种写法
<!-- to的写法1 -->
<RouterLink to="/home" active-class="active">首页</RouterLink>
<!-- to的写法2 -->
<RouterLink :to="{path:'/news'}" active-class="active">新闻</RouterLink>
<RouterLink :to="{name:'news'}" active-class="active">新闻</RouterLink>
5、嵌套路由
在 Vue 3 中,嵌套路由允许我们根据应用程序的结构和层次来组织 URL。这种方式非常适合于具有多层嵌套组件的应用程序,例如用户的个人信息页和帖子页可能就是这样的情况。通过 Vue Router,我们可以轻松地实现这种嵌套路由的配置。
基本概念
嵌套路由的核心概念是在 Vue 组件中使用 <router-view> 作为占位符,来渲染匹配的子路由组件。顶层的 <router-view> 渲染顶层路由匹配的组件,而嵌套的 <router-view> 则渲染子路由组件。例如,一个 User 组件可能包含一个 <router-view>,用于渲染用户的个人信息或帖子列表。
配置嵌套路由
要配置嵌套路由,我们需要在 Vue Router 的路由配置中使用 children 属性。这个属性是一个路由数组,表示子路由的配置。例如,如果我们有一个用户的个人页面和帖子页面,我们可以这样配置路由:
const routes = [
{
path: '/user/:id',
component: User,
children: [
{
path: 'profile',
component: UserProfile,
},
{
path: 'posts',
component: UserPosts,
},
],
}];
6、路由query参数
(1)传递参数
<!-- 路由器的query传参 写法一: -->
<!-- <RouterLink :to="`/news/detail?id=${item.id}title=&${item.title}content&=${item.content}`">{{ item.title }}</RouterLink> -->
<!-- 路由器的query传参 写法二: -->
<RouterLink :to="{
path:'/news/detail',
query:{
id:item.id,
title:item.title,
content:item.content
}
}">
{{ item.title }}
</RouterLink>
(2)接收参数
import { useRoute } from 'vue-router';
let route = useRoute()
7、路由params参数
(1)路由器配置
{
name:'newDetail',
// vue3的路由——新闻>详情
// 使用param传参时,需要用占位符
path: 'detail/:id/:title/:content?', // ? 代表参数可传可不传
component: Detail,
}
(2)传递参数
<li v-for="item in newsList">
<!-- 路由器的params传参 写法一: -->
<!-- <RouterLink :to="`/news/detail/0001/新闻01/内容001`">{{ item.title }}</RouterLink> -->
<!-- 路由器的params传参 写法二: -->
<RouterLink :to="{
name:'newDetail', // 必须用name参数
params:{
id:item.id,
title:item.title,
content:item.content
}
}">
{{ item.title }}
</RouterLink>
</li>
(3)接收参数
import { useRoute } from 'vue-router';
let route = useRoute()
let data = route.params
备注1:传递params参数时,若使用to的对象写法,必须使用name配置项,不能用path。
备注2:传递params参数时,需要提前在规则中占位。
8、路由的props配置
作用:让路由组件更方便的接收到参数(可以将路由参数作为props传给组件)
(1)路由器props配置
{
name:'newDetail',
// vue3的路由——新闻>详情
path: 'detail', // ? 代表参数可传可不传
component: Detail,
// props的第一种写法:将路由接收到的所有params参数作为props传给路由组件
// props:true
// props的第二种写法:函数写法,可以自己决定将什么作为props给路由组件
props(route){
return route.query
}
// props的第三种写法(用的少):对象写法,可以自己决定将什么作为props给路由组件
// props:{
// x: 100,
// y: 200,
// z: 300
// }
}
(2)接收、使用参数
<template>
<ul class="news-list">
<li>编号:{{ id }}</li>
<li>标题:{{ title }}</li>
<li>内容:{{ content }}</li>
</ul>
</template>
<script lang="ts" setup>
import { defineProps } from "vue";
defineProps(['id','title','content'])
</script>
9、路由的replace属性
(1)作用:控制路由跳转时操作浏览器历史记录的模式;
(2)浏览器的历史记录有两种写入方式:分别为:push和replace:
- push是追加历史记录(默认开启)
- replace是替换当前历史
(3)开启replace模式:
<RouterLink to="/about" replace active-class="active">关于</RouterLink>
10、编程式导航
编程式路由导航是通过代码来实现页面跳转的一种方式,与使用 组件进行声明式导航不同,编程式导航更加灵活,可以在任何地方触发,适用于诸如按钮点击、表单提交等场景。
import { useRouter , useRoute } from 'vue-router'
const $router=useRouter()
const $route=useRoute()
// 对象 $router.push()可以向history对象添加新记录
$router.push({ path: 'home' })
// 命名的路由
$router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
$router.push({ path: 'register', query: { plan: 'private' }})
//$router.replace 替换当前路由不会向history对象添加记录 与push()基本一致
$router.replace({ path: 'home' })
11、路由重定向
定义:让指定的路径重新定位到另一个路径
用法:
{
// 重定向
path:'/',
redirect:'/home'
}