当前位置: 首页 > article >正文

学习Vue3的第三天

Vue3 生命周期

概念:生命周期钩子是 Vue 组件在其生命周期内不同阶段触发的函数,允许开发者在这些关键时刻插入自定义逻辑。

规律

生命周期整体分为四个阶段,分别是:创建、挂载、更新、销毁,每个阶段都有两个钩子,一前一后。

Vue2 生命周期钩子

创建阶段

  • beforeCreate:组件实例刚创建,数据观测和事件/侦听器尚未设置。
  • created:组件实例创建完成,数据观测和事件/侦听器已设置,但 DOM 尚未挂载。

挂载阶段

  • beforeMount:DOM 挂载前调用,模板已编译,虚拟 DOM 已创建。
  • mounted:DOM 挂载完成后调用,可以进行 DOM 操作。

更新阶段

  • beforeUpdate:数据更新后,虚拟 DOM 重新渲染前调用。
  • updated:虚拟 DOM 更新完成后调用,数据已更新且 DOM 已重新渲染。

销毁阶段

  • beforeDestroy:组件实例销毁前调用,可以进行清理操作。
  • destroyed:组件实例销毁后调用,所有子组件也已销毁。

Vue3 生命周期钩子

创建阶段

  • setup:组件创建之前调用,初始化逻辑在这里执行,此时组件的 props 和 context 可用。

挂载阶段

  • onBeforeMount:组件挂载前调用,DOM 还未插入文档。
  • onMounted:组件挂载完成后调用,可以进行 DOM 操作。

更新阶段

  • onBeforeUpdate:组件数据更新前调用,虚拟 DOM 更新前。
  • onUpdated:组件数据更新后调用,虚拟 DOM 已更新。

卸载阶段

  • onBeforeUnmount:组件卸载前调用,可以进行清理操作。
  • onUnmounted:组件卸载后调用,组件及其子组件都已卸载。

常用的钩子:onMounted(挂载完毕)、onUpdated(更新完毕)、onBeforeUnmount(卸载之前)

示例代码:

<template>
  <div class="person">
    <!-- 显示当前求和结果 -->
    <h2>当前求和为:{{ sum }}</h2>
    <!-- 点击按钮时调用 changeSum 方法 -->
    <button @click="changeSum">点我sum+1</button>
  </div>
</template>
<script lang="ts" setup name="Person">
import {
  ref, // 引入 ref 函数用于创建响应式数据
  onBeforeMount, // 组件挂载前执行的钩子
  onMounted, // 组件挂载完成后执行的钩子
  onBeforeUpdate, // 组件更新前执行的钩子
  onUpdated, // 组件更新完成后执行的钩子
  onBeforeUnmount, // 组件卸载前执行的钩子
  onUnmounted // 组件卸载完成后执行的钩子
} from 'vue'

// 声明一个初始值为 0 的响应式变量 sum
let sum = ref(0)

// 定义一个方法来增加 sum 的值
function changeSum() {
  sum.value += 1 // 将 sum 的值加 1
}

console.log('setup') // 打印 setup 阶段的信息

// 组件挂载前执行
onBeforeMount(() => {
  console.log('挂载之前') // 打印组件挂载前的信息
})

// 组件挂载完成后执行
onMounted(() => {
  console.log('挂载完毕') // 打印组件挂载完成后的信息
})

// 组件更新前执行
onBeforeUpdate(() => {
  console.log('更新之前') // 打印组件更新前的信息
})

// 组件更新完成后执行
onUpdated(() => {
  console.log('更新完毕') // 打印组件更新完成后的信息
})

// 组件卸载前执行
onBeforeUnmount(() => {
  console.log('卸载之前') // 打印组件卸载前的信息
})

// 组件卸载完成后执行
onUnmounted(() => {
  console.log('卸载完毕') // 打印组件卸载完成后的信息
})
</script>

自定义hook

在 Vue3 中,自定义钩子(或称为自定义组合函数)是一个函数,利用了 Vue 的组合式 API(Composition API),它封装了逻辑并允许在多个组件之间共享和复用这些逻辑。这与 Vue2 中的 mixin 类似,但自定义钩子更具灵活性和可维护性。

自定义 hook 的优势

  • 复用代码: 自定义 hook 可以将逻辑封装在一个函数中,并在多个组件中使用。这避免了重复编写相同的逻辑,并提高了代码的重用性。
  • 逻辑清晰: 将逻辑提取到自定义 hook 中,可以使 setup 函数中的代码更简洁。这样有助于将关注点分离,使组件的主要逻辑更加专注。
  • 易于维护: 自定义 hook 将逻辑集中在一个地方,使得更新和维护逻辑变得更加容易。如果逻辑有变化,只需修改 hook 中的实现,而不需要在每个使用该逻辑的组件中修改。

