今日学习记录之vue3/vue2

1.vue2/vue3不同点

1.异步组件:
defineAsyncComponent
例如:
const asyncComponent = defineAsyncComponent(
()=> import('xxx.vue')
)

2.自定义指令
2.x语法
bind: 指令绑定到元素后发生,只发生一次。
inserted: 元素插入父DOM后发生。
update: 当元素更新,但子元素尚未更新时,将调用此钩子。
componentUpdated: 一旦组件和子级被更新,就会调用这个钩子。
unbind: 一旦指令被移除,就会调用这个钩子,只调用一次。
例如:
Vue.directive('highlight',{
bind(el, binding, vnode){
el.style.background = binding.value
}
})
<div v-highlight="'red'">字体颜色为红色</div>

3.x语法
const MyDirective = {
beforeMount(el, binding, vnode, prevVnode){},
mounted(){},
beforeUpdate(){},
updated(){},
beforeUnmount(){},
unmounted(){}
}
例如:
const app = Vue.createApp()
app.directive('highlight',{
beforeMount(el, binding, vnode){
el.style.background = binding.value
}
})

 2.vue3.0性能提升体现在哪些方面?

a.编译阶段
b.源码体积
c.响应式系统
vue2中采用defineProperty来劫持整个对象,然后进行深度遍历所有属性,给每个属性添加getter和setter,实现响应式。
vue3采用proxy重写了响应式系统,因为proxy可以对整个对象进行监听,所以不需要深度遍历就可以监听动态属性的添加,
数组的索引和数组的length属性以及监听删除属性。

proxy的监听针对一个对象,即对这个对象的所有操作会进入监听操作。
//定义一个响应式reactive函数
function reactive(obj){
if(typeof obj !== 'object' && obj != null){
return obj
}
const observed = new Proxy(obj, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver)
return isObject(res) ? reactive(res) : res;
}
})
return observed;
}
proxy直接可以劫持整个对象,并返回一个新对象。

3.vue2.0响应式原理

// 定义一个响应式函数 defineReactive
function update(){
app.content = obj.foo
}
function defineReactive(obj, key, val){
Object.defineProperty(obj, key, {
get(){
return val;
},
set(nv){
if(nv !== val){
val = nv;
update();
}
}
})
}
调用defineReactive,数据发生变化触发update方法,实现数据响应式。如果存在多个key,嵌套对象,则需要进行遍历,递归等操作。

Object.defineProperty 只能遍历对象属性进行劫持。

4.Treeshaking特性

Treeshaking 是一种通过清除多余代码方式来优化项目打包体积的技术。
即 在保持代码运行结果不变的前提下,去除无用的代码。

如何做:
Treeshaking 基于 es6 模板语法(import与export),借助es6模块的静态编译思想,在编译时就确定模块的依赖关系,
以及输入和输出的变量。
编译阶段利用es6 module判断哪些模块已经加载和判断那些模块和变量未被使用或者引用,进而删除对应代码。

作用:
减少程序体积,减少程序执行时间,便于对程序架构进行优化。

5.vue2中v-if和v-for使用时应注意什么?

注意点:
1.永远不要把 v-if 和 v-for 同时用在同一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断)。
2.如果避免出现这种情况,则在外层嵌套template(页面渲染不生成dom节点),在这一层进行v-if判断,然后在内部进行v-for循环。
3.如果条件出现在循环内部,可通过计算属性computed提前过滤掉那些不需要显示的项。

 

源码:genElement函数中在进行if判断的适合, v-for比v-if先进行判断,得出结论:v-for优先级高于v-if。

6.SPA首屏加载速度慢如何解决?

//解决方案
减小入口文件体积:
常用的手段是路由懒加载,把不同路由对应的组件分割成不同的代码块,待路由被请求的时候会单独打包路由,
使得入口文件变小,加载速度大大增加。及在vue-router配置路由的时候,采用动态加载路由的形式。
静态资源本地缓存:
合理利用localStorage。
ui框架按需加载;
图片资源的压缩:
对于所有的图片资源,我们可以进行适当的压缩
对页面上使用到的icon,可以使用在线字体图标,或者雪碧图,将众多小图标合并到同一张图上,用以减轻http请求压力。
    组件重复打包:
在webpack的config文件中,修改 CommonsChunkPlugin的配置。
例如:
minChunks: 2 //表示会把使用2次以上的包抽离出来,放进公共依赖文件,避免重复加载组件。
开启gzip压缩;
使用SSR。

7.vue2中data属性是一个函数而不是对象原因?

1.根实例对象data可以是对象也可以是函数(根实例是单例),不会产生数据污染情况。
2.组件实例对象data必须为函数,目的是为了防止多个组件实例对象之间共用一个data,产生数据污染。
采用函数的形式,initData时会将其作为工厂函数都会返回全新data对象。

8.vue2中给对象添加新属性界面不刷新,如何解决?

例如:
<div v-for="item in obj" :key="item">{{item}}</div>
<button @click="add">点击新增属性</button>
export default {
data(){
return {
obj: {
a: 'aa'
}
}
},
methods: {
add(){
this.obj.b = 'bb';
console.log(this.obj);//这里能输出所有属性,但是页面没有显示刚刚新增的b属性。
}
}
}
导致原因是:由于vue2采用的是Object.defineProperty实现数据响应式,obj的a属性被设成了响应式数据,而新增的b属性
没有通过Object.defineProperty设置成响应式数据。

解决方案:
Vue.set(target, propertyName/index, value),
Object.assign({}, this.obj,{b:1}...)//创建一个新对象,合并源对象和混入对象的属性。
$forceUpdated():使vue实例重新渲染。

注意: vue3用proxy实现数据响应式,直接动态添加新属性仍可以实现数据响应式。

9.组件和插件区别

组件: 在vue中每一个.vue文件都可以视为一个组件。

插件:通常为vue添加全局功能。
例如:
添加全局方法或者属性;添加全局资源(指令/过滤器/过渡等);通过全局混入来添加一些组件选项;
添加vue实例方法,通过把他们添加到vue.prototype上实现。

组件格式:
<template></template>
<script>
export default {}
</script>
<style></style>
插件格式:【应该暴露一个install方法。这个方法的第一个参数是vue构造器,
第二个参数是一个可选的选项对象。】
TestPlugin.install = function(Vue,options){
//添加全局方法或property
Vue.globalMethod = function(){}
//添加全局资源
Vue.directive('my-directive',{
bind(el, binding, vnode, oldVnode){}
})
...
}

组件注册:
import ComponentTest from '../xx.vue';
Vue.component('component-name', ComponentTest)
//or
export default {
components: { ComponentTest }
}
插件注册:
Vue.use(插件名字)

10.组件通信

vue中8种常规的通信方案:
通过props传递;
通过$emit触发自定义事件
使用ref;
EventBus;
$parent/$root;
$attrs与listeners;
provide与inject;
vuex;

组件关系:
1.父子组件
props/$emit 或者使用ref
2.兄弟组件
eventbus 或者 $parent
3.祖孙与后代组件
attrs/$listeners 或者 provide/inject
4非关系组件
vuex

11.双向绑定

Vue中的双向绑定流程是:

  1. new Vue()首先执行初始化,对data执行响应化处理,这个过程发生Observe
  2. 同时对模板执行编译,找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在Compile
  3. 同时定义⼀个更新函数和Watcher,将来对应数据变化时Watcher会调用更新函数
  4. 由于data的某个key在⼀个视图中可能出现多次,所以每个key都需要⼀个管家Dep来管理多个Watcher
  5. 将来data中数据⼀旦发生变化,会首先找到对应的Dep,通知所有Watcher执行更新函数

12.nextTick

定义: 在下次DOM更新循环结束之后执行延迟回调。【即:在修改数据之后立即使用这个方法,可以获取更新后的DOM结构】

例如:
//修改数据
this.msg = '修改了';
//DOM还没有更新
console.log(this.$refs.el.textContent);//原始的值
this.$nextTick(()=>{
//DOM更新了
console.log(this.$refs.el.textContent);//修改后的值
})

总结:把回调函数放入callbacks等待执行;将执行函数放到微任务或宏仁务中;
事件循环到了微任务或者宏仁务,执行函数依次执行callbacks中的回调。

13.vue2中mixin作用

定义:mixin提供了一种灵活的方式,来分发vue组件中的可复用功能。
本质其实就是一个js对象,可以包含你组件中任意功能选项,例如data,components,methods,created,computed等。

混入分为: 全局混入和局部混入

局部混入:
先定义一个mixin对象,里面包含data,methods, computed, created等属性。
组件通过 mixins属性调用mixin对象即可。

全局混入:
通过 Vue.mixin()进行全局混入。
Vue.mixin({
created(){},
})

14.vue2中slot作用

slot分为: 默认插槽, 具名插槽, 作用域插槽。

v-slot属性只能在template上使用,但只有默认插槽时可以在组件标签上使用。
默认插槽名为 default,可以省略default直接写v-slot。
缩写为#时不能不写参数,写成#default。
可以通过解构获取v-slot={user},还可以重命名v-slot="{user:newName}"和定义默认值v-slot="{user="默认值"}"。

15.vue2中key作用

key的作用:key是给每一个vnode唯一id,也是diff的一种优化策略,可以根据key,更准确,更快的找到对应的vnode节点。 

16.vue2中keep-alive作用

keep-alive是vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
keep-alive三个属性:
include: 只有名称匹配的组件会被缓存。
exclude: 任何名称匹配的组件都不会被缓存。
max: 最多可以缓存多少组件实例。

例如:
在路由配置中添加meta属性
meta: { keepAlive: true, title:'xx' }

<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>


缓存后如何获取数据:
1.beforeRouteEnter: 每次组件渲染时,都会执行beforeRoteEnter
2.actived: 在keep-alive缓存的组件被激活的时候,都会执行actived钩子。

17.vue2中常用修饰符

lazy: 表单修饰符, v-model.lazy
trim:自动过滤用户输入的空格, v-model.trim
number: 自动将用户的输入值转为数值类型,v-model.number

事件修饰符:
.stop 阻止事件冒泡
.prevent 阻止事件的默认行为
.self 将事件绑定在自身,相当于阻止事件冒泡。当在event.target 是当前元素自身时触发处理函数。
.once 绑定事件以后只能触发一次。
.capture 使事件触发从包含这个元素的顶层开始往下触发
.passive 不想阻止事件的默认行为。
.native 绑定原生事件。

18.vue2中自定义指令

指令分为全局注册和局部注册。

全局注册通过 Vue.directive 方法进行注册。
Vue.directive('focus',{
bind(){},
inserted(el){
el.focus();
},
update(){},
componentUpdated(){},
unbind(){},
})

局部注册: 通过在组件options选项中设置 directive属性即可。
directives: {
focus: {
inserted:function(el){
el.focus()
}
}
}

19.vue2中过滤器

vue允许自定义过滤器,用于一些常见的文本格式化。
注意:vue3已废弃filter。

全局过滤器:
Vue.filter('filter_name', function(value){
//...
})
局部过滤器:
filters:{
filterName:function(value){
//...
}
}

20.vue2中虚拟DOM?

createElement创建VNode的过程,每个VNode有children,children每个元素也是一个VNode,这样就形成了一个虚拟结构,用于
描述真实的DOM树结构。

即它是一层对真实DOM的抽象,以js对象作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上。

21.vue2中的diff算法

diff算法两个特点:
1.比较只会在同层级进行,不会跨层级比较;
2.在diff比较的过程中,循环从两边向中间比较。

当数据发生改变时,set方法会调用Dep.notify通知所有订阅者watcher,订阅者就会调用patch给真实的DOM打补丁,更新相应视图。

22.axios封装

封装axios时需要考虑哪些问题:
1.设置即可请求前缀,分开发,测试,生成环境
2.请求头携带token参数与超时时间等
3.状态码,根据接口返回不同的status,执行不同的业务。
4.请求方法
5.请求拦截器
6.响应拦截器

23.SSR

SSR解决方案,后端渲染出完整的首屏dom结构返回,前端拿到的内容包括首屏及完整spa结构,应用激活后依然按照spa方式运行。

 

posted on 2022-10-10 11:32  有匪  阅读(67)  评论(0编辑  收藏  举报

导航