vue学习杂记

1、初识

react是基于MVC设计模式,vue基于MVVM设计模式,相比较,MVVM与MVC的最大区别就是:它实现了View和Model的自动同步,也就是当Model的数据改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变数据后该数据对应View层显示会自动改变。

2、内置指令

v-if 指令会基于表达式 seen 的值的真假来移除/插入该 <p> 元素

v-bind 指令将表达式 url 的值绑定到元素的 href attribute 上。在简写中,参数前的一切 (例如 v-bind:) 都会被缩略为一个 : 字符

 v-on 指令,它将监听 DOM 事件,有一个相应的缩写,即 @ 字符

3、组合式API和选项式API

组合式API是Vue3新加的

组合式API与选项式差异点如下:

(1)当使用单文件组件(SFC)时,我们可以使用 <script setup> 来大幅度地简化代码

<script setup> 中的顶层的导入和变量声明可在同一组件的模板中直接使用。你可以理解为模板中的表达式和 <script setup> 中的代码处在同一个作用域中。

(2)reactive, computed,方法直接声明在script中,onMounted, defineProps,defineEmits,

不再使用this来访问响应式状态

(3)可以使用 reactive() 函数创建一个响应式对象或数组

  1. 仅对对象类型有效(对象、数组和 MapSet 这样的集合类型),而对 stringnumber 和 boolean 这样的 原始类型 无效。

  2. 因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用。这意味着我们不可以随意地“替换”一个响应式对象,因为这将导致对初始引用的响应性连接丢失

  3. 用 ref() 定义响应式变量解决reactive对非引用类型的响应问题

4、响应式代理 vs. 原始值

重新赋值data中的引用对象,此值已经是原来的 newObject 的一个响应式代理。与 Vue 2 不同的是,这里原始的 newObject 不会变为响应式,请确保始终通过 this 来访问响应式状态。

5、methods

Vue 自动为 methods 中的方法绑定了永远指向组件实例的 this。这确保了方法在作为事件监听器或回调函数时始终保持正确的 this。你不应该在定义 methods 时使用箭头函数,因为箭头函数没有自己的 this 上下文。

6、nextTick

Dom的更新并不是同步的。要等待一个状态改变后的 DOM 更新完成,你可以使用 nextTick() 这个全局 API

7、深层响应式

意味着即使在更改深层次的对象或数组,你的改动也能被检测到。

reactive() API 有两条限制:

  1. 仅对对象类型有效(对象、数组和 MapSet 这样的集合类型),而对 stringnumber 和 boolean 这样的 原始类型 无效。

  2. 因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用。这意味着我们不可以随意地“替换”一个响应式对象,因为这将导致对初始引用的响应性连接丢失。这也意味着当我们将响应式对象的属性赋值或解构至本地变量时,或是将该属性传入一个函数时,我们会失去响应性

ref() 让我们能创造一种对任意值的 “引用”,并能够在不丢失响应性的前提下传递这些引用。这个功能很重要,因为它经常用于将逻辑提取到 组合函数 中。

ref各种场景下的解包,后续再总结。let count = $ref(0)响应式语法糖,还在实验阶段。

watch和ref搭配侦听后续再整理。

8、生命周期钩子

所有生命周期钩子函数的 this 上下文都会自动指向当前调用它的组件实例。注意:避免用箭头函数来定义生命周期钩子,因为如果这样的话你将无法在函数中通过 this 获取组件实例。

mounted 钩子可以用来在组件完成初始渲染并创建 DOM 节点后运行代码

使用 watch 选项在每次响应式属性发生变化时触发一个函数

create :创建,绑定有状态函数等

unamout:组件卸载

10、计算属性和方法

使用计算属性来描述依赖响应式状态的复杂逻辑。

两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。方法调用总是会在重渲染发生时再次执行函数。

计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 getter 和 setter 来创建。

不要在 getter 中做异步请求或者更改 DOM

11、绑定样式

可以给 :class (v-bind:class 的缩写) 传递一个对象来动态切换 class

<div class="static" :class="{ active: isActive, 'text-danger': hasError }" ></div>

绑定的对象并不一定需要写成内联字面量的形式,也可以直接绑定一个对象