示例代码:

useSum.ts - 自定义 hook 用于管理计数器逻辑。

import { ref, onMounted } from 'vue';

/**
 * 用于管理一个累加器的钩子函数
 *
 * 提供累加、累减操作以及当前累加和的获取
 */
export default function useSum() {
    // 定义一个响应式变量 sum,用于存储当前的累加和
    let sum = ref(0);

    /**
     * 累加操作
     * 将 sum 的值增加 1
     */
    const increment = () => {
        sum.value += 1;
    };

    /**
     * 累减操作
     * 将 sum 的值减少 1
     */
    const decrement = () => {
        sum.value -= 1;
    };

    // 在组件挂载后调用 increment,对 sum 进行初始累加
    onMounted(() => {
        increment();
    });

    // 返回当前的累加和以及改变累加和的方法
    return { sum, increment, decrement };
}

useDog.ts - 自定义 hook 用于管理狗狗图片的获取和加载。

import { reactive, onMounted } from 'vue';
import axios, { AxiosError } from 'axios';

/**
 * 用于获取狗狗图片的自定义钩子
 *
 * 该钩子提供了一个函数用于获取狗狗图片,并管理图片加载状态和图片URL列表
 */
export default function useDog() {
    // 状态管理对象,用于存储狗狗图片的URL列表和加载状态
    let dogList = reactive<{ urlList: string[], isLoading: boolean }>({
        urlList: [],
        isLoading: false
    });

    /**
     * 异步获取狗狗图片
     *
     * 该函数通过调用API获取狗狗图片的URL,并将其添加到urlList中
     * 在获取图片前后更新isLoading状态,以反映加载状态
     */
    const getDog = async () => {
        dogList.isLoading = true;
        try {
            const { data } = await axios.get('https://dog.ceo/api/breed/pembroke/images/random');
            dogList.urlList.push(data.message);
        } catch (error) {
            const err = <AxiosError>error;
            console.log(err.message);
        } finally {
            dogList.isLoading = false;
        }
    };

    // 在组件挂载时自动调用getDog函数以获取狗狗图片
    onMounted(() => {
        getDog();
    });

    // 返回包含dogList状态和getDog函数的对象,供外部使用
    return { dogList, getDog };
}

组件使用 - 使用这两个自定义钩子。  

<template>
  <h2>当前求和为:{{ sum }}</h2>
  <button @click="increment">点我+1</button>
  <button @click="decrement">点我-1</button>
  <hr>
  <img v-for="(u, index) in dogList.urlList" :key="index" :src="u">
  <span v-show="dogList.isLoading">加载中......</span><br>
  <button @click="getDog">再来一只狗</button>
</template>

<script lang="ts" setup>
import useSum from '../hooks/useSum';
import useDog from '../hooks/useDog';

const { sum, increment, decrement } = useSum();
const { dogList, getDog } = useDog();
</script>

路由

Vue 3 的路由处理主要通过 Vue Router 库来实现。

Vue Router 是 Vue.js 的官方路由库,用于实现单页应用中的路由功能。它允许开发者定义 URL 与视图之间的映射,使得应用能够根据不同的 URL 显示不同的组件或页面,而不需要重新加载整个页面。

基本切换效果

要在 Vue 3 项目中使用 Vue Router,首先需要安装它:

npm install vue-router@4

然后,在项目中创建和配置路由。以下是一个简单的配置示例:

// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import HomeView from '../views/HomeView.vue';
import AboutView from '../views/AboutView.vue';

const routes = [
  { path: '/', component: HomeView },
  { path: '/about', component: AboutView }
];

const router = createRouter({
  history: createWebHistory(), // 使用 HTML5 History API
  routes
});

export default router;

在 src/main.ts 中将路由实例添加到 Vue 应用中:

// src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';

const app = createApp(App);
app.use(router);
app.mount('#app');

路由组件

在 Vue Router 中,路由通常通过以下组件来显示:

  • <router-view>:这是一个占位组件,它显示当前激活路由所对应的组件。每个路由组件都会被渲染在 <router-view> 中。
  • <router-link>:这是一个用于导航的链接组件,它生成的链接可以用于跳转到指定的路由。它相当于 HTML 中的 <a> 标签,但它会以 SPA 的方式进行导航,不会重新加载页面。
