vue3基础

一、vue2与vue3区别

1、响应式方面

  • vue3中响应式用refreactive

关于响应式:juejin.cn/post/710762...

2、v-ifv-for一起使用

不推荐一起使用

  • 在vue2中,v-for 优先级大于 v-if
  • 在vue3中,v-if 优先级大于 v-for

关于为什么不推荐一起使用

3、生命周期

  • vue3中的生命周期,名字改为onBeforeMount,加上 on;销毁由 vue2中的beforeDestory改为onBeforeUnmout
  • script setup语法糖中,setup 代表了初始化

关于生命周期:

4、vue3中添加了composition API

关于composition APIjuejin.cn/post/710647...

5、组合式函数与mixin,通过组合式函数复用比mixin好

关于组合式函数:juejin.cn/post/735912...

6、内置组件增加了teleportfragmentsuspense

关于新增组件:juejin.cn/post/735830...

7、异步组件写法

  • 在vue2中异步组件是返回一个promise函数创建,const asyncModal = () => import('./Modal.vue')
  • 在vue3中通过defineAsyncComponent创建,const asyncModal = defineAsyncComponent(() => import('./Modal.vue'))

8、优化编译过程,重写虚拟DOM,提升渲染功能

关于渲染机制:

9、优化源码体积,更好的tree shaking,减少打包体积

  • 在vue3中,移除了不常用的API,例如:inline-template,filter等
  • vue3中的API基本添加了Tree shaking,按需引入,如果不需要vue3新增的API,打包的时候是不会打包的

10、vue3使用vite打包,vue2使用webpack打包,两者的区别

关于vite与webpack

二、vue3基础知识

1、响应式数据

1. 响应式数据refreactiv区别?

  • 接受类型:ref可以接受基础类型和对象类型 ;reactive只能接受对象类型

  • 使用场景:定义基础类型使用ref;定义对象类型最好使用reactive,避免对象中有value混合

  • 响应式数据:ref的响应式数据是RefImpl ,因为Proxy只能代理监听对象类型的数据,监听不了基础类型(Number,String,Boolean,Null,Undefined,BigInt)的数据,所以将基础类型封装为一个对象,将基础类型的读写转换为对对象的value的get和set操作 ,这个时候,读写基础类型的value就是基于对象的get和set内置方法监听数据变化,实现基础类型响应式能力;reactive的响应式数据是Proxy;

2. reactive解构赋值会怎么样?使用什么解构赋值?

  • 响应式数据解构赋值后可能会解除响应式联系,当使用解构赋值时,是直接将text复制 一份,没有调用getter,setter,所以不具备响应式

  • toRefs可以将响应式数据中的属性变为响应式

    • toRefs需要传入一个代理对象,否则会报错;
    • 然后toRefs内部创建一个新的对象来,遍历传入对象的所有属性,将属性值转为响应式对象,然后挂载到新创建的对象,最后将对象返回;
    • 内部会为代理对象的每一个属性创建一个具有value属性的对象,该对象是响应式的,value属性具有getter和setter,所以返回的每个属性都是响应式的
xml 复制代码
<template>  
    <textarea v-model="text" placeholder="文本信息" />  
    <div>文本信息:{{text}}</div>  
</template>
 
<script setup>  
    import { reactive } from 'vue';  
    const state = reactive({  
        text: '今天是2022年01月01日',  
    });  
    const { text } = toRefs(state);  
</script>

3. shallowReactive,shallowReadonly

注意:慎用浅层响应式作用API,例如shallowReactive,shallowReadonly

  • 浅层数据结构应该只用于组件中的根级状态。避免将其嵌套在深层次的响应式对象中,因为它创建的树具有不一致的响应行为,这可能很难理解和调试。

4. 去除响应式toRaw

把响应式关系解除,比如表单中,数据渲染在模板里的表单中,我们可以在表单中更改数据内

容,但是又不希望表单里每次数据变化都触发响应式作用,这个时候就需要用到 toRaw 来解

除掉数据的响应式

如果只是临时修改数据,不想影响视图,就要解除数据的响应式,甚至还要考虑是否需要深拷⻉