<div :class="classObject"></div>

绑定数组

<div :class="[activeClass, errorClass]"></div>

<div :class="[isActive ? activeClass : '', errorClass]"></div>

<div :class="[{ active: isActive }, errorClass]"></div>

12、条件渲染

v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染

一个 v-else 元素必须跟在一个 v-if 或者 v-else-if 元素后面,否则它将不会被识别。

和 v-else 类似,一个使用 v-else-if 的元素必须紧跟在一个 v-if 或一个 v-else-if 元素后面。

单文件中template中的v-if没有生效?为啥?

v-if vs v-show: 不同之处在于 v-show 会在 DOM 渲染中保留该元素;v-show 仅切换了该元素上名为 display 的 CSS 属性。

v-show 不支持在 <template> 元素上使用,也不能和 v-else 搭配使用。

v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。

当 v-if 和 v-for 同时存在于一个元素上的时候,v-if 会首先被执行。

13、列表渲染

<li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </li>

对于多层嵌套的 v-for,作用域的工作方式和函数的作用域很类似。每个 v-for 作用域都可以访问到父级作用域。

14、事件处理

使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click="methodName" 或 @click="handler"

Vue 为 v-on 提供了事件修饰符。修饰符是用 . 表示的指令后缀,包含以下这些:

  • .stop
  • .prevent
  • .self
  • .capture
  • .once
  • .passive

可以链式调用

15、表单输入绑定

使用v-model

默认情况下,v-model 会在每次 input 事件后更新数据 (IME 拼字阶段的状态例外)。你可以添加 lazy 修饰符来改为在每次 change 事件后更新数据:

如果你想让用户输入自动转换为数字,你可以在 v-model 后添加 .number 修饰符来管理输入

如果你想要默认自动去除用户输入内容中两端的空格,你可以在 v-model 后添加 .trim 修饰符

16、事件侦听

watch 默认是浅层的:被侦听的属性,仅在被赋新值时,才会触发回调函数——而嵌套属性的变化不会触发。

如果想侦听所有嵌套的变更,你需要深层侦听器:deep: true

immediate: true 选项,这样便能强制回调函数立即执行

flush: 'post' 选项,默认情况下,用户创建的侦听器回调,都会在 Vue 组件更新之前被调用。这意味着你在侦听器回调中访问的 DOM 将是被 Vue 更新之前的状态。如果想在侦听器回调中能访问被 Vue 更新之后的DOM,你需要指明 flush: 'post' 选项。

我们也可以使用组件实例的 $watch() 方法来命令式地创建一个侦听器。

用 watch 选项或者 $watch() 实例方法声明的侦听器,会在宿主组件卸载时自动停止。

在少数情况下,你的确需要在组件卸载之前就停止一个侦听器,这时可以调用 $watch() API 返回的函数:unwatch()。

17、模板引用

组件挂载结束后引用都会被暴露在 this.$refs 之上。

当在 v-for 中使用模板引用时,相应的引用中包含的值是一个数组,应该注意的是,ref 数组并不保证与源数组相同的顺序。

除了使用字符串值作名字,ref attribute 还可以绑定为一个函数,会在每次组件更新时都被调用。需要使用动态的 :ref 绑定才能够传入一个函数。当绑定的元素被卸载时,函数也会被调用一次,此时的 el 参数会是 null

模板引用也可以被用在一个子组件上。这种情况下引用中获得的值是组件实例。

expose 选项可以用于限制对子组件实例的访问。

18、Vue 组件与原生 Web Components 之间的关系

19、组件基础

 当使用构建步骤时,我们一般会将 Vue 组件定义在一个单独的 .vue 文件中,这被叫做单文件组件 (简称 SFC)(.vue)

当不使用构建步骤时,一个 Vue 组件以一个包含 Vue 特定选项的 JavaScript 对象来定义(.js)

Props 是一种特别的 attributes,你可以在组件上声明注册。

当一个值被传递给 prop 时,它将成为该组件实例上的一个属性。该属性的值可以像其他组件属性一样,在模板和组件的 this 上下文中访问。

一个组件可以有任意多的 props,默认情况下,所有 prop 都接受任意类型的值。