<template>
  <nav>
    <router-link to="/">Home</router-link>
    <router-link to="/about">About</router-link>
  </nav>
  <router-view></router-view>
</template>

两个注意点

  • 路由组件通常存放在`pages` 或 `views`文件夹,一般组件通常存放在`components`文件夹。
  • 通过点击导航,视觉效果上“消失” 了的路由组件,默认是被卸载掉的,需要的时候再去挂载。

路由模式

哈希模式:使用 createWebHashHistory() 来创建路由实例,URL 会包含一个 # 符号。适用于一些不支持 HTML5 History API 的环境。

  • 优点:兼容性更好,因为不需要服务器端处理路径。
  • 缺点:`URL`带有`#`不太美观,且在`SEO`优化方面相对较差。

历史模式:使用 createWebHistory() 来创建路由实例,它提供更自然的 URL 结构。需要服务器配置,以便能够处理所有的 URL 请求。

  • 优点:URL更加美观,不带有`#`,更接近传统的网站URL。
  • 缺点:后期项目上线,需要服务端配合处理路径问题,否则刷新会有`404`错误。
const router = createRouter({
  history: createWebHistory(), // 或者 createWebHashHistory()
  routes
});

to的写法

在模板中使用 <router-link> 组件时,可以通过 to 属性指定导航目标。to 属性可以是字符串、对象或函数,具体如下:

  • 字符串:用于简单的路径导航。
  • 对象:用于更复杂的导航,例如包含查询参数或哈希片段。
  • 函数:动态生成导航目标。
<template>
  <nav>
    <!-- 字符串写法 -->
    <router-link to="/about">About</router-link>

    <!-- 对象写法 -->
    <router-link :to="{ path: '/user', query: { id: 123 } }">User</router-link>

    <!-- 函数写法 -->
    <router-link :to="generatePath">Dynamic</router-link>
  </nav>
</template>

<script>
export default {
  methods: {
    generatePath() {
      return { path: '/dynamic', query: { timestamp: Date.now() } };
    }
  }
}
</script>

命名路由

命名路由是 Vue Router 提供的一种功能,它允许我们为路由定义一个名称,从而在导航时可以使用这个名称而不是路径。这种方式特别适用于大型应用,能提高代码的可维护性和灵活性。

如何定义命名路由

在路由配置中,可以为每个路由定义一个 name 属性。以下是一个示例:

// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import HomeView from '../views/HomeView.vue';
import AboutView from '../views/AboutView.vue';