2、计算属性computed

  1. 在get中只读属性,并且只有依赖的值发生改变的时候才会重新计算

  2. 在set中设置属性,最好避免直接修改计算属性,因为这是个临时存放点,应该改变他所依赖的值

  3. get只做计算而没有其他副作用,比如更改DOM,异步请求,不改变其他状态,只做计算和返回值(改变其他状态使用侦听器watch)

  4. computed计算的属性值可以是一对多

3、侦听器watch

  1. 状态变化时处理一些操作(副作用),比如想更改DOM,异步请求改变状态。实际场景:比如每次响应式状态发生变化时调用函数或者触发请求操作。

  2. 深度监听时,deep,会监听对象中的所有属性,如果数据结构较大,开销会大,应谨慎使用

  3. 立即执行:immediate: true

  4. watch侦听的属性值,只能是一对一,第一个参数

1. watch与watchEffect

  • watch第一个参数是侦听值,需要明确表明出来,当第二个参数回调函数中有侦听值时,侦听值改变的同时也会改变回调函数中的,这时候可以简化使用watchEffect;

  • watchEffect第一个参数直接写回调函数,并且可以监听多个侦听值,不需要添加侦听值;不过watchEffect只在同步的时候监听,异步的时候只在第一个await正常工作前被访问到的属性被追踪;

    • watch: watch第一个参数是侦听值,确认的;第二个回调函数;只有在侦听值变化时才会更改回调函数中的;不会在产生副作用时追踪侦听值
    • watchEffect:只有一个回调函数;追踪回调函数中的响应式属性;有副作用时也会追踪,只能在同步的时候追踪,依赖值不明确

2.watch回调函数操作

  • watch的回调函数是一次性操作很多,批量处理,比如要向侦听的数组中添加一千个数据,是批量处理,不是处理一千次。

  • watch的触发时机是在父组件更新后,当前组件更新前,也就是DOM操作前,所以当前组件访问到的是DOM数据处理前

  • 如果想在DOM操作后触发watch,使用flush: 'post'

arduino 复制代码
watch(source, callback, {
  flush: 'post'
})

watchEffect(callback, {
  flush: 'post'
})

或者是使用watchPostEffect

javascript 复制代码
import { watchPostEffect } from 'vue'

watchPostEffect(() => {
  /* 在 Vue 更新后执行 */
})
  • 如果想同步触发的话,需要使用flush: 'sync',watchSyncEffect;但是这个最好监听简单的布尔值,因为不能批量操作,不能用于批量操作数组。
  • 停止监听:同步的时候,会绑定到当前组件实例上,组件卸载即停止监听;异步的话,需要手动停止监听,最好不用异步,如果需要使用异步数据,使用条件判断语句。

4、v-if,v-show区别?

  • v-if: 进行DOM渲染与销毁 ;只有在为true的时候才进行渲染 ,比如刚开始是false,不渲染,true时才渲染;v-if可以使用在template上 ;有更高的切换开销

  • v-show:一直渲染 ,进行css的显示隐藏;v-show不能使用在template上 ;有更高的初始渲染开销,频繁操作使用

5、v-for

  • v-for: v-for中循环对象,可以写value(值)、key(属性)、index(索引)
  • v-for可以使用在template上

1. v-ifv-for一起使用

不推荐一起使用

  • 在vue2中,v-for 优先级大于 v-if
  • 在vue3中,v-if 优先级大于 v-for
1. 为什么改了优先级?

在vue2中,v-for 优先级大于 v-if,所以每次需要先进行遍历,遍历后再判断,这样的话我们只渲染出一小部分的元素,也得在每次重渲染的时候遍历整个列表,不论是否发生了变化。不建议这样做的原因就是比较浪费性能 。也可以使用计算属性将v-if的值和v-for循环数组合为一个数组遍历。

2. 为什么不支持一起使用?

在vue3中一起使用时,会先进行判断,v-if 的条件将无法访问到 v-for 作用域内定义的变量别名,使用变量名的话会报错。在外新包装一层 <template> 再在其上使用 v-for或者v-if,更加通俗易懂

xml 复制代码
<!--
 这会抛出一个错误,因为属性 todo 此时
 没有在该实例上定义
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo.name }}
</li>

// 改为
<template v-for="todo in todos">
  <li v-if="!todo.isComplete">
    {{ todo.name }}
  </li>
</template>

