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暴露出来;其他情况是可以直接访问

相关推荐
cy玩具16 分钟前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
customer0842 分钟前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
qq_390161771 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test1 小时前
js下载excel示例demo
前端·javascript·excel
Yaml42 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事2 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶2 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo2 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v2 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
知孤云出岫2 小时前
web 渗透学习指南——初学者防入狱篇
前端·网络安全·渗透·web