Vue演练场基础知识(四)生命周期 + 模板引用

为学习Vue基础知识,我动手操作通关了Vue演练场,该演练场教程的目标是快速体验使用 Vue 是什么感受,设置偏好时我选的是选项式 + 单文件组件。以下是我结合深入指南写的总结笔记,希望对Vue初学者有所帮助。

九. 生命周期

每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。
最常用的是 mounted、updated 和 unmounted。

生命周期流程图

在这里插入图片描述

生命周期可用属性表

props、data、methods、computed、watch可用$el可用
beforeCreate××
created
beforeMount
×
mounted
beforeUpdate
updated
beforeUnmount
unmounted

服务端渲染方式对生命周期的影响

什么是服务端渲染?

服务器端渲染(Server-Side Rendering,简称SSR)是一种在Web开发领域中广泛应用的技术,与之相对的是传统的客户端渲染(Client-Side Rendering,CSR)。

服务端渲染与浏览器渲染有什么区别?

‌服务端渲染(SSR)‌:在服务器端完成HTML页面的生成和渲染,然后将完整的HTML页面发送给客户端浏览器。服务器接收到用户请求后,从数据库或其他数据源获取数据,使用模板引擎(如EJS、Pug、Handlebars等)将数据与预定义的HTML模板结合,生成最终的HTML内容,并作为HTTP响应的一部分发送给客户端‌。
‌浏览器渲染(CSR)‌:在客户端浏览器中通过JavaScript动态生成页面。前端通过AJAX等技术从后端获取数据,并根据数据动态生成DOM树,插入到HTML页面中。初次渲染时,通常会将原HTML中的数据标记替换为实际数据‌。‌
服务端渲染对浏览器的兼容性更强,对服务器的压力更大,对SEO关键词搜索机制更友好。

服务端渲染方式对Vue生命周期有什么影响?
由于服务端渲染直接输出静态HTML内容,不涉及DOM操作,所以服务端渲染时不会调用和DOM操作相关的生命周期,包括beforeMount mountedbeforeUpdateupdatedbeforeUnmountunmounted

具体生命周期介绍

1. beforeCreate

在组件实例初始化完成之后立即调用。

interface ComponentOptions {
  beforeCreate?(this: ComponentPublicInstance): void
}

所有生命周期钩子函数的 this 上下文都会自动指向当前调用它的组件实例。

注意:

  1. 避免用箭头函数来定义生命周期钩子,因为如果这样的话你将无法在函数中通过 this 获取组件实例。
  2. 组合式 API 中的 setup() 钩子会在所有选项式 API 钩子之前调用,beforeCreate() 也不例外。

2. created

在组件实例处理完所有与状态相关的选项后调用。
当这个钩子被调用时,以下内容已经设置完成:响应式数据、计算属性、方法和侦听器。然而,此时挂载阶段还未开始,因此 $el 属性仍不可用。

3. beforeMount

在组件被挂载之前调用。

4. mounted⭐️

在组件被挂载之后调用。
开始支持DOM操作,可以调用this.$el。
这个钩子通常用于执行需要访问组件所渲染的 DOM 树相关的副作用,或是在服务端渲染应用中用于确保 DOM 相关代码仅在客户端被调用。

5. beforeUpdate

在组件即将因为一个响应式状态变更而更新其 DOM 树之前调用。
这个钩子可以用来在 Vue 更新 DOM 之前访问 DOM 状态。

注意:
最好不要在beforeUpdateupdated中修改组件状态,以免陷入无限更新循环。

6. updated⭐️

在组件因为一个响应式状态变更而更新其 DOM 树之后调用。

注意:
父组件的更新钩子将在其子组件的更新钩子之后调用。

这个钩子会在组件的任意 DOM 更新后被调用,这些更新可能是由不同的状态变更导致的。如果你需要在某个特定的状态更改后访问更新后的 DOM,请使用 nextTick() 作为替代。

7. beforeUnmount

在一个组件实例被卸载之前调用。

8. unmounted⭐️

在一个组件实例被卸载之后调用。

一个组件在以下情况下被视为已卸载:

  1. 其所有子组件都已经被卸载。
  2. 所有相关的响应式作用 (渲染作用以及 setup() 时创建的计算属性和侦听器) 都已经停止。

可以在这个钩子中手动清理一些副作用,例如清除计时器、注销注册过的DOM 事件监听器或者断开与服务器的连接。

还有一些不常用的钩子,包括errorCaptured、renderTracked、renderTriggered、activated、deactivated、serverPrefetch,有兴趣可看这里

拓展:nextTick

当你在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个“tick”才一起执行。这样是为了确保每个组件无论发生多少状态改变,都仅执行一次更新。
nextTick 方法是Vue提供的一个全局 API,用于在下次 DOM 更新循环结束之后执行延迟回调。

function nextTick(callback?: () => void): Promise<void>

使用场景:

  1. 用于局部数据更新
    nextTick()用作组件中局部数据更新后DOM更新结束后的操作,全局的数据更新可以用updated生命周期函数。
  2. 用于在连续逻辑中加入等待DOM更新的条件
    在状态改变后立即使用nextTick() ,以等待 DOM 更新完成,确保在执行callback之前,DOM已经完成了所有更改。

使用方法:

  1. await 返回的 Promise
import { nextTick } from 'vue'
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    async increment() {
      this.count++

      // DOM 还未更新
      console.log(document.getElementById('counter').textContent) // 0

      await nextTick()
      // DOM 此时已经更新
      console.log(document.getElementById('counter').textContent) // 1
    }
  }
}
// 或
nextTick().then(()=>{
	console.log(document.getElementById('counter').textContent) // 1
});
  1. 传递一个回调函数作为参数
import { nextTick } from 'vue'
nextTick(()=>{
	console.log('已更新的DOM元素');
});

比全局版本的 nextTick() 更常见的用法是使用绑定在实例上的函数:this.$nextTick()

interface ComponentPublicInstance {
  $nextTick(callback?: (this: ComponentPublicInstance) => void): Promise<void>
}

可以看到,callback的参数里多了一个this。两个nextTick唯一区别就是组件传递给 this.$nextTick() 的回调函数会带上 this 上下文,其绑定了当前组件实例。

await this.$nextTick()this.$nextTick(callback)有什么区别?
没有搜到具体的讲解,但搜到了一个博主debug的分析:这里。还是不是很理解,尝试写一下,说得不对还请指正。
请看下面这个例子: 需要实现一个需求,一个小区业务详情页面,在左侧菜单栏切换了小区后,详情页跟着切换。

watch: {
  	async neighNo(newVal) {
      if (newVal) {
        this.$nextTick(() => {
        	this.$router.replace(`/base/business/${newVal}`);
        });         
      }
   }
}

当前页会由于菜单栏小区切换而刷新,那么此时当前的页面实例将要销毁,而this应该绑定在了这个要销毁的实例上。然后又切换了路由,重新创建了页面实例,this在这个过程中失去了正确的上下文,从而导致data失去了响应性。
换成下面这样用await的写法,this会根据语法作用域来确定绑定的上下文,每次都会绑定在对应的页面实例上,从而工作正常。

await this.$nextTick()
this.$router.replace(`/base/business/${newVal}`)

总结:await this.$nextTick()是更好的写法。

十. 模板引用

之前在Vue演练场基础知识(一)声明式渲染+Attribute绑定+事件监听中写到过一部分模板和指令的内容,这里再简单写一下。

文本插值

<span>Message: {{ msg }}</span>

原始 HTML

双大括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html 指令:

<script setup>
	const rawHtml = "<span style='color: red'>This should be red.</span>";
<script>
<template>
	<span v-html="rawHtml"></span>
<template>

渲染的结果是在HTML中插入:

<span><span style="color: red">This should be red.</span></span>

v-html 指令的参数仅限纯 HTML,数据绑定将会被忽略。
注意:在网站上动态渲染任意 HTML 是非常危险的,因为这非常容易造成 XSS 漏洞。请仅在内容安全可信时再使用 v-html,并且永远不要使用用户提供的 HTML 内容。

Attribute 绑定

使用v-bind指令:

<div v-bind:id="dynamicId"></div>
<div :id="dynamicId"></div>

如果绑定的值是 null 或者 undefined,那么该 attribute 将会从渲染的元素上移除。

同名简写(仅支持 3.4 版本及以上)

<div :id></div>

等同于:

<div :id="id"></div>

布尔型 Attribute

布尔型 attribute 依据 true / false 值来决定 attribute 是否应该存在于该元素上。disabled 就是最常见的例子之一。
如果绑定的值是 真值 或 null,那么元素会包含这个 disabled attribute,否则不包含。

<button :disabled="isButtonDisabled">Button</button>

动态绑定多个值

<div v-bind="objectOfAttrs"></div>

相当于绑定了objectOfAttrs中的所有属性。

调用函数

<time :title="toTitleDate(date)" :datetime="date">
  {{ formatDate(date) }}
</time>

注意:绑定在表达式中的方法在组件每次更新时都会被重新调用,因此不应该产生任何副作用,比如改变数据或触发异步操作。

指令 Directives

指令是带有 v- 前缀的特殊 attribute。Vue 提供了许多内置指令。一个指令的任务是在其表达式的值变化时响应式地更新 DOM。

<div v-bind="objectOfAttrs"></div>

动态参数

<a :[attributeName]="url"> ... </a>
// attributeName = href时等同于
<a :href="url"> ... </a>

<a @[eventName]="doSomething"> ... </a>
// eventName = focus时等同于
<a @focus="doSomething"> ... </a>

注意:

  1. 动态参数中表达式的值应当是一个字符串,或者是 null。特殊值 null 意为显式移除该绑定。
  2. 参数中不要有空格或引号,编译器会警告。如果你需要传入一个复杂的动态参数,我们推荐使用计算属性。
<a :['foo' + bar]="value"> ... </a>

当使用 DOM 内嵌模板 (直接写在 HTML 文件里的模板) 时,我们需要避免在名称中使用大写字母,因为浏览器会强制将其转换为小写。

<a :[someAttr]="value"> ... </a>
// 将会被转换为
<a :[someattr]="value"> ... </a>

修饰符 Modifiers

修饰符是以点开头的特殊后缀,表明指令需要以一些特殊的方式被绑定。
例如 .prevent 修饰符会告知 v-on 指令对触发的事件调用 event.preventDefault():

<form @submit.prevent="onSubmit">...</form>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值