2. v-for中为什么要使用key?

  • 在v-for中会根据就地更改的原则 来进行修改元素,数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。这种模式是高效的,但是只适用渲染元素不依赖子组件或临时DOM状态(例如表单输入值),一般情况都会给key

  • key在diff算法虚拟DOM 中,vnode新旧节点的比较中起到作用,不使用key的话,会移动进行比较值,有key的话,会根据key的顺序进行比较,并且会移除销毁不存在的key

  • 还可以根据key值强制替换元素,不是更新元素,这时的key可以用在任何情况下,不一定跟v-for一起使用

3. 为什么不建议index作为Key?key使用Math.random可以吗?

不建议使用index,Math.random作为key。

因为key是唯一的,如果使用index这些,状态不稳定,vue是动态变化的,当数值变化的时候,可能插入到中间末尾等随意位置,这时候index会变化,根据key去找进行比较,这时候Key值也已经变化。

3. v-for与组件一起使用,v-for中循环的内容使用props来接受

6、事件

事件有内联事件处理器(在html上直接写方法内容),方法事件处理器(调用方法):

  • 内联处理器调用方法,@click="say('hello')"
  • 内联处理器访问参数,@click="warn('Form cannot be submitted yet.', $event)"

1. 常见的事件修饰符有哪些?

  • 事件有冒泡模式(从下往上触发)和捕获模式(从上往下触发)
  • 冒泡效果:子元素和父元素都有绑定事件,这时候会自动向上冒泡,如果要阻止冒泡行为 ,使用stop来阻止
xml 复制代码
<div>
    <a @click.stop="doThis"></a>
</div>
  • prevent : 一般用于form表单提交事件,提交后将不再重新加载页面,阻止默认事件,比如说阻止a标签,不让他去触发
ini 复制代码
<form @submit.prevent="onSubmit"></form>
  • self : 只有点击自己的时候才会执行,但是要是在父元素上,子元素都是成对标签,这样点击是不行的,得有自己的内容,比如说文本等
erlang 复制代码
<div @click.self="doThat">
    我是外层div文字
    <div>内层div</div>
</div>
  • capture : 使用capture是捕获行为,从上到下处理,先处理doThis函数,再处理doThat函数
ini 复制代码
<div @click.capture="doThis">
    <div @click='doThat'></div>
</div>
  • once: 只执行一次
  • passive : 滚动行为立即发生而不是等待onSroll完成再滚动,主要用于移动端滚屏性能

2. 常见的按键修饰符?

  • esc、enter、ctrl、shift、tab、alt、meta、left、right、up、down、space、delete

3. v-on可以实现监听多个方法吗?

v-on监听事件,简写为@。可以监听多个方法,但不推荐这样使用,一般只监听与模板相关的方法。

ini 复制代码
<div @click="doThis,doThat"></div>

<div @click='doThis;doThat'></div>

这两种写法都可以监听多个方法,事件触发时依次调用这些方法

7、v-model在表单,组件中使用,v-model语法糖?

1. 在表单中使用

就是在input(input,checkbox,radio),textarea,select

2. 在组件上使用v-model:

  • 可以实现组件间的双向绑定
  • 在3.4之后通过defineModel宏,实现原理与v-model语法糖一样

3. 在vue2中v-model语法糖

juejin.cn/post/711152...

4. 在vue3中v-model语法糖

  • 在vue3.4之前也是通过把value用作props,把input用作event事件,只不过写法是通过vue3的defineProps,defineEmits 父组件:
ini 复制代码
<Child v-model:title="bookTitle" />

子组件:

xml 复制代码
<!-- Child.vue-->
<script setup>
defineProps({
 title: {
   required: true
 }
})
defineEmits(['update:title'])
</script>

<template>
 <input
   type="text"
   :value="title"
   @input="$emit('update:title', $event.target.value)"
 />
</template>
  • 在3.4开始,使用defineModel来代替value与input 父组件:
ini 复制代码
<Child v-model:title="bookTitle" />

子组件:

xml 复制代码
<!-- Child.vue -->
<script setup>
const title = defineModel('title')
</script>

<template>
 <input type="text" v-model="title" />
</template>

5. v-model的内置修饰符

  • number:自动转换为数字
  • trim: 将两边的空格去掉
  • lazy: 将input事件改为change事件,change后触发