当一个 prop 被注册后,可以像这样以自定义 attribute 的形式传递数据给它:

<BlogPost title="My journey with Vue" />

父子组件交互

父组件可以通过 v-on 或 @ 来选择性地监听子组件上抛的事件,就像监听原生 DOM 事件那样;子组件可以通过调用内置的 $emit 方法,通过传入事件名称来抛出一个事件,抛出和接收的事件名相同。父组件会接收这一事件,从而更新值。

子组件可以通过 emits 选项来声明需要抛出的事件。

通过插槽来分配内容??与使用组件区别在哪里?

动态组件

通过 Vue 的 <component> 元素和特殊的 is attribute 实现的。

当使用 <component :is="..."> 来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过 <KeepAlive> 组件强制被切换掉的组件仍然保持“存活”的状态。

HTML 标签和属性名称是不分大小写的,当你使用 DOM 内的模板时,都需要转换为相应等价的 kebab-case (短横线连字符) 形式。

 Vue 的模板解析器支持任意标签使用 /> 作为标签关闭的标志。在 DOM 模板中,我们必须显式地写出关闭标签。

当使用在原生 HTML 元素上时,is 的值必须加上前缀 vue: 才可以被解析为一个 Vue 组件。这一点是必要的,为了避免和原生的自定义内置元素相混淆。

元素位置限制

某些 HTML 元素对于放在其中的元素类型有限制,例如 <ul><ol><table> 和 <select>,相应的,某些元素仅在放置于特定元素中时才会显示,例如 <li><tr> 和 <option>

自定义的组件 <blog-post-row> 将作为无效的内容被忽略,因而在最终呈现的输出中造成错误。我们可以使用特殊的 is attribute 作为一种解决方案:

<table> <tr is="vue:blog-post-row"></tr> </table>

20、组件注册

使用 Vue 应用实例的 app.component() 方法,让组件在当前 Vue 应用中全局可用

全局注册,但并没有被使用的组件无法在生产打包时被自动移除 (也叫“tree-shaking”)。

全局注册在大型项目中使项目的依赖关系变得不那么明确。

在使用 <script setup> 的单文件组件中,导入的组件可以直接在模板中使用,无需注册。

如果没有使用 <script setup>,则需要使用 components 选项来显式注册。

21、props声明

在使用 <script setup> 的单文件组件中,props 可以使用 defineProps() 宏来声明

在没有使用 <script setup> 的组件中,prop 可以使用 props 选项来声明

传递给 defineProps() 的参数和提供给 props 选项的值是相同的,两种声明方式背后其实使用的都是 prop 选项

所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。

在大多数场景下,子组件应该抛出一个事件来通知父组件做出改变。尽量避免直接修改props。

Prop 校验:Vue 组件可以更细致地声明对传入的 props 的校验要求,可以向 defineProps() 宏提供一个带有 props 校验选项的对象。校验选项中的 type 可以是下列这些原生构造函数, 也可以是自定义的类或构造函数,Vue 将会通过 instanceof 来检查类型是否匹配。

22、事件

和原生 DOM 事件不一样,组件触发的事件没有冒泡机制。你只能监听直接子组件触发的事件。平级组件或是跨越多层嵌套的组件间通信,应使用一个外部的事件总线,或是使用一个全局状态管理方案

可以给 $emit 提供一个额外的参数传参。

组件要触发的事件可以显式地通过 defineEmits() 宏来声明,这个 emits 选项还支持对象语法,它允许我们对触发事件的参数进行验证,如果你正在搭配 TypeScript 使用 <script setup>,也可以使用纯类型标注来声明触发的事件。

如果一个原生事件的名字 (例如 click) 被定义在 emits 选项中,则监听器只会监听组件触发的 click 事件而不会再响应原生的 click 事件。

V-model: v-model 在组件上都是使用 modelValue 作为 prop,并以 update:modelValue 作为对应的事件。当然也可以使用变量,如下:

<MyComponent v-model:title="bookTitle" /> 表示使用title变量作为prop,子组件应声明一个 title prop,并通过触发 update:title 事件更新父组件值。

23、透传attribute

透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 classstyle 和 id

当一个组件以单个元素为根作渲染时,透传的 attribute 会自动被添加到根元素上。

如果一个子组件的根元素已经有了 class 或 style attribute,它会和从父组件上继承的值合并。

同样的规则也适用于 v-on 事件监听器。

有些情况下一个组件会在根节点上渲染另一个组件。接收的透传 attribute 会直接继续往下传递。

请注意:

  1. 透传的 attribute 不会包含 子组件上声明过的 props 或是针对 emits 声明事件的 v-on 侦听函数,换句话说,声明过的 props 和侦听函数被 子组件“消费”了。

  2. 透传的 attribute 若符合声明,也可以作为 props 传入深层组件。

透传进来的 attribute 可以在模板的表达式中直接用 $attrs 访问到。这个 $attrs 对象包含了除组件所声明的 props 和 emits 之外的所有其他 attribute,例如 classstylev-on 监听器等等。

  • 和 props 有所不同,透传 attributes 在 JavaScript 中保留了它们原始的大小写,所以像 foo-bar 这样的一个 attribute 需要通过 $attrs['foo-bar'] 来访问。

  • 像 @click 这样的一个 v-on 事件监听器将在此对象下被暴露为一个函数 $attrs.onClick

我们想要所有像 class 和 v-on 监听器这样的透传 attribute 都应用在内部的 <button> 上而不是外层的 <div> 上。我们可以通过设定 inheritAttrs: false 和使用 v-bind="$attrs" 来实现:

<div class="btn-wrapper"> <button class="btn" v-bind="$attrs">click me</button> </div>

没有参数的 v-bind 会将一个对象的所有属性都作为 attribute 应用到目标元素上

和单根节点组件有所不同,有着多个根节点的组件没有自动 attribute 透传行为。如果 $attrs 没有被显式绑定,将会抛出一个运行时警告。

可以在 <script setup> 中使用 useAttrs() API 来访问一个组件的所有透传 attribute

这里的 attrs 对象总是反映为最新的透传 attribute,但它并不是响应式的 (考虑到性能因素)。你不能通过侦听器去监听它的变化。如果你需要响应性,可以使用 prop。或者你也可以使用 onUpdated() 使得在每次更新时结合最新的 attrs 执行副作用。

24、插槽 Slots

组件使用slots接收模板内容

插槽内容可以是任意合法的模板内容,不局限于文本。例如我们可以传入多个元素,甚至是组件

插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的。

25、依赖注入

要为组件后代提供数据,需要使用到 provide() 函数

provide() 函数接收两个参数。第一个参数被称为注入名,可以是一个字符串或是一个 Symbol。后代组件会用注入名来查找期望注入的值。一个组件可以多次调用 provide(),使用不同的注入名,注入不同的依赖值。

第二个参数是提供的值,值可以是任意类型,包括响应式的状态,比如一个 ref。提供的响应式状态使后代组件可以由此和提供者建立响应式的联系。

除了在一个组件中提供依赖,我们还可以在整个应用层面提供依赖。在应用级别提供的数据在该应用内的所有组件中都可以注入。

注入上层组件提供的数据,需使用 inject() 函数,如果提供的值是一个 ref,注入进来的会是该 ref 对象,而不会自动解包为其内部的值。这使得注入方组件能够通过 ref 对象保持了和供给方的响应性链接。

注入默认值:const value = inject('message', '这是默认值')

在一些场景中,默认值可能需要通过调用一个函数或初始化一个类来取得。为了避免在用不到默认值的情况下进行不必要的计算或产生副作用,我们可以使用工厂函数来创建默认值。

当提供 / 注入响应式的数据时,建议尽可能将任何对响应式状态的变更都保持在供给方组件中。这样可以确保所提供状态的声明和变更操作都内聚在同一个组件内,使其更容易维护。

如果你想确保提供的数据不能被注入方的组件更改,你可以使用 readonly() 来包装提供的值。

26、异步组件

拆分应用为更小的块,并仅在需要时再从服务器加载相关组件 -------Vue 提供了 defineAsyncComponent 方法来实现此功能。

异步操作不可避免地会涉及到加载和错误状态,因此 defineAsyncComponent() 也支持在高级选项中处理这些状态

