第三趴:vue框架进阶
2020/4/2 11:01:19
本文主要是介绍第三趴:vue框架进阶,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
整理中高级前端系列,可以当作面试复习,也可以当作实战来看,分享一下 方便自己,方便他人。有不足的地方欢迎评论~
MVC架构 (model、controller、view)
- View: 检测用户输入、操作(键盘、鼠标)行为,传递调用Controller执行对应逻辑。View更新需要重新获取 Model的数据。
- Controller:是View和Model 之间协作的应用层,负责业务逻辑处理。
- Model:数据层,数据变化后 通过观察者模式通知 View更新视图。
优点:
- 模块化:低耦合、可替换、可扩展性、可复用性强
- 多视图更新:使用观察者模式可以做到 单方Model通知多视图 实现数据更新
缺点:
- 依赖强:View和 Model 强依赖,很难抽离成 组件化
MVVM框架核心原理
图上可以看到,view通过viewmodel 的DOM Listeners 将事件绑定到 Model上,而Model则通过 Data Bindings来管理View中的数据,View-Model从中起到一个连接桥的作用。双向数据绑定(响应式)原理
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
Vue实现这种数据双向绑定的效果,需要三大模块:
- Observer:能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
- Compile:对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
- Watcher:作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
Vue全家桶
组件深入( 组件通信、生命周期 )
- 使用 kebab-case my-component-name 或者 MyComponentName
组件通信:
- 父子之间:props ----- $emit
- this.refs.xxx.属性/方法:父组件里直接获取子组件 方法和属性
- eventBus模式:新建Vue事件bus对象,然后通过 bus.on监听触发事件。
脚手架的 使用
Vue Loader
这个插件是必须的! 将你定义过的其他规则赋址并应用到 .vue文件里相应语言的块。例如:你有一条匹配/\.js$/
的规则,那么它会应用到 .vue文件里的 <script>
块
路由 原理
HashHistory:利用URL中的 hash("#")
- hash是用来指导浏览器动作的,对服务器端完全无用,因此 改变hash不会重新加载页面。
- 可以为 hash 的改变添加监听事件:
window.addEventListener("hashchange", funcRef, false)
- 每次改变
hash(window.location.hash)
都会在浏览器的访问历史中增加一个记录
利用这几点特性,就可以实现前端路由 【更新视图但不重新请求页面】的功能了
HashHistory.push()
从设置路由改变到视图更新的流程如下:
$router.push() --> HashHistory.push() --> History.transitionTo() --> History.updateRoute() --> {app._route = route} --> vm.render()
HashHistory.replace()
其实和push()类似,不同就是 替换掉当前路由,调用的是window.location.replace方法。
HTML5History:
利用HTML5中新增的方法pushState\replaceState
- pushState() 、replaceState()使得我们可以对浏览器历史记录栈进行修改
window.history.pushState(stateObject, title, URL) window.history.replaceState(stateObject, title, URL) 复制代码
实现原理:代码结构以及更新视图的逻辑与hash模式基本类似,只不过将对window.location.hash
直接进行赋值window.location.replace()
,改为了调用history.pushState()和history.replaceState()
方法。
非浏览器环境准备了一个abstract模式 (没使用过 可百度)
vuex 原理
state: 存储数据(相当于 data)
我们设置在state中的属性会被存储在根元素中,
this._modules = new ModuleCollection(options)
//初始化
const state = this._modules.root.state
// 获取定义的state
vuex初始化时先去获取定义在state属性的值 new ModuleCollection(options)
进行模块收集(重新组装 store中的相关属性),最终形成一颗module树。
getter:获取store属性方法 (相当于 computed)
mutations: 更改store中状态的唯一方法就是 提交 mutation,类似于调用事件(methods)
视图通过点击事件,触发 mutattions中的方法,可以更改state中的数据,此时 getters把数据反映到视图。
action: 提交 mutation 去变更状态
那么action 可以理解是 为了处理异步,单纯多加的一层。
dispatch、commit
在vue中 我们触发 click事件,就能触发 methods中的方法。但是 vuex就不行,一定要有个东西来触发才行,就相当于自定义事件on\emit。
关系就是,通过dispatch来触发actions中得方法,action中commi去触发mutions中方法。
Proxy与Object.defineProperty的优劣对比?
Proxy的优势:
- 可以直接监听对象而非属性
- 可以直接监听数组的变化
- Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而
Object.defineProperty
只能遍历对象属性直接修改 - 作为新标准会收到浏览器厂商重点持续的性能优化。
Object.defineProperty的优势如下:
虚拟dom原理
Virtual DOM是对DOM的抽象,本质上是JavaScript对象,这个对象就是更加轻量级的对DOM的描述.
出发点
Virtual DOM最初的目的,就是更好的跨平台,比如Node.js就没有DOM,如果想实现SSR(服务端渲染),那么一个方式就是借助Virtual DOM,因为Virtual DOM本身是JavaScript对象.
主流
现代前端框架的一个基本要求就是无须手动操作DOM, 一方面是因为手动操作DOM无法保证程序性能,多人协作的项目中如果review不严格,可能会有开发者写出性能较低的代码, 另一方面更重要的是省略手动DOM操作可以大大提高开发效率.
实现流程
1、需要一个**函数创建单个Virtual DOM **,这个函数很简单,接受一定的参数,再根据这些参数返回一个对象,这个对象就是DOM的抽象.
/** * 生成 vnode * @param {String} type 类型,如 'div' * @param {String} key key vnode的唯一id * @param {Object} data data,包括属性,事件等等 * @param {Array} children 子 vnode * @param {String} text 文本 * @param {Element} elm 对应的 dom * @return {Object} vnode */ function vnode(type, key, data, children, text, elm) { const element = { __type: VNODE_TYPE, type, key, data, children, text, elm } return element } 复制代码
2、DOM其实是一个Tree,我们接下来要做的就是声明一个函数用于创建DOM Tree的抽象 -- Virtual DOM Tree.
3、Virtual DOM 归根到底是JavaScript对象,我们得想办法将Virtual DOM与真实的DOM对应起来,也就是说,需要我们声明一个函数,此函数可以将vnode转化为真实DOM.
4、Virtual DOM 的 diff才是整个Virtual DOM 中最难理解也最核心的部分,diff的目的就是比较新旧Virtual DOM Tree找出差异并更新.
Virtual DOM的优化
snabbdom.js已经是社区内主流的Virtual DOM实现了**,vue 2.0阶段与snabbdom.js一样**都采用了上面讲解的 「双端比较算法」,那么有没有一些优化方案可以使其更快?
其实,社区内有更快的算法,例如inferno.js就号称最快react-like框架(虽然inferno.js性能强悍的原因不仅仅是算法,但是其diff算法的确是目前最快的),而vue 3.0就会借鉴inferno.js的算法进行优化.
Vue中的key到底有什么用?
diff算法的过程中,先会进行新旧节点的首尾交叉对比,当无法匹配的时候会用新节点的key
与旧节点进行比对,然后超出差异.
快速: key的唯一性可以被Map数据结构充分利用,相比于遍历查找的时间复杂度O(n),Map的时间复杂度仅仅为O(1).
$nextTick的原理
将回调延迟到下次DOM更新循环之后执行。在修改数据之后立即使用它,然后等待DOM更新。
<template> <div id="example">{{message}}</div> </template> <script> var vm = new Vue({ el: '##example', data: { message: '123' } }) vm.message = 'new message' // 更改数据 console.log(vm.$el.innerHTML) // '123' Vue.nextTick(function () { console.log(vm.$el.innerHTML) // 'new message' }) </script> 复制代码
在上面这个例子中,当我们通过vm.message = 'new message'
更新数据时,此时该组件不会立即重新渲染。当刷新事件队列时,组件会在下一个事件循环“tick”中重新渲染。所以当我们更新完数据后,此时又想基于更新后的DOM
状态来做点什么,此时我们就需要使用Vue.nextTick(callback)
,把基于更新后的DOM
状态所需要的操作放入回调函数callback
中,这样回调函数将在DOM
更新完成后被调用。
数据为什么频繁变化但只会更新一次
vue异步执行DOM更新
首屏加载性能优化
此点其实在说的是 白屏问题,白屏时间就是 当用户地址栏按下确认键开始到首次内容绘制(即看到第一个内容)。 所以 解决 白屏问题 才是关键 优化点。 ** 我们先梳理下白屏时间内发生了什么:
- 回车按下,浏览器解析网址,进行 DNS 查询,查询返回 IP,通过 IP 发出 HTTP(S) 请求
- 服务器返回HTML,浏览器开始解析 HTML,此时触发请求 js 和 css 资源
- js 被加载,开始执行 js,调用各种函数创建 DOM 并渲染到根节点,直到第一个可见元素产生
开启 HTTP2
- http2 的通信效率更高
- 可以进行多路复用
- http2 可以头部压缩,能够节省消息头占用的网络的流量
使用骨架屏
同学觉得有帮助的可以点个赞哈,以示鼓励 😊
这篇关于第三趴:vue框架进阶的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-04package.json 文件位置在哪?-icode9专业技术文章分享
- 2024-10-01Craco.js学习:从入门到实践指南
- 2024-10-01Create-React-App学习:入门与实践指南
- 2024-10-01CSS-in-JS学习:从入门到实践指南
- 2024-09-30JSX语法学习:从入门到初步掌握
- 2024-09-30Mock.js学习:入门教程与实战演练
- 2024-09-30React Hooks学习:从入门到实践
- 2024-09-30受控组件学习:React中的基础入门教程
- 2024-09-29JS定时器教程:初学者必看指南
- 2024-09-29JS对象教程:初学者的全面指南