6. v-model自定义修饰符

  • 自定义修饰符,是通过defineModel()或者是defineProps中的set()函数来生成自定义修饰符

父组件:

xml 复制代码
<script setup>
import { ref } from 'vue'
import MyComponent from './MyComponent.vue'
 
const myText = ref('')
</script>

<template>
 This input capitalizes everything you enter:
 <MyComponent v-model.capitalize="myText" />
</template>

子组件:

xml 复制代码
<script setup>
import { computed } from 'vue'

const [model, modifiers] = defineModel({
 set(value) {
   // modifiers名字对应,可以修改为其他名;capitalize与父组件名字对应,可修改为其他名
   if (modifiers.capitalize) {
     return value.charAt(0).toUpperCase() + value.slice(1)
   }
   return value
 }
})
</script>

<template>
 <input type="text" v-model="model" />
</template>

8、生命周期

1. vue3中组合式API生命周期:

  • 开始渲染组件
  • script setup 钩子函数,进行初始化,相当于vue2中的beforeCreate、created
  • onBeforeMount : 挂载前,这时候只有响应式完成,未创建DOM,将要首次执行DOM;SSR期间不被调用
  • onMounted : 挂载后,虚拟DOM转为实体DOM,能访问到实体DOM ,所有同步的子组件 (不包含异步组件和Suspense组件)挂载完成后父组件挂载 ;SSR期间不被调用;子组件onMounted --> 父组件onMounted
  • onBeforeUpdate : DOM修改前,这时候还是旧的数据;SSR期间不被调用
  • onUpdated : 修改完成,数据已经更新为新的数据子组件onUpdated-->父组件onUpdated ,vue机制是多个状态更改后会在某一时刻同时批量进行渲染 (考虑到性能问题),所以要单独 在某个状态变更后修改DOM使用nextTick();SSR期间不被调用
  • onBeforeUnmount: 卸载前,这时候还能访问到实体DOM中的内容;SSR期间不被调用
  • OnUnmounted : 卸载完成,访问不到数据,所有的子组件都会卸载,可以用来处理副作用(计时器,DOM监听,与服务器相关的);SSR期间不被调用
  • onErrorCaptured: 捕获错误,可以捕获到错误,一般用于app.config.errorHandler全局错误提示;SSR期间不被调用
  • onActivated: keep-alive缓存的时候插入到DOM中用,缓存被重新插入,组件挂载时也会被调用;SSR期间不被调用
  • onDeactivated: keep-alive卸载时周期;SSR期间不被调用
  • onServerPrefretch: 服务器渲染前调用,有时数据存在服务器上,需要调用数据使用,在SSR时期发生
  • onRenderTracked: 开发模式下调用,追踪响应式依赖时调用;SSR期间不被调用
  • onRenderTriggered: 开发模式下调用,响应式变更触发触发组件渲染时调用;SSR期间不被调用

2. vue3中响应式API生命周期:

  • 开始渲染组件
  • script setup钩子函数
  • beforeCreate: 创建前,初始化选项式钩子,初始化data,method等,双向绑定,响应式已经完成
  • created: 判断有无预编译模板,没有等待编译模板;有的话
  • beforeMount: 有模板后进行挂载,将vm.$el挂载到el上,将vnode虚拟DOM转化为实体DOM,渲染在界面上
  • mounted: 挂载后,此时已经能访问到实体DOM
  • 有数据修改时,触发beforeUpdate,此时数据还是未修改前数据;进行虚拟DOM与实体DOM比较,diff算法
  • updated: 此时数据已经为修改后数据
  • 触发销毁,beforeUnmount,销毁前,此时还能访问到实例内容
  • unmounted: 销毁完成,访问不到实例内容

3. vue2中生命周期:

juejin.cn/post/711152...

9、模板引用

  1. 通过ref进行模板引用,ref是在组件挂载后访问,初始化的时候是null,使用ref需要先声明

  2. ref声明可以是数组,比如在v-for中使用ref时,声明为数组

  3. 组件上的ref,可以在父组件中调用子组件的内容,在<script setup>中访问是私有的,默认访问不到子组件的内容,子组件需要使用defineExpose暴露出来;其他情况是可以直接访问

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼6 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax