vue
1、什么是虚拟DOM?
- 虚拟dom是react框架率先提出并使用的,后来在vue2.0中也引入了虚拟dom的概念。
- 简单来说,虚拟dom就是js对象来描述真实的dom结构
- 在虚拟dom出现之前,我们通过直接操作dom来达到视图更新的效果
- 有了虚拟dom之后,当数据发生改变时,我们通过diff算法找到新旧虚拟dom之间的差异,在最小的范围内来更新真实的dom结构,没有变化的节点则不需要再次渲染
2、什么是diff算法?
- vue中的diff算法只会进行同层比较,不会进行跨级比较
- 如果标签名不相同,则直接删除重建,不再深度比较
- 如果标签名和key都相同,则认为是相同节点,也不再深入比较
3.vue组件是如何渲染和更新的?
- 初次渲染的过程:
1 先解析template模板为render函数
2 在执行render函数时会触发响应式,监听data属性中的getter
3 然后执行render函数,生成vnode,然后再将虚拟dom转化为真实的dom渲染到页面上(patch(elem,vnode))
- 更新过程:
1 修改data,触发setter(此前在getter中已被监听)
2 重新执行render函数,生成newVnode
3 新旧虚拟dom使用diff算法找到最小的更新点,然后进行视图的更新 (patch(oldVnode,newVnode))
- 汇总:
首先vue组件中会有template模板和data数据,
开始渲染时,vue会解析template模板会render函数,
然后执行render函数生成虚拟dom树,
在执行render函数时会触发data属性中的getter,
一旦触发getter,vue就会进行依赖收集,把相应的data数据观察起来,
当数据发生改变后,就会触发setter,
被触发setter的数据在确认之前已经被观察过后,就会触发re-render,
也就是重新执行render函数,生成新的虚拟dom树,
然后新旧虚拟dom树通过diff算法进行对比,找到最小的差异点,然后进行视图的更新
4、vue-router
- 核心原理:通过改变url,在不重新请求页面的前提下,更新页面视图。
- 实现方式:Hash模式、History模式
- Hash模式下可以通过window.onhashchange来监听hash的改变
- history模式下可以使用history.pushState修改浏览器历史记录栈,使用window.onpopstate监听浏览器地址的前进、后退
5、为什么data函数是个对象
- .vue文件实质上是一个类(Class),使用组件时就相当于对类进行实例化。
- 如果data只是一个对象的话,所有该组件的实例都会共用一份data内存地址,就会造成一个变全变的结果。
- 而data是函数的话,数据以函数返回值的形式定义。这样每复用一个组件,就会返回一份新的data内存地址,每个组件的实例都可以拥有一个私有的数据空间,数据修改则不会相互影响
6、ajax请求应该放在哪个生命周期
- mounted
- js是单线程的,ajax是异步获取数据的;
- 所以放在mounted之前没有用,只会让逻辑更加混乱;
- 为了看起来逻辑的统一性,建议放在mounted中
7、何时需要beforeDestory
- 解除自定义事件 event.$off
- 清除定时器
- 解绑自定义的DOM事件,如window.scroll
8、vue常见性能优化方式
- 合理使用v-show和v-if
- 合理使用computed
- v-for时加key,避免和v-if同时使用(v-for优先级更高)
- 自定义事件、dom事件及时销毁
- 合理使用异步组件
- 合理使用keep-alive
- data层级不要太深
vue3
1、vue3比vue2有什么优势?
- 性能更好
- 体积更小
- 更好的ts支持
- 更好的代码组织
- 更好的逻辑抽离
- 更多新功能
1 createApp
2 emits属性
3 生命周期
4 多事件
5 fragment:在vue2的template模板中必须有一个根节点,vue3中则支持多个节点
6 移除.sync
7 异步组件写法
8 移除filter
9 新增teleport,可以使用teleport很方便的将组件放到body中
10 suspense:使用插槽封装了suspense组件
11 CompositionApi
2、vue3生命周期
setup, beforeCreate,created, beforeMount,mounted, beforeUpdate,updated, beforeUnmount, unmounted
3、composition API
- 具有更灵活的代码组织:
在选项式api中,处理相同逻辑关注点的代码被强制拆分在了不同的选项中,位于文件的不同部分。在一个几百行的大组件中,要读懂代码中的一个逻辑关注点,需要在文件中反复上下滚动。
而在组合式api中,相同逻辑的代码被归为一组,代码就不需要反复上下滚动查看。此外,也就可以轻松地将一组代码移动到一个外部文件中,大大降低了重构成本。
4、为何需要ref?
- 因为返回的值类型需要响应式
- 如在setup、computed、合成函数中,都有可能返回值类型
- vue如果不定义ref,用户将自造ref,就会更混乱
5、为何需要.value
- ref是一个对象,需要利用value属性存储值
- 通过.value 属性的get和set实现并保持响应式
- 用于模板、reactive时不需要.value,其他情况都需要
6、为何需要toRef和toRefs
- 针对的是reactive封装的响应式对象
- 目的是在不丢失响应式的前提下,把对象数据进行解构、分解
- 不创造响应式,而是延续响应式
7 vue3如何实现响应式
- vue2中Object.defineProperty的缺点:
1 对于多层级对象,需要深度监听,递归到底,一次性计算量很大
2 无法监听新增或删除的属性,所以vue2中才会有Vue.$set/vue.$delete
3 无法原生监听数组,需要重新定义数组原型,重写数组方法才能实现数组的监听
- vue3 使用proxy
1 深度监听,性能更好:
vue2中响应式是一次性监听完成,一开始就会通过递归监听对象每个层级的属性;
而vue3中只有在get到某个属性时才会递归,并且只会递归一层,里面的内容也只有遇到的时候才会把它包装成代理对象
2 可监听新增或删除的属性( deleteProperty)
3 可监听数组的变化
4 总之,能规避Object.defineProperty的问题,但是也有缺点,无法兼容所有浏览器,无法polyfill
<script>
function reactive(target = {}) {
// 如果不是对象或数组,则返回
if (typeof target !== 'object' || target == null) {
return target
}
const proxyConf = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
console.log('get', key, result)
// return result
// 深度监听,
// 性能提升: vue2中响应式是一次性监听完成,一开始就会通过递归监听对象每个层级的属性;
// 而vue3中只有在get到某个属性时才会递归,并且只会递归一层,里面的内容也只有遇到的时候才会把它包装成代理对象
return reactive(result)
},
set(target, key, val, receiver) {
// 判断是不是新增的属性:可以在set时判断key是不是原来的key集合中,此处可以用reflect.ownKeys获取到原来的所有key值
const ownKeys = Reflect.ownKeys(target)
if(ownKeys.includes(key)) {
console.log('已有的key')
} else {
console.log('新增的key')
}
// 直接支持新增属性
const result = Reflect.set(target, key, val, receiver)
console.log('set', key, val, result)
return result
},
deleteProperty(target, key) {
const result = Reflect.deleteProperty(target, key)
console.log('delete', result)
return result
}
}
const observed = new Proxy(target, proxyConf)
return observed
}
const data = {
name: 'zs',
age: 20,
info: {
city: 'bj'
}
}
// const data = ['a', 'b', 'c']
const proxyData = reactive(data)
// 数组的变化proxy原生就支持,
// 对象属性删除可以用proxy的deleteProperty
</script>
8.watch与watchEffect的区别
- 两者都可监听data属性的变化
- watch需要明确指出要监听的属性,而watchEffect会根据其中的属性自动监听其变化
- watchEffect初始化时一定会执行一次,因为要收集需要监听的数据;而watch只有设置了初始化监听才会监听
9 setup中如何获取组件的实例
- 在CompositionApi中没有this,通过getCurrentInstance获取当前实例
- 而在OptionsApi中照常使用this
10 vue3为什么比vue2快
- proxy响应式优化:
可以更好地监听数组的变化,也可以更好监听新增或删除的属性,
对于多层级需要深度监听的对象来说,
vue2中是一次性监听完成,一开始就会通过递归监听对象每个层级的属性;
而在vue3中,只有在get到某个属性时才会递归,并且只会递归一层,里面的内容也只有遇到的时候才会被包装成代理对象
- patchFlag,静态标记:
对动态节点做标记,如TEXT/PROPS,
这样做diff算法时就可以区分静态节点以及不同类型的动态节点,也就会更快一些
- hoistStatic
把静态节点提到父作用域缓存起来,多个相邻的静态节点会被合并到一起缓存起来
- cacheHandler
缓存事件,
- SSR 优化
在ssr输出时,静态节点不再走vdom的逻辑,而是直接输出字符串;
动态节点还是需要动态渲染
- tree-shaking
根据模板的内容动态从vue中import需要的内容