vue和jquery区别
- jq直接操作dom,vue不直接操作dom,vue的数据与视图是分开的,只需要操作数据即可
- jq操作dom行为是频繁的,vue利用虚拟dom,大大提高了性能
- vue集成的一些库比如vuex、router等大大提高了开发效率
vue的优势
- 数据视图分离,数据双向绑定
- 组件化
- 虚拟dom,运行速度快
- 单页面应用,局部刷新,提高访问速度和用户体验
- 与第三方ui框架配合使用良好
vue2、vue3的生命周期有哪些及每个生命周期做了什么?
| vue2 | vue3 options API | vue3 composition API | 做了什么 |
|---|---|---|---|
| beforeCreate | beforeCreate | setup代替 | 创建一个空白Vue实例;data、method尚未被初始化,不可使用 |
| created | created | setup代替 | Vue实例初始化完成,完成响应式绑定; data、method都可以初始化使用,可调用;尚未渲染模板 |
| beforeMount | beforeMount | onBeforeMount | 编译模板,调用render生成vdom;还没有开始渲染dom |
| mounted | mounted | onMounted | 完成dom渲染;组件渲染完成;开始由创建阶段进入运行阶段 |
| beforeUpdate | beforeUpdate | onBeforeUpdate | data发生变化之后;准备更新dom(尚未更新dom) |
| updated | updated | onUpdated | data发生变化,且dom更新完成(ps注意:不要在updated中修改data,可能会导致死循环) |
| beforeDestroy | beforeUnmount | onBeforeUnmount | 组件即将进入销毁(尚未销毁,可以正常使用);可移除解绑一些全局事件、自定义事件 |
| destroyed | unmounted | onUnmounted | 组件、子组件销毁完成 |
-
v3 composition api生命周期
setup 代替了beforeCreate和created
使用hooks函数形式,如mounted改为onMounted,updated改为onUpdated
父子生命周期
-
创建阶段
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
-
更新阶段
父beforeUpdate->子beforeUpdate->子updated->父updated
-
销毁阶段
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
接口请求一般放在哪个生命周期中?为什么要这样做?
接口请求可以放在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。
但是推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:
- 能更快获取到服务端数据,减少页面 loading 时间
- SSR 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于代码的一致性
- created 是在模板渲染成 html 前调用,即通常初始化某些属性值,然后再渲染成视图。如果在 mounted 钩子函数中请求数据可能导致页面闪屏问题
vue2、vue3区别
- API
- 生命周期
- 响应式
- vite
vue2、vue3响应式原理
vue2
通过Object.defineProperty将对象所有的property转化成getter和setter,每一个组件对应一个watcher实例,它会在组件渲染的过程中把接触过的数据property记录为依赖,当依赖项的setter触发时会通知watcher来派发更新。
- 数据劫持:Vue2使用
Object.defineProperty方法将对象的每一个属性转化成getter和setter。这样,当访问或修改对象的属性时,就可以触发相应的getter或setter函数,从而进行依赖收集和派发更新。 - 依赖收集:在渲染视图时,Vue会将
watcher(观察者)和具体的属性通过发布订阅者模式管理起来。这样,当数据发生变化时,就能更精准地更新视图。 - 派发更新:当数据变化时,通过
dep(依赖管理器)来执行watcher的notify方法,通知所有依赖该数据的watcher进行更新。
vue3
- 基于proxy实现对getter/setter的代理,在getter中收集依赖,修改数据触发setter。
- proxy只能代理对象,对于值类型的数据通过包裹一层,也就是我们使用的ref来设成响应式对象
- Proxy只会代理对象的第一层,vue3中会判断当前Reflect.get的返回值是否为Object,如果是则再通过
reactive方法做代理, 这样就实现了深度观测
vue2、vue3优缺点
vue2优点
- 渐进式:Vue2可以逐步地以不同的方式使用,只引入需要的部分,这使得它非常灵活和易于集成。
- 组件化:Vue2鼓励开发者将UI界面拆分成一个个独立的、可复用的组件,这有助于提升开发效率和项目的可维护性。
- 轻量级:Vue2的库体积相对较小,加载速度快,适合构建大型应用。
- 虚拟DOM:Vue2使用虚拟DOM来提高性能,减少真实DOM的操作次数,提升应用的渲染效率。
- 响应式:Vue2的响应式系统能够自动追踪数据的变化,并在数据变化时更新视图。
- 单页面路由:Vue2支持单页面应用(SPA)的开发,通过vue-router可以实现页面的无刷新跳转。
vue2缺点
- 深度监听,需要递归到底,一次性计算量大(需要递归到底+Object.defineProperty)
- 无法监听新增属性、删除属性,需要用到Vue.set和Vue.delete
- 无法原生监听数组,需要特殊处理(重新定义数组原型)
vue3优点
- 更小巧的体积:Vue3在保留功能的同时,通过对代码重构和优化,将库的大小减少了约30%,降低了前端页面加载时间和占用空间。
- 更高效的渲染机制:Vue3通过异步渲染和编译优化等措施,大幅提升了页面渲染的效率,特别是在处理大量数据和复杂组件时效果更为明显。
- 更简单的组件开发方式:Vue3引入了Composition API,这是一种基于函数的API,它让组件代码更加简洁和可复用,提升了开发者的编码体验。
- 更严格的TypeScript支持:Vue3对TypeScript进行了更严格的支持,提供了更加完整、准确的类型检查和错误提示,有助于开发者编写更加健壮的代码。
- 更好的可维护性和拓展性:通过组件化和模块化的方式,Vue3极大地增加了代码的可维护性和拓展性,让开发者在项目开发过程中更加容易进行代码管理和扩展。
vue3缺点
- 学习成本
- 迁移成本
- 生态完善程度
- proxy为es6新特性,旧版本浏览器会出现兼容问题
Vue2相关
vue2如何监测数据变化
- 使用了函数劫持的方式,重写了数组的方法,
- Vue将data中的数组进行了原型链重写,指向了自己定义的数组原型方法。这样当调用数组api时,可以通知依赖更新。
- 如果数组中包含着引用类型,会对数组中的引用类型再次递归遍历进行监控。这样就实现了监测数组变化
// 重新定义数组原型
const oldArrayProper = Array.prototype;
const arrProto = Object.create(oldArrayProper); // 创建新对象,原型指向oldArrayProper, 再扩展新方法不会影响到原型
['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(methodName => {
// 上述方法会改变原数组,所以需要重写
arrProto[methodName] = function(arguments) {
updateView(); // 更新视图
oldArrayProper[methodName].call(this, ...arguments)
}
})
MVVM
- M代表Model数据,V代表View视图,VM-ViewModel是他们之间的桥梁,实现了数据到视图和视图到视图的转化
MVC、MVP、MVVM
mvc理论上是单向数据流,其中controller负责业务逻辑,每个事件都会经过controller, 理论上可行,但是实际开发中view已经具备独立处理事件的能力,当每个事件都经过c的时候会变得非常臃肿 而且v和c一一对应,过于紧密的连接使得无法复用
mvp中p处理业务逻辑,v和m分开他们是独立的,p需要手动将v和m之间的数据进行同步,使得p非常沉重,维护也比较困难
mvc和mvp的对比: 相同点:p、c负责业务逻辑,m负责数据管理,v负责视图 不同点:mvp中v和m是分开的,而mvc在实际过程中v是可以操作m的
mvvm是model-view-viewmodel的简写, 是一种开发模式,它实现了视图和数据的分离, model是数据,view是视图,viewmodel是他们之间的桥梁, 实现了视图到数据、数据到视图的转化,也就是双向数据绑定, 使用这种开发模式的框架有vue和react
v-model 双向绑定的原理是什么?
v-model本质就是一个语法糖,可以看成是value + input方法的语法糖。
- input元素的value=this.xxx
- 绑定input事件 this.xxx = $event.target.value
- data更新触发re-render
// 父组件
<Test v-model="text">
// 子组件Test
<template>
<input type="text" :value="text" @input="$emit('change', $event.target.value)" />
</template>
export default {
model: {
prop: 'text', // 和props里面的text字段对应, 绑定到value
event: 'change' // 与emit事件对应
},
props: {
text: {
type: String,
default: ''
}
}
}
数据响应式和双向绑定的主要区别在于: 数据响应式是数据驱动视图更新 双向绑定是数据和视图相互驱动更新
vue2 diff算法
- O(n^3)-->O(n)做出的调整:(diff算法特点)
- 只比较同一层级,不跨级比较
- tag不同则直接删掉重建,不再深度比较
- tag和key两者都相同则认为是相同节点,不再重复对比
diff算法是vdom中最核心、最关键的部分, vdom用js对象模拟dom结构(vnode),数据发生变化时,进行新旧vnode对比,计算出最小变更,有效控制dom操作
vue组件通信
- 父->子 props
- 子->父 on
- listener、provider+inject、$refs
- 跨级组件:vuex、EventBus
父组件如何得知子组件的生命周期:子组件在每个生命周期中定义emit事件来通知父组件
v-if和v-show的异同、使用场景
- 相同点:都能控制元素的显示与隐藏
- 不同点:
- 实现方式:
v-if是根据条件渲染或销毁元素来实现,v-show是利用css中display:none来实现的。 - 性能消耗:
v-if相比v-show开销更大的(直接操作dom节点增加与删除)
如果需要非常频繁地切换,则使用 v-show 较好 如果在运行时条件很少改变,则使用 v-if 较好
vue为何使用key
必须使用key,不能是index或者random key是给每一个vnode的唯一id,也是diff算法的一种优化策略,可以更加准确快速的找到对应的节点, diff算法中通过tag和key来判断是否是同一节点sameNode 可以减少渲染次数,提示渲染性能
keep-alive
- 工作原理
keep-alive可以实现组件缓存,当组件切换时不会对当前组件进行卸载。
两个属性include/exclude,控制组件是否进行缓存
两个生命周期activated/deactivated,用来得知当前组件是否处于活跃状态。
- 实现原理
- 缓存对象:
<keep-alive>组件内部维护了一个cache对象和一个keys数组,用于存储被缓存的组件实例和它们的键(key)。 - 组件匹配:在渲染过程中,
<keep-alive>会检查当前要渲染的组件是否满足缓存条件(即是否在include中且不在exclude中)。如果满足条件,则尝试从cache中查找该组件的实例。 - 缓存命中:如果
cache中存在该组件的实例(即命中缓存),则将该实例的componentInstance赋值给当前要渲染的vnode的componentInstance属性,并更新keys数组,以保证最近使用的组件实例始终在数组末尾。 - 缓存未命中:如果
cache中不存在该组件的实例(即未命中缓存),则将该vnode及其组件实例添加到cache和keys中。如果此时cache的大小超过了max属性指定的限制,则根据LRU策略移除最久未使用的组件实例。 - 生命周期钩子:当组件被激活(即重新挂载到DOM上)时,会触发
activated钩子函数;当组件被缓存(即从DOM上移除但保留在缓存中)时,会触发deactivated钩子函数。 - 缓存销毁:当
<keep-alive>组件被销毁时,它会遍历cache对象,并销毁所有缓存的组件实例,以释放内存空间。
原理:
内部维护了一个cache对象和一个keys数组,用于存储被缓存的组件实例和它们的键(key)
created阶段会将组件实例存入cache,key存入keys
mounted阶段会监听include和exclude,检查当前要渲染的组件是否满足缓存条件
使用场景: 缓存组件 频繁切换,不需要重复渲染(如tab页) vue性能优化
nextTick 的作用是什么?他的实现原理是什么?
主要作用是在当前数据变化后等待 DOM 更新完成,然后执行特定的操作。
在 Vue 2 中,Vue.nextTick 的实现依赖于 MutationObserver 或 setTimeout。其基本原理如下:
- 依赖收集与变更检测:当 Vue 检测到数据变化时,会将这些变更放入一个异步队列中。
- 异步更新:Vue 使用
MutationObserver(如果可用)或setTimeout来创建一个微任务或宏任务,在这些任务中执行队列中的所有变更。 nextTick回调:Vue.nextTick接收一个回调函数,这个回调函数会在所有的 DOM 更新完成后执行。
function nextTick(callback) {
const p = Promise.resolve();
p.then(callback);
// 兼容性处理,如果 Promise 不可用,则使用 setTimeout
if (!isUsingMicroTask) {
setTimeout(callback, 0);
}
}
mixin
场景: 多个组件有相同的逻辑,抽离出来
mixin问题
- 变量来源不明确,不利于阅读
- 多mixin可能会造成命名冲突
- mixin和组件可能出现多对多的关系,复杂度高(一个组件引入多个mixin,或者多个组件引入一个mixin)
vue3中提供了hooks作为一种更新、更清晰的逻辑复用方法
优点:
- Hooks 提供了一种更清晰的复用逻辑的方式,因为每个 hook 都封装了一个独立的逻辑块。
- 相比于 mixin,hooks 的来源更明确,代码的可读性和可维护性更高。
- Hooks 可以更好地与 TypeScript 集成,提供类型检查和自动补全等特性。
比较与总结
- 复用性:Mixin 和 hooks 都提供了代码复用的功能,但 hooks 的复用方式更加清晰和灵活。
- 可读性:Hooks 的代码结构更加清晰,因为它们将逻辑封装在独立的函数中,而 mixin 的逻辑则分散在组件的各个部分。
- 可维护性:Hooks 提供了更好的可维护性,因为每个 hook 都可以单独测试和调试。而 mixin 的合并策略可能会导致一些难以追踪的问题。
- 集成性:Hooks 与 TypeScript 的集成更加紧密,提供了更好的类型检查和开发体验。
slot插槽
- 基本使用
// 父组件
<Test>
我是slot内容
</Test>
// 子组件Test
<template>
<div>
<slot>
默认值,如果没有传入则显示这段文字,反之不显示
</slot>
</div>
</template>
作用域插槽(父组件使用子组件data)
// 父组件
<Test>
<template v-slot="childSlotData">
{{childSlotData.slotData}}
</template>
</Test>
// 子组件Test
<template>
<div>
<slot :slotData="title"></slot>
</div>
</template>
data() {
return {
title: '子组件内容'
}
}
- 具名插槽
// 父组件
<Test>
<p>未命名的slot内容</p>
<template v-slot:slot1>
slot1插槽内容
</template>
<template v-slot:slot2>
slot2插槽内容
</template>
</Test>
//子组件Test
<template>
<div>
<slot></slot>
<slot name="slot1"></slot>
<slot name="slot2"></slot>
</div>
</template>
动态组件
// 用法
<component :is="component-name" />
需要根据数据,动态渲染的场景。即组件类型不确定
<div v-for="(item, key) in data" :key="key">
<component :is="item.name" />
<div/>
异步组件
异步加载:
import() 函数
按需加载,异步加载大组件(echart等)
export default {
component: {
AsyncDemo: () => import('路径')
}
}
Vuex的几种属性--state、getter、mutation、action、modules
- state 基本数据(数据存放池)
- getter 从基本数据派生出来的数据
- mutation 提交修改数据的方法 同步
- action 可以整合mutation,可以处理异步
- modules 模块化vuex
Vue 组件的 data 为什么必须是函数
一个组件被复用多次的话,也就会创建多个实例。本质上,这些实例用的都是同一个构造函数。如果data是对象的话,对象属于引用类型,会影响到所有的实例。所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。
说一下 watch(侦听属性) 与 computed(计算属性) 的区别是什么?以及他们的使用场景分别是什么?
都可以监听数据变化。
-
watch是监听某一个值变化,执行对应操作,第一次不会触发(除非设置inmediate:true),支持异步,watch是函数时接收两个参数,新值和旧值。
-
- 使用场景:需要在数据变化时执行一些特定操作的场景,如异步操作、复杂的逻辑处理等。
-
computed会生成新的值,有缓存,监听的数据变化才会变化,computed为函数时有get和set方法。
-
- 使用场景:需要根据多个数据来计算得到新值的场景
一起使用时v-if和v-for的优先级
-
Vue2中v-for的优先级高于v-if这意味着Vue会先遍历列表中的每个元素,然后再对每个元素进行条件判断,它会导致渲染效率下降。
-
Vue3中v-if的优先级高于v-for这意味着
v-if将无法访问到v-for里面的变量解决办法
- 条件出现在循环内部时:结合computed将数组进行过滤后再去遍历
- 条件出现在外层时:使用template标签进行包裹,它不会生成dom标签渲染到页面上,在这一层进行v-if判断,然后在内部进行v-for循环
权限管理
- 接口权限:请求拦截,头部携带token;响应拦截,状态判断
- 菜单权限:beforeEach进行判断,addRoutes动态添加路由
- 路由权限:路由跳转时用beforeEach进行判断
- 按钮权限:v-if或自定义指令
路由传参
- name + params 地址栏不可见,刷新会消失
- path + query 显示在地址栏,刷新不会消失
vue-router
- 常用的路由模式hash(默认)、h5 history(后者需要server端支持)
- 路由配置(动态路由、懒加载)
- 动态路由
{path: '/user/:id', component: User},以冒号开头 - 懒加载/异步加载
{path: '/user/:id', component: () => import(./../user)}
前端路由
- hash
- hash变化会触发浏览器的前进、后退,不会刷新页面(spa必须的特点)
- hash永远不会提交到server端
- onhashchange监听浏览器前进后退
- h5 history
- 用规范的路由,但跳转时不刷新页面
- 需要后端支持
- history.pushState(...)打开一个新路由
- window.onpopstate监听浏览器前进后退
- 路由选择
- to B用hash,简单易用,对url规范不敏感
- to C可以考虑h5 history,需要后端支持
-
history模式下部署到服务器会出现404?vue是单页面应用只会产出一个index.html,输入其他路由会找不到资源, 需要后端在nginx配置将所有路由重定向到index
static和assets区别
相同点: 都可以放置静态资源
区别:
- static放第三方资源,assets放自己写的css和js等文件
- static目录直接上传到服务器,assets会经过build打包放到static里面一起上传
vue中如何解决跨域问题
JSONP:在客户端定义全局onSuccess函数,通过script发送请求,服务端返回一串字符串,在客户端当作一段js执行,调用onSuccess函数CORS:设置Access-Control-Allow-Origin响应头Proxy:vue.config.js中配置、nginx配置
vue.config.js配置
amodule.exports = {
devServer: {
host: '127.0.0.1',
port: 8084,
open: true,// vue项目启动时自动打开浏览器
proxy: {
'/api': { // '/api'是代理标识,用于告诉node,url前面是/api的就是使用代理的
target: "http://xxx.xxx.xx.xx:8080", //目标地址,一般是指后台服务器地址
changeOrigin: true, //是否跨域
pathRewrite: { // pathRewrite 的作用是把实际Request Url中的'/api'用""代替
'^/api': ""
}
}
}
}
}
通过axios发送请求中,配置请求的根路径
axios.defaults.baseURL = '/api'
nginx配置
server {
listen 8080;
# server_name www.xxx.com;
location / {
root /var/www/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
实际工作中vue优化
1、v-if vs v-show 销毁 vs css隐藏
2、v-for使用key
3、使用computed缓存
4、keep-alive缓存组件 频繁切换的组件,如tabs,不要过度使用
5、异步组件 如体积较大的组件,复杂表格等
6、服务端渲染ssr nuxt.js
按需优化,不要为了优化而优化
SPA首屏优化方式
-
减小入口文件积
-
静态资源本地缓存
后端返回资源问题:采用
HTTP缓存,设置Cache-Control,Last-Modified,Etag等响应头;采用Service Worker离线缓存前端合理利用
localStorage -
UI框架按需加载
-
图片资源的压缩
-
组件重复打包
在webpack中使用3次及以上的包抽离出来,放进公共依赖文件,避免了重复加载组件
-
开启GZip压缩
-
使用SSR
减少首屏渲染时间的方法有很多,总的来讲可以分成两大部分 :资源加载优化 和 页面渲染优化
SSR
SSR也就是服务端渲染,也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成,然后再把html直接返回给客户端。
SSR有着更好的SEO、并且首屏加载速度更快等优点。不过它也有一些缺点,比如我们的开发条件会受到限制,服务器端渲染只支持beforeCreate和created两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于Node.js的运行环境。还有就是服务器会有更大的负载需求。
Vue3相关
ref、toRef、toRefs区别
- ref用于生成
值类型的响应式数据,通过.value来调用修改,模版中不需要加.value
const ageRef = ref(18);
ageRef.value = 20
PS:为何需要ref?
返回值类型会丢失响应式(proxy只能代理对象)
如再setup、computed、合成函数中都有可能返回值类型
vue如果不定义ref,用户将自造ref,反而混乱
PS:为何需要.value
ref是一个对象(不丢失响应式), value存储值
通过.value属性的get和set
用于模板、reactive对象是不需要.value,其他情况需要
- toRef 将响应式数据的某一个属性变成ref
const state = reactive({
age: 18,
name:'jubao'
});
const ageRef = toRef(state, 'age')
// 两者保持引用关系
- toRefs 将reactive响应式对象变为普通对象, 对象的每个属性都是对应的ref,解决reactive对象不能直接解构的问题(直接结构会失去响应式)
const stateRefs = toRefs(state);
const { age: ageRef, name: nameRef } = stateRefs;
return {
ageRef,
nameRef
}
// 两者保持引用关系
// 模板里面使用{{ageRef}}和{{nameRef}}
PS:为何需要toRef、toRefs
初衷:不丢失响应式的情况下,把对象数据分解/扩散
前提:响应式对象(reactive封装的)而非普通对象
不创造响应式,而是延续响应式
composition API和options API对比
composition API: 更好的代码组织,更好的逻辑复用,更好的类型推导
- 小型项目 业务逻辑简单用options api
- 中大型项目 逻辑复杂用composition api
- 不建议共用,混乱
composition api和react hooks对比
- composition api的setup只会调用一次,它是作为created和beforeCreate生命周期来处理的,而react hooks会被多次调用
- 前者无需useMemo useCallBack,因为setup只会调用一次
- 前者无需考虑调用顺序,而后者需要保证hooks的顺序一致
- 前者reactive+ref比后者useState更难理解
v3比v2快的原因(性能体现)
- 使用proxy
- patchFlag进行动态标记
- hoistStatic将静态节点提升到父作用域,多个静态节点进行合并处理
- cacleHandle缓存事件
- SSR优化,静态节点直接输出字符串
- tree-shaking消除没有用到的代码,减少代码体积
v3比v2优势
- 体积更小(tree-shaking去除无用代码)
- 性能更好***
- 更好的ts支持***(几乎都是函数)
- 更好的代码组织(composition API)
- 更好的逻辑抽离(composition API)
- 更多新功能
v3升级了哪些新功能
- 1、createApp
v2
const app = new Vue({...})
Vue.use(..)
v3
const app = Vue.createApp({...})
app.use(...)
- 2、emits属性
子组件:
export default {
emits: ['xxx'];
setup(props, {emit}) {
emit(xxx)
}
}
<script setup>
const props = defineProps(obj/arr)
const emit = defineEmits(['xxx'])
emit('xxx')
</script>
- 3、生命周期
- 4、多事件
<button @click="one($event), two($event)">多事件</button>
- 5、Fragment(template里面可以有多个节点)
- 6、移除.sync
v2
<Test :title.sync="title"></Test>
v3
<Test v-model:title="title"></Test>
- 7、异步组件的写法
v2:
new Vue({
...
components: {
'Test': () => import('./Test.vue')
}
})
v3:
createApp({
...
components: {
Test: defineAsyncComponent(() => import('./Test.vue'))
}
})
- 8、移除filter
- 9、Teleport弹窗
- 10、Suspense(有两个插槽)
<Suspense>
<!-- 具有深层异步依赖的组件 -->
<Dashboard />
<!-- 在 #fallback 插槽中显示 “正在加载中” -->
<template #fallback> // 具名插槽
Loading...
</template>
</Suspense>
- 11、Composition API
- reactive【返回响应式代理】
- ref相关【返回响应式且可变的引用对象,ref优于reactive】
- readonly
- setup
- watch和watchEffect
- 生命周期钩子函数
场景题
如何件套路由参数变化
- watch 监听'$route'的to和from两个参数
- 通过beforeRouteUpdate获取to、from、next参数变化
如何捕获vue组件错误信息
- 通过window.error监听其他js错误以及异步组件的报错
- 通过errorCaptured钩子监听下级组件错误,返回false可以阻止向上传播
- 通过errorHandle监听全局vue组件错误