vue数据响应式实现
使用Object.defineProperty
和ES6的Proxy
,这就是进行数据劫持或数据代理。vue3使用的第二种,之前版本使用第一种。Object.defineProperty
Vue通过设定对象属性的 setter/getter
方法来监听数据的变化,通过getter
进行依赖收集,而每个setter
方法就是一个观察者
,在数据变更
的时候通知订阅者
更新视图。
该方式存在的问题:无法观察到对象属性的新增或者删除,array的push和shfit是可以观察到的,因为vue对数组的方法做了特殊的处理。Proxy
支持完整的对象的变化观察,缺点就是兼容性不是很好。
参考文章:vue响应式详解
vue的生命周期
beforeCreate->created->beforeMount->mounted->beforeUpdate->updated->beforeDestroy->destroyed
**
vue的通行方式
- props父组件传参至子组件
- $emit()子组件发事件至父组件
- $parent组件直接调用父组件实例
- $children子组件直接调用父组件
- ref挂在实例,调用组件实例
- Event Bus 实现跨组件通信: Vue.prototype.$bus = new Vue ,bus.$on监听事件,bus.$emit()发送事件,便于全局跨组件事件通信
- attrs,listeners 一般用于封装组件的集成父组件参数和事件
- Provide、inject一般用于封装组件中夫子组件参数的共享
vue路由原理
vue-router 有 3 种路由模式:hash、history、abstract
,前两种浏览器使用,最后一种node使用
hash模式
location.hash获取的就是url中#后面的部分
- URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,
hash 部分不会被发送
; - hash 值的改变,都会在浏览器的访问历史中
增加一个记录
。因此我们能通过浏览器的回退、前进按钮控制hash 的切换; - 可以通过 a 标签,并设置 href 属性,当用户点击这个标签后,URL 的 hash 值会发生改变;或者使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值;
- 我们可以使用
hashchange
事件来监听 hash 值的变化,从而对页面进行跳转(渲染)
history模式
HTML5 提供了 History API 来实现 URL 的变化。其中做最主要的 API 有以下两个:history.pushState()
和 history.repalceState()
。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史纪录
。唯一不同的是,前者是新增
一个历史记录,后者是直接替换
当前的历史记录,如下所示:
window.history.pushState(null, null, path);
window.history.replaceState(null, null, path);
history 路由模式的实现主要基于存在下面几个特性:
- pushState 和 repalceState 两个 API 来操作实现 URL 的变化 ;
- 我们可以使用 popstate 事件来监听 url 的变化,从而对页面进行跳转(渲染);
- history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面跳转(渲染)。
Webpack 层面的优化
- Webpack 对图片进行压缩———-先引入npm install image-webpack-loader —save-dev,然后在 webpack.config.js 中配置
- 减少 ES6 转为 ES5 的冗余代码
- 提取公共代码
- 模板预编译
- 提取组件的 CSS
- 优化 SourceMap
- 构建结果输出分析
- Vue 项目的编译优化
keep-alive
keep-alive会缓存包裹组件的vnode,keep-alive作为父组件,缓存包裹的子组件vnode,在需要渲染的时候,再把对应的vnode渲染,就可以保存当前页面的状态了。
- 提供
include
和exclude
属性,两者都支持字符串或正则表达式, include 表示只有名称匹配
的组件会被缓存
,exclude 表示任何名称匹配的组件都不会被缓存
,其中 exclude 的优先级
比 include 高; - 对应两个钩子函数
activated
和deactivated
,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。
监听子组件生命周期
@hook
<Child @hook:mounted="doSomething" ></Child>
Vue2.x和Vue3.x渲染器的diff算法分别说一下
简单来说,diff算法有以下过程
同级比较, 再比较子节点,先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除),
比较都有子节点的情况(核心diff)递归比较子节点
正常·Diff两个树·的时间复杂度是O(n^3),但实际情况下我们很少会进行跨层级的移动DOM,所以Vue将Diff进行了优化,从O(n^3) -> O(n),只有当新旧children都为多个子节点
时才需要用核心的Diff算法进行同层级比较
。
Vue2的核心Diff算法采用了双端比较
的算法,同时从新旧children的两端
开始进行比较,借助key值找到可复用
的节点,再进行相关操作。相比React的Diff算法,同样情况下可以减少移动节点次数,减少不必要的性能损耗,更加的优雅。
_Vue3.x借鉴了_ivi算法和 inferno算法 在创建VNode时就确定其类型,以及在mount/patch的过程中采用位运算来判断一个VNode的类型,在这个基础之上再配合核心的Diff算法,使得性能上较Vue2.x有了提升。 该算法中还运用了动态规划的思想求解最长递归子序列。
移动端高分屏1px问题
https://juejin.cn/post/6844903877947424782
JavaScript原理题
https://juejin.cn/post/6844903891591495693#heading-6