vue3 vue2 区别
使用方面:
- 选项式API 代替组合式APi
- 组合式API 没有this
- 生命周期没有create ,setup 等同于create,卸载改成unmount
- V-if 优先级高于v-for
- 根实例的创建从new app 变成 create App
- 一些全局注册,比如mixin ,注册全局组件,use改成了用app 实例调用,而不是vue 类调用
- 新增了传送门teleport 组件
- template模版可以不包在一个根div 中
- 新增watchEffect
- shallowReactive 只在第一次加监听
- shallowReadonly
原理方面:
-
object.defineProperty 改成 proxy ,解决数组无法通过下标修改,无法监听到对象属性新增修改删除问题。提高响应书效率
-
vue3 并没有完全抛弃 defineProperty ,ref 是通过 defineProperty 去给一个空对象,定义的一个value属性来做响应式
reactive 是通过 proxy包装出来的
-
组合式API 的写法,源码改成了函数式编程,方便按需引入
-
性能优化,增加了静态节点标记。会标记静态节点,diff对比不对静态节点做对比,从而增加效率
- 标记策略:对动态的值加上标记,值标1,动态class 标记2
进阶方面:
-
vue3 不推荐使用mixin 进行复用逻辑提取,而是推荐使用hook
-
v-model 应用与组件时,监听的事件和传递的值改变
- vue2 中 value 监听 change/input 事件
- Vue3 中自定义事件 modelValue 监听update:modelValue
-
Ts 更好的配合
vue v-show v-if 理解
v-if 直接操作的DOM(v-show
隐藏则是为该元素添加css--display:none
,dom
元素依旧还在。v-if
显示隐藏是将dom
元素整个添加或删除)
v-if 触发生命周期: 由false
变为true
的时候,触发组件的beforeCreate
、create
、beforeMount
、mounted
钩子
由true
变为false
的时候触发组件的beforeDestory
、destoryed
方法
v-if v-for 为什么不建议一起使用
v-for
优先级比v-if
高
- 永远不要把
v-if
和v-for
同时用在同一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断) - 在 vue 2.x 中,在一个元素上同时使用 v-if 和 v-for 时, v-for 会优先作用。 在 vue 3.x 中, v-if 总是优先于 v-for 生效
注意事项:
-
永远不要把
v-if
和v-for
同时用在同一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断) -
如果避免出现这种情况,则在外层嵌套
template
(页面渲染不生成dom
节点),在这一层进行v-if判断,然后在内部进行v-for循环<template v-**if**="isShow"> <p v-for="item in items"> </template>
-
如果条件出现在循环内部,可通过计算属性
computed
提前过滤掉那些不需要显示的项computed: { items: function() { return this.list.filter(function (item) { return item.isShow }) } }
SPA 手屏加载速度慢怎么解决
-
什么是首屏加载
指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容
-
首屏加载出现的原因
- 网络延时问题
- 资源是否重复发送请求去加载了
- 资源文件体积是否过大
- 加载脚本的时候,渲染内容堵塞了
-
解决方案
常见的几种SPA首屏优化方式
-
静态资源本地缓存
-
减小入口文件积
-
UI框架按需加载
-
图片资源的压缩
-
组件重复打包
-
开启GZip压缩
-
使用SSR
减少入口文件体积
常用的手段是路由懒加载,把不同路由对应的组件分割成不同的代码块,待路由被请求的时候会单独打包路由,使得入口文件变小,加载速度大大增加
在vue-router
配置路由的时候,采用动态加载路由的形式
以函数的形式加载路由,这样就可以把各自的路由文件分别打包,只有在解析给定的路由时,才会加载路由组件
routes:[ path: 'Blogs', name: 'ShowBlogs', component: () => import('./components/ShowBlogs.vue') ]
静态资源本地缓存
后端返回资源问题:
- 采用
HTTP
缓存,设置Cache-Control
,Last-Modified
,Etag
等响应头 - 采用
Service Worker
离线缓存
前端合理利用localStorage
UI框架按需加载
在日常使用UI
框架,例如element-UI
、或者antd
,我们经常性直接引用整个UI
库
import ElementUI from 'element-ui' Vue.use(ElementUI)
但实际上我用到的组件只有按钮,分页,表格,输入与警告 所以我们要按需引用
import { Button, Input, Pagination, Table, TableColumn, MessageBox } from 'element-ui';
Vue.use(Button)
Vue.use(Input)
Vue.use(Pagination)
或者
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import router from './router'
import { Button,Row,DatePicker } from 'element-ui';
Vue.config.productionTip = false
Vue.use(VueRouter)
Vue.component(Button.name,Button)
Vue.component(Row.name,Row)
Vue.component(DatePicker.name,DatePicker)
new Vue({
render: h => h(App),
router
}).$mount('#app')
组件重复打包
假设A.js
文件是一个常用的库,现在有多个路由使用了A.js
文件,这就造成了重复下载
解决方案:在webpack
的config
文件中,修改CommonsChunkPlugin
的配置
minChunks: 3
minChunks
为3表示会把使用3次及以上的包抽离出来,放进公共依赖文件,避免了重复加载组件
图片资源的压缩
对页面上使用到的icon
,可以使用在线字体图标,或者雪碧图,将众多小图标合并到同一张图上,用以减轻http
请求压力。
开启GZip压缩
使用SSR
SSR(Server side ),也就是服务端渲染,组件或页面通过服务器生成html字符串,再发送到浏览器
从头搭建一个服务端渲染是很复杂的,vue
应用建议使用Nuxt.js
实现服务端渲染
为什么data属性是一个函数不是对象
组件实例对象data
必须为函数,目的是为了防止多个组件实例对象之间共用一个data
,产生数据污染。
采用函数的形式,initData
时会将其作为工厂函数都会返回全新data
对象
vue组件中添加新属性不刷新
vue history模式下刷新404及上线后的代理问题
vue.config.js设置 publicPath、historyApiFallback
但是上线后,问题又来了
怎么办?只需在nginx.conf中添加参数配置即可。
location / {
try_files $uri $uri/ /index.html$args;
}
修改完配置文件后记得配置的更新
nginx -s reload
原因分析
产生问题的本质是因为我们的路由是通过JS来执行视图切换的,
当我们进入到子路由时刷新页面,web容器没有相对应的页面此时会出现404
所以我们只需要配置将任意页面都重定向到 index.html,把路由交由前端处理
配置proxy后导致页面报错
很多小伙伴上线后配置了跨域代理,但是发现接口返回的并不是想要的数据,还是大块的html,这时候大部分情况下是因为proxy参数没配好导致的。
'/api': {
//这里最好有一个 /
target: 'https://api.thecatapi.com/v1/', // 线上服务器端接口地址
ws: false, //如果要代理 websockets,配置这个参数
// 如果是https接口,需要配置这个参数
changeOrigin: true, //是否跨域
historyApiFallback: {
index: '/index.html', // 与output的publicPath
},
pathRewrite: {
'^/api': '/',
},
},
},
————————————————
版权声明:本文为CSDN博主「Boriska1996」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/RequesToGod/article/details/126284395
使用代理,首先需要有一个标识,告诉程序这个连接要使用代理,不然的话,可能你的html、css、js、矢量图等静态资源都跑去代理,从而导致返回的是一个html,而不是你想要的数据。所以我们要通过一个唯一标识,让接口使用代理,静态资源文件使用本地。 proxy中的 ‘/api’:{······},就是告诉node,我的接口是要以 /api 开头的才使用代理。所有的接口都要写成 /api/xx/xx ,以 /api 开头,最后代理的接口路径路径就是 http://localhost:8080/api/xx/xx
Element-ui 二次封装 怎么全局用,不全局怎么单独引用
全局引入
(1)在入口文件main.js引入所有自定义封装的组件
通过 import 引入全局组件,注意引入的路径一定要正确
import Button from './components/button'
// 注册全局组件
Vue.component('button', Button)
// 第一个参数 全局组件的名字(字符串类型),第二个参数:哪一个组件(引入的组件名)
局部引入
引入时的名字 一般都与组件名保持一致,components的写的就是书写组件的标签
import Button from '@/components/button'
export default {
components: {
Button
},
}
Element-ui 全局引入,部分引入
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
部分引入
// 在Script标签中导入Button组件
import { Button } from 'element-ui'
export default {
components: {
'el-button': Button
}
}
生命周期
数据请求在created和mouted的区别
created
是在组件实例一旦创建完成的时候立刻调用,这时候页面dom
节点并未生成;mounted
是在页面dom
节点渲染完毕之后就立刻执行的。触发时机上created
是比mounted
要更早的,两者的相同点:都能拿到实例对象的属性和方法。 讨论这个问题本质就是触发的时机,放在mounted
中的请求有可能导致页面闪动(因为此时页面dom
结构已经生成),但如果在页面加载前完成请求,则不会出现此情况。建议对页面内容的改动放在created
生命周期当中。
通信方式
- 父子组件:
props
/$emit
/$parent
/ref
- 兄弟组件:
$parent
/eventbus
/vuex
- 跨层级关系:
eventbus
/vuex
/provide+inject
/$attrs + $listeners
/$root
小结
- 父子关系的组件数据传递选择
props
与$emit
进行传递,也可选择ref
- 兄弟关系的组件数据传递可选择
$bus
,其次可以选择$parent
进行传递 - 祖先与后代组件数据传递可选择
attrs
与listeners
或者Provide
与Inject
- 复杂关系的组件数据传递可以通过
vuex
存放共享的变量
缓存
Vue 2 是 路由包着 keep-alives
Vue3 是keep-alive 包着路由
include 缓存哪些路由地址 ; exclude 不缓存哪些
watch 原理
watch
本质上是为每个监听属性 setter
创建了一个 watcher
,当被监听的属性更新时,调用传入的回调函数。常见的配置选项有 deep
和 immediate
,对应原理如下
deep
:深度监听对象,为对象的每一个属性创建一个watcher
,从而确保对象的每一个属性更新时都会触发传入的回调函数。主要原因在于对象属于引用类型,单个属性的更新并不会触发对象setter
,因此引入deep
能够很好地解决监听对象的问题。同时也会引入判断机制,确保在多个属性更新时回调函数仅触发一次,避免性能浪费。immediate
:在初始化时直接调用回调函数,可以通过在created
阶段手动调用回调函数实现相同的效果
v-model 的原理
- text 和 textarea 元素使用 value 属性和 input 事件;
- checkbox 和 radio 使用 checked 属性和 change 事件;
- select 字段将 value 作为 prop 并将 change 作为事件。
v-for vi-if
vue2 v-for>v-if
Vue3 v-if>v-for
nextTick 原理
为什么Vue采用异步渲染
核心是nextTick
vue 3
选项式 组件式区别
逻辑组织上2偏碎片化,3将逻辑关注点都放一个函数里
逻辑复用上,hooks取代mixin 命名冲突,数据来源不明
Tree-shaking 代码压缩
见不到this 使用,减少this 指向不明情况
Vue3 性能上提升
-
编译阶段
-
diff 优化----增加了
静态标记
,在会发生变化处添加标记,下次发生变化直接找到该地方 -
静态提升----不参与更新的元素做静态提升,只会被创建一次,在渲染时直接复用。
做了静态提示后,被放置render函数外,每次直接取出。该元素被打上静态标记-1。负数代表永远不会diff
-
事件监听缓存
- 没开启事件监听器缓存,默认情况绑定事件被视为动态绑定,开启缓存后没有了静态标记,diff算法时直接用
-
ssr优化 ----当静态内容一定量级时会用createStaticVNode方法在客户端生成一个static node ,这些静态node 会被直接 innerHtml,就不需要创建对象,然后根据对象渲染
-
-
源码体积
- Tree shanking 。没用到的函数变量模块等,会被摇掉,打包整体体积变小
-
响应式系统
- proxy Reflect 结合对整个对象进行监听
vue3 treeShanking 特性
清楚多余代码优化打包体积
如何做的?基于es6 import export.主要是es6 的模块的静态编译思想,在编译时就能确定依赖关系,以及输入输出
好处?体积小,执行快,
vue3 新特性有哪些
-
性能提升
-
支持t s
-
新增组建式 setup()函数
-
新增组件
- fragment
- teleport
- Suspense 等待异步时渲染一些额外的内容,提高用户体验
-
Tree shaking 支持摇树优化
-
Custom Render API :自定义渲染器。实现DOM 的方式进行WebGL编程
vue3 升级了哪些重要功能
新的API:Vue3使用createApp方法来创建应用程序实例,并有新的组件注册和调用方法。
emits属性
生命周期
多个Fragment
移除 .sync
异步组件的写法
const Foo = defineAsyncComponent(() => import('./Foo.vue') )
vue3 生命周期有哪些变化
Setup 取代 beforeCreate Created
Setup onbeforeMounted onMounted onBeforeUpdate onUpdated onBeforeUmount onUnmounted onErrorCaptured onRenderTracked onRenderTriggered onActivated onDeactivated
watch watchEffect 区别
Watch 能访问改变前后的值,watchEffect只能获取改变后的值
Watch不会立即执行,watchEffect会立即执行
watchEffect 有点像 computed
computed必写返回值重结果。watchEffect重过程可无返回值
setup 到底干啥的
Vue3 语法糖,属性,方法无需返回直接使用
引入组件自定注册,无需components手动注册
defineProps 接父组件传的值
useAttrs获取属性,useSlots获取插槽,defineEmits 获取自定义事件
默认不会对外暴露任何属性,如果有需要可使用defineExpose
vue3 通信方式
props
$emit
expose/ref
atrrs
V-model
Provide/inject(原理:原型链)
Vuex/pinia
Mitt
vue2 通信方式
props
$emit/v-on
.sync
v-model
ref
Children/parent
Attrs/listeners
Provide/inject
EventBus
Vuex
$root
Slot
ref 与 reactive 区别
Ref 可接受原始数据类型,引用类型
reactive 函数只能接受引用类型
Ref 底层还是 reactive
EventBus mitt 区别
优点 :
非常小,压缩后仅200 bytes
支持t s
跨框架 react。 JQ 等
使用简单仅有 on,emit,off 等少量实用API
谈谈pinia
优点:
更加轻量级 ,,压缩后提交只有1.6KB
源码全由TS编写完成
移除mutations ,只剩state, action ,getters
有store 概念,但都相互隔离的
无需手动添加每个store ,它的模块自定注册
支持服务端渲染SSR
更加优化的代码分割机制,传送门
setup 中如何获取组件实例
getCurrentInstance()
方法来获取组件实例。方法返回一个对象,对象里包含组件实例以及其他相关信息。
如何理解toRef toRefs
当我们从 setup
函数返回一个响应式对象时,对象的属性将失去响应式。为了防止这种情况,我们可以使用 toRefs
或 toRef
函数。
toRef :
Suspense
Suspense 组件允许你等待一个或多个异步组件,然后显示一些备用内容,直到所有的异步组件都被解析。
effect、reactive、ref
import { effect, reactive, ref } from 'vue'
// 使用 reactive
const state = reactive({ a: 1 })
effect(() => {
console.log(state.a)
})
state.a = 2 // 打印 "2"
// 使用 ref
const count = ref(0)
effect(() => {
console.log(count.value)
})
count.value++ // 打印 "1"
在这个示例中,我们创建了一个响应式对象和一个 ref,然后使用 effect
创建了两个副作用,它们分别打印出对象和 ref 的值。当这些值被改变时,副作用就会被触发。
render 函数
Render 函数的工作原理是通过返回一个虚拟节点(VNode)来告诉 Vue 如何渲染界面。Vue 3 提供了 h
函数用于创建 VNode。
import { h } from 'vue'
export default {
render() {
return h('div', {}, 'Hello, world!')
}
}