const routes = [
  {
    path: '/',
    name: 'home', // 命名路由
    component: HomeView
  },
  {
    path: '/about',
    name: 'about', // 命名路由
    component: AboutView
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;

使用命名路由进行导航

可以在 <router-link> 中使用命名路由,通过 :to 属性传递路由名称:

<template>
  <nav>
    <!-- 使用命名路由进行导航 -->
    <router-link :to="{ name: 'home' }">Home</router-link>
    <router-link :to="{ name: 'about' }">About</router-link>
  </nav>
</template>

命名路由的好处

  • 简化代码:使用名称而非路径,避免硬编码路径字符串,特别是当路径发生变化时,可以减少修改的地方。
  • 灵活性:路径修改时,只需更新路由配置,不需要更改组件中的链接。
  • 清晰的意图:路由名称更具描述性,能更清晰地表达导航意图。

嵌套路由

Vue Router 支持嵌套路由,使得可以在一个页面内展示子页面。例如,一个博客文章页面可以有评论作为嵌套的子路由:

const routes = [
  {
    path: '/post/:id',
    component: PostView,
    children: [
      {
        path: 'comments',
        component: CommentsView
      }
    ]
  }
];

路由传参

在 Vue Router 中,可以通过多种方式传递参数到路由。常见的方式包括路径参数、查询参数和路由元数据。

路径参数

路径参数是路由定义中的动态部分。例如,定义一个用户详情页面路由时,可以在路径中使用占位符:

// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import UserProfile from '../views/UserProfile.vue';

const routes = [
  {
    path: '/user/:id',
    name: 'user-profile',
    component: UserProfile
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;

在组件中,可以通过 this.$route.params 访问这些参数:

<template>
  <div>User ID: {{ userId }}</div>
</template>

<script>
export default {
  computed: {
    userId() {
      return this.$route.params.id;
    }
  }
}
</script>
  • 备注1:传递params参数时,若使用to的对象写法,必须使用name配置项,不能用path。
  • 备注2:传递params参数时,需要提前在规则中占位。

查询参数

查询参数附加在 URL 的末尾,以 ? 开始,多个参数时,例如 :“/news/detail?a=1&b=2&content=欢迎你”。可以通过 :to 属性传递查询参数:

<template>
  <router-link :to="{ name: 'user-profile', query: { id: 123 } }">User Profile</router-link>
</template>

在组件中,使用 this.$route.query 访问查询参数:

<template>
  <div>Query ID: {{ queryId }}</div>
</template>

<script>
export default {
  computed: {
    queryId() {
      return this.$route.query.id;
    }
  }
}
</script>

路由元数据

虽然不直接用于导航,但路由元数据(meta 字段)可以用于存储其他信息,如访问权限或页面标题:

const routes = [
  {
    path: '/profile',
    name: 'profile',
    component: UserProfile,
    meta: { requiresAuth: true }
  }
];

在导航守卫中可以访问这些元数据:

router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !isAuthenticated) {
    next('/login');
  } else {
    next();
  }
});

总结

  • 路径参数:在路由定义中用 :param 形式定义,访问方式为 this.$route.params.param。
  • 查询参数:通过 URL 中 ? 后的参数传递,访问方式为 this.$route.query.param。
  • 路由元数据:用来存储附加信息,通过 meta 字段配置。

路由的props配置

在 Vue Router 中,props 配置允许将路由参数直接作为组件的 props 传递,这样可以使组件更具可重用性和测试性。

在路由定义中,可以通过 props 属性将路由参数传递给组件。可以配置为 true、false 或一个函数:

  • 布尔值 true:将路由参数作为组件的 props 传递。
  • 布尔值 false:不传递任何 props。
  • 函数:可以自定义如何将路由信息作为 props 传递。

布尔值 true

const routes = [
  {
    path: '/user/:id',
    name: 'user-profile',
    component: UserProfile,
    props: true // 将路由参数作为 props 传递
  }
];

在 UserProfile 组件中,可以直接使用 id prop:

<template>
  <div>User ID: {{ id }}</div>
</template>

<script>
export default {
  props: ['id'] // 声明 `id` 作为 prop
}
</script>

函数

const routes = [
  {
    path: '/user/:id',
    name: 'user-profile',
    component: UserProfile,
    props: route => ({ id: route.params.id }) // 自定义 props
  }
];

在 UserProfile 组件中,同样可以使用 id prop:

<template>
  <div>User ID: {{ id }}</div>
</template>

<script>
export default {
  props: ['id']
}
</script>

为什么使用 props

  • 增强组件可重用性:将路由参数作为 props 传递可以使组件更容易重用和测试。
  • 简化组件逻辑:避免在组件内部直接访问 $route,使组件逻辑更简洁明了。
  • 提高可测试性:通过 props 传递数据,使组件的测试更加直接,无需模拟 $route 对象。

replace 属性

作用

replace 属性用于控制路由跳转时如何操作浏览器的历史记录。它决定了是否在历史记录中替换当前条目,而不是新增一个条目。

浏览器的历史记录写入方式

  • push: 默认方式,添加新的历史记录条目。使用 push 进行的导航会在浏览器的历史记录中增加一个新的条目,从而允许用户通过“后退”按钮返回到之前的页面。
  • replace: 替换当前的历史记录条目。使用 replace 进行的导航不会添加新的历史记录条目,而是替换掉当前的条目。这样,用户无法通过“后退”按钮返回到之前的页面。

开启 replace 模式

在 <router-link> 中使用,可以在 <router-link> 组件中使用 replace 属性来开启 replace 模式。点击链接时,当前的历史记录条目将被替换,而不会新增条目:

<template>
  <router-link :to="{ name: 'user-profile', params: { id: 123 } }" replace>
    Go to User Profile
  </router-link>
</template>

在编程式导航中使用

在编程式导航中,可以通过将 replace 选项设置为 true 来替换当前的历史记录条目:

// 使用 replace 进行编程式导航
this.$router.push({ name: 'user-profile', params: { id: 123 }, replace: true });

在这种情况下,replace: true 确保了当前的历史记录条目被新的条目替换,而不是在历史记录中添加新的条目。

何时使用 replace 属性

  • 表单提交:在处理表单提交后,通常会使用 replace 属性来避免在提交后返回表单页的历史记录。
  • 重定向:在某些场景中,可能会进行重定向而不希望用户能通过“后退”按钮返回到原页面。使用 replace 属性可以实现这种效果。
  • 程序逻辑:在根据程序逻辑进行导航时,如果你希望替换当前历史记录而不是创建新的条目,可以使用 replace。

编程式导航

编程式导航允许你在代码中控制路由跳转,而不是仅仅依赖于 <router-link>。它通常用于处理复杂的导航逻辑,比如在用户操作之后或在条件满足时自动跳转。

基本用法

在 Vue 组件中,可以使用 this.$router 对象进行编程式导航。例如,跳转到某个路径:

this.$router.push('/new-path');

带参数的导航

可以在导航时传递参数,例如: 

this.$router.push({ name: 'user-profile', params: { id: 123 } });

重定向与 replace 属性

使用 replace 选项来替换当前历史记录条目,而不是添加新条目: 

this.$router.replace('/new-path');

处理导航错误

可以使用 catch 处理导航错误,例如路由不存在的情况: 

this.$router.push('/unknown-path').catch(err => {
  console.error(err);
});

使用导航守卫 

路由守卫用于在路由导航前或后执行特定的逻辑。Vue Router 提供了多种类型的路由守卫:

  • 全局守卫:在 router 实例中定义,适用于所有路由。
  • 路由独享守卫:在路由配置中定义,适用于特定路由。
  • 组件内守卫:在组件内部定义,适用于组件的生命周期。
beforeRouteEnter(to, from, next) {
  if (to.meta.requiresAuth) {
    // 需要认证的逻辑
    next('/login');
  } else {
    next();
  }
}

重定向

在 Vue Router 中,重定向用于将用户自动导航到另一个路由。当某个特定的路径被访问时,可以使用重定向将用户引导到预定的路径。

基本重定向

可以在路由配置中使用 redirect 属性来设置重定向。例如,当访问 /old-path 时,将自动重定向到 /new-path:

const routes = [
  { path: '/old-path', redirect: '/new-path' },
  { path: '/new-path', component: NewPathComponent },
];

动态重定向

可以使用函数动态决定重定向的目标。例如,根据某个条件决定重定向的路径:

const routes = [
  {
    path: '/redirect-me',
    redirect: to => {
      return to.query.loggedIn ? '/home' : '/login';
    }
  },
  { path: '/home', component: HomeComponent },
  { path: '/login', component: LoginComponent },
];

重定向与 replace 属性

在编程式导航中,可以结合 replace 属性来控制是否在历史记录中创建新的条目。例如,在重定向后使用 replace 属性来避免在历史记录中添加新条目:

// 使用 replace 进行编程式重定向
this.$router.replace('/home');

总结

  • redirect 属性: 用于设置路由重定向。
  • 动态重定向: 可以使用函数根据条件动态决定重定向的目标。
  • replace 属性: 在编程式重定向中控制是否替换当前历史记录条目。

http://www.kler.cn/a/298710.html

相关文章:

  • 智能工厂的设计软件 应用场景的一个例子:为AI聊天工具添加一个知识系统 之2
  • 知识碎片-环境配置
  • STM32 FLASHdb
  • 【Python】 基于Python实现日志聚合与分析工具:利用Logstash与Fluentd构建高效分布式日志系统
  • 定义Shape:打造属于你的独特图形
  • 深度学习中的并行策略概述:1 单GPU优化
  • QT如何判断一个文件是否存在
  • C++之打造my vector篇
  • 艺术体操与骑行的完美协奏:维乐Angel Rise+坐垫,激情与力量的展现!
  • Guitar Pro 8.2.1 Build 32 永久中文破解解锁版
  • 关于前端分辨率兼容和显示器缩放兼容的处理
  • ffmpeg的安装和使用教程及案例
  • 存储课程学习笔记1_访问scsi磁盘读写测试(struct sg_io_hdr,ioctl,mmap)
  • GAF-PCNN-BiLSTM、GASF-CNN-BiLSTM、GADF-CNN-BiLSTM的多特征分类预测/故障诊断
  • Linux操作系统:yum安装报错问题
  • Linux:特殊字符整理
  • 【区块链 + 人才服务】CERX- 基于联盟链的研学资源交换网络 | FISCO BCOS应用案例
  • Mysql链接异常 | [08001] Public Key Retrieval is not allowed
  • RK3399 android7.1 话柄电话功能
  • llms 文本分类的微调
  • 《论多源数据集成及应用》写作框架,软考高级系统架构设计师
  • 【Android】NestedScrollView的简单用法与滚动冲突、滑动冲突
  • 聚观早报 | 红魔电竞平板新品发布;台积电8月份营收
  • LabVIEW步进电机控制方式
  • node.js入门基础
  • Learn OpenGL In Qt之着色器