27、组合式函数

“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数

组合式函数约定用驼峰命名法命名,并以“use”作为开头。

尽管其响应性不依赖 ref,组合式函数仍可接收 ref 参数。如果编写的组合式函数会被其他开发者使用,你最好在处理输入参数时兼容 ref 而不只是原始的值。unref() 工具函数会对此非常有帮助:

如果你的组合式函数在接收 ref 为参数时会产生响应式 effect,请确保使用 watch() 显式地监听此 ref,或者在 watchEffect() 中调用 unref() 来进行正确的追踪。

在组合式函数中使用 ref() 而不是 reactive()。

从组合式函数返回一个响应式对象会导致在对象解构过程中丢失与组合式函数内状态的响应性连接。与之相反,ref 则可以维持这一响应性连接。

28、自定义指令

一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。

在没有使用 <script setup> 的情况下,自定义指令需要通过 directives 选项注册

将一个自定义指令全局注册到应用层级也是一种常见的做法:

const app = createApp({}) // 使 v-focus 在所有组件中都可用 app.directive('focus', { /* ... */ })

指令也可以接收任何合法的 JavaScript 表达式。

当在组件上使用自定义指令时,它会始终应用于组件的根节点。当应用到一个多根组件时,指令将会被忽略且抛出一个警告。和 attribute 不同,指令不能通过 v-bind="$attrs" 来传递给一个不同的元素。总的来说,推荐在组件上使用自定义指令。

只有当所需功能只能通过直接的 DOM 操作来实现时,才应该使用自定义指令。其他情况下应该尽可能地使用 v-bind 这样的内置指令来声明式地使用模板,这样更高效,也对服务端渲染更友好。

29、插件

插件 (Plugins) 是一种能为 Vue 添加全局功能的工具代码。一个插件可以是一个拥有 install() 方法的对象,也可以直接是一个安装函数本身。安装函数会接收到安装它的应用实例和传递给 app.use() 的额外选项作为参数。

插件没有严格定义的使用范围,但是插件发挥作用的常见场景主要包括以下几种:

  1. 通过 app.component() 和 app.directive() 注册一到多个全局组件或自定义指令。

  2. 通过 app.provide() 使一个资源可被注入进整个应用。

  3. 向 app.config.globalProperties 中添加一些全局实例属性或方法

  4. 一个可能上述三种都包含了的功能库 (例如 vue-router)。

30、内置组件

Teleport:类似react-dom的createPortal功能

<KeepAlive> 是一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例。

<TransitionGroup> 是一个内置组件,用于对 v-for 列表中的元素或组件的插入、移除和顺序改变添加动画效果。

<Transition> 会在一个元素或组件进入和离开 DOM 时应用动画。

31、单文件组件

Vue 的单文件组件 (即 *.vue 文件,英文 Single-File Component,简称 SFC) 是一种特殊的文件格式,使我们能够将一个 Vue 组件的模板、逻辑与样式封装在单个文件中。

32、工具链

Vite 是一个轻量级的、速度极快的构建工具,对 Vue SFC 提供第一优先级支持。

Vue CLI 是官方提供的基于 Webpack 的 Vue 工具链,它现在处于维护模式。

33、路由

单页应用中,“路由”是在客户端执行的。一个客户端路由器的职责就是利用诸如 History API 或是 hashchange 事件这样的浏览器 API 来管理应用当前应该渲染的视图。

34、状态管理

可以使用 reactive() 来创建一个响应式对象,并将它导入到多个组件中。

还可以使用其他响应式 API 例如 ref() 或是 computed(),或是甚至通过一个组合式函数来返回一个全局状态

35、测试推荐方案

36、服务端渲染

SSR 是 Server-Side Rendering,即服务端渲染的英文缩写。

Vue.js 是一个用于构建客户端应用的框架。默认情况下,Vue 组件的职责是在浏览器中生成和操作 DOM。然而,Vue 也支持将组件在服务端直接渲染成 HTML 字符串,作为服务端响应返回给浏览器,最后在浏览器端将静态的 HTML“激活”(hydrate) 为能够交互的客户端应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值