vue全家桶
2020-06-05 14:37:26 5 举报
AI智能生成
前端面试 vue
作者其他创作
大纲/内容
Vue常考基础知识点
生命周期钩子函数
beforeCreate
<font color="#c41230">获取不到 props 或者 data 中的数据</font>的,因为这些数据的初始化都在 initState 中<br>在当前阶段<font color="#c41230">data、methods、computed以及watch上的数据和方法都不能被访问</font><br>
created
可以<font color="#c41230">访问到之前不能访问到的数据</font>,<br>实例已经完成数据观测, 属性和方法的运算, watch/event事件回调. <br>但是这时候<font color="#c41230">组件还没被挂载</font>,所以是<font color="#c41230">看不到</font>的<br><font color="#c41230">可以做一些初始数据的获取</font>,在当前阶段无法与Dom进行交互,如果非要想,可以通过vm.$nextTick来访问Dom<br>
beforeMount
当前阶段<font color="#c41230">虚拟Dom已经创建完成</font>,即将开始渲染<font color="#c41230"><br></font>
mounted
<font color="#c41230">将 VDOM 渲染为真实 DOM 并且渲染数据</font><br>组件中如果有子组件的话,会递归挂载子组件,只有当所有子组件全部挂载完毕,才会执行根组件的挂载钩子。<font color="#f384ae"><br></font>
mounted在<font color="#c41230">挂载完成</font>后发生,<br>在当前阶段,真实的Dom挂载完毕,<font color="#c41230">数据完成双向绑定,可以访问到Dom节点</font>,<font color="#c41230">使用$refs属性对Dom进行操作</font>
beforeUpdate<br>
发生在更新之前,也就是响应式数据发生更新,虚拟dom重新渲染之前被触发,<br>你可以在当前阶段进行更改数据,不会造成重渲染
updated
发生在更新完成之后,当前阶段组件Dom已完成更新。<br>要注意的是避<font color="#c41230">免在此期间更改数据,因为这可能会导致无限循环的更新</font>
activated<br><br>deactivated<br>
<font color="#c41230">keep-alive 独有</font>的生命周期
用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,<br>命中缓存渲染后会执行 actived 钩子函数
beforeDestroy
<font color="#c41230">移除事件、定时器</font>等等,<font color="#c41230">否则可能会引起内存泄露的问题</font><br>然后进行一系列的销毁操作,如果有子组件的话,也会递归销毁子组件,<br>所有子组件都销毁完毕后才会执行根组件的 destroyed 钩子函数。<br>
destroyed
组件生命周期调用顺序
组件的<font color="#c41230">调用顺序</font>都是<font color="#c41230">先父后子</font>,<font color="#c41230">渲染完成</font>的顺序是<font color="#c41230">先子后父</font>。<br><br>组件的<font color="#c41230">销毁操作</font>是<font color="#c41230">先父后子</font>,<font color="#c41230">销毁完成</font>的顺序是<font color="#c41230">先子后父</font>
<font color="#c41230">加载渲染过程</font>
<font color="#c41230">父beforeCreate->父created->父beforeMount-><br>子beforeCreate->子created->子beforeMount- >子mounted-><br>父mounted</font>
子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程
父 beforeUpdate -> 父 updated
销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
组件通信
父子通信
最典型的方法
父->子
<font color="#c41230">props</font>,父组件通过 props 传递数据给子组件
子->父
<font color="#c41230">$on、$emit</font>
子组件通过 <font color="#c41230">emit</font><font color="#f384ae"> </font>发送事件传递数据给父组件
这种父子通信方式也就是典型的<font color="#c41230">单向数据流</font>
<font color="#c41230">$parent 或者 $children</font>
可以通过<font color="#c41230">访问 $parent 或者 $children 对象</font>来访问组件实例中的方法和数据
$listeners 和 .sync
兄弟组件通信<br>
对于这种情况可以通过查找父组件中的子组件实现,也就是<font color="#c41230"> this.$parent.$children</font>,<br>在 $children 中可以通过<font color="#c41230">组件 name</font> 查询到需要的组件实例,然后进行通信
跨多层级组件通信
<font color="#c41230">provide / inject</font>
任意组件
Vuex
Event Bus
就是创建一个<font color="#c41230">事件中心</font>,相当于中转站,可以用它来传递事件和接收事件。<br><font color="#c41230">项目比较小时</font>,用这个比较<font color="#c41230">合适</font>
Vue.prototype.$bus = new Vue
mixin 和 mixins 区别
mixin
<font color="#c41230">mixin 用于全局混入</font>,<font color="#c41230">会影响到每个组件实例</font>,通常插件都是这样做初始化的。
虽然文档不建议我们在应用中直接使用 mixin,但是如果不滥用的话也是很有帮助的,<br>比如可以<font color="#c41230">全局混入封装好的 ajax 或者一些工具函数</font>等等。
mixins
mixins 应该是我们最常使用的<font color="#c41230">扩展组件</font>的方式了。<br>如果多个组件中有<font color="#c41230">相同的业务逻辑</font>,就可以将这些逻辑<font color="#c41230">剥离</font>出来,<br>通过 mixins 混入代码,比如上拉下拉加载数据这种逻辑等等。
需要注意的是 mixins 混入的钩子函数会先于组件内的钩子函数执行,<br>并且在遇到同名选项的时候也会有选择性的进行合并
computed 和 watch 区别
computed 是计算属性,依赖其他属性计算值,<br>并且 computed 的值<font color="#c41230">有缓存</font>,<font color="#c41230">只有当计算值变化才会返回内容</font>。
<font color="#c41230">watch 监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作</font>。
所以一般来说<font color="#c41230">需要依赖别的属性来动态获得值</font>的时候可以使用 computed,<br>对于<font color="#c41230">监听到值的变化需要做一些复杂业务逻辑的情况可以使用 watch</font>。
keep-alive 组件有什么作用
如果你需要在<font color="#c41230">组件切换</font>的时候,<font color="#c41230">保存</font>一些<font color="#c41230">组件</font>的<font color="#c41230">状态防止多次渲染</font>,就可以使用 keep-alive 组件包裹需要保存的组件。<br><br>对于 keep-alive 组件来说,它拥有两个独有的生命周期钩子函数,分别为<font color="#c41230"> activated 和 deactivated</font> 。<br><font color="#c41230">用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,命中缓存渲染后会执行 actived 钩子函数</font>。
v-show 与 v-if 区别
v-show 只是在<font color="#c41230"> display: none 和 display: block 之间切换</font>。<br>无论初始条件是什么都会被渲染出来,后面只需要切换 CSS,DOM 还是一直保留着的。<br>所以总的来说 v-show <font color="#c41230">在初始渲染时有更高的开销,但是切换开销很小,更适合于频繁切换的场景</font>。
v-if 的话就得说到 Vue 底层的编译了。<br>当属性初始为 false 时,组件就不会被渲染,直到条件为 true,并且切换条件时会触发销毁/挂载组件,<br>所以总的来说在<font color="#c41230">切换时开销更高,更适合不经常切换的场景</font><br>并且基于 v-if 的这种惰性渲染机制,可以在必要的时候才去渲染组件,减少整个页面的初始渲染开销。<br>
组件中 data 什么时候可以使用对象
为什么把data写成函数
<font color="#c41230">组件复用时所有组件实例都会共享 data</font>,<br>如果 data 是对象的话,就会造成一个组件修改 data 以后会影响到其他所有组件,<br>所以需要将 data 写成函数,每次用到就调用一次函数获得新的数据。<br>
什么时候可以把data写成对象
当我们使用 new Vue() 的方式的时候,无论我们将 data 设置为对象还是函数都是可以的,<br>因为 <font color="#c41230">new Vue() 的方式是生成一个根组件,该组件不会复用,也就不存在共享 data 的情况</font>了。
Vue 常考进阶知识点
响应式原理
监听数据的 set 和 get 的事件
Vue 内部使用了 Object.defineProperty() 来实现数据响应式,通过这个函数可以监听到 set 和 get 的事件
数据劫持
以上代码简单的实现了如何监听数据的 set 和 get 的事件,但是仅仅如此是不够的,因为自定义的函数一开始是不会执行的。<br>只有先执行了依赖收集,才能在属性更新的时候派发更新,所以接下来我们需要先触发依赖收集。
依赖收集
<div><br> {{name}}<br></div>
在解析如上模板代码时,遇到 {{name}} 就会进行依赖收集。
实现一个 Dep 类,<br>用于<font color="#c41230">解耦属性的依赖收集和派发更新操</font>作
以上的代码实现很简单,当需要依赖收集的时候调用 addSub,当需要派发更新的时候调用 notify。
接下来我们先来简单的了解下<font color="#c41230"> Vue 组件挂载时添加响应式的过程。<br>在组件挂载时,会先对所有需要的属性调用 Object.defineProperty(),然后实例化 Watcher,传入组件更新的回调。<br>在实例化过程中,会对模板中的属性进行求值,触发依赖收集</font>。
触发依赖收集时的操作
因为这一小节主要目的是学习响应式原理的细节,所以接下来的代码会简略的表达触发依赖收集时的操作。
以上就是 Watcher 的简单实现,在执行构造函数的时候将 Dep.target 指向自身,从而使得收集到了对应的 Watcher,<br>在派发更新的时候取出对应的 Watcher 然后执行 update 函数。
接下来,需要对 defineReactive 函数进行改造,<br>在自定义函数中添加依赖收集和派发更新相关的代码。
以上所有代码实现了一个简易的数据响应式,核心思路就是手动触发一次属性的 getter 来实现依赖收集。
Object.defineProperty 的缺陷
缺陷
通过<font color="#c41230">下标方式修改数组数据</font>或者<font color="#c41230">给对象新增属性</font>并不会触发组件的重新渲染
产生这写缺陷的原因
<font color="#c41230">因为 Object.defineProperty 不能拦截到这些操作</font>,<br><font color="#c41230">更精确的来说,对于数组而言,大部分操作都是拦截不到的,只是 Vue 内部通过重写函数的方式解决了这个问题</font>
怎么解决
Vue 提供了一个 API <br>解决添加对象属性不响应的问题<br><font color="#c41230">Vue.set( target, key, value )</font><br>
对于数组而言,<br>Vue 内部重写了以下函数实现派发更新
vue2.x中如何监测数组变化
使用了<font color="#c41230">函数劫持</font>的方式,<font color="#c41230">重写了数组的方法</font>,Vue将data中的数组进行了<font color="#c41230">原型链重写,指向了自己定义的数组原型方法</font>。<br>这样当调用数组api时,可以通知依赖更新。<br>如果<font color="#c41230">数组中包含着引用类型</font>,会<font color="#c41230">对数组中的引用类型再次递归遍历进行监控</font>。<br>这样就实现了监测数组变化。
NextTick 原理分析
nextTick 可以让我们<font color="#c41230">在下次 DOM 更新循环结束之后执行延迟回调,用于获得更新后的 DOM</font>。
nextTick主要使用了宏任务和微任务<br>根据执行环境分别尝试采用<br>
<ul><li>Promise</li><li>MutationObserver</li><li>setImmediate</li><li><span style="font-size: inherit;">如果以上都不行则采用setTimeout</span></li></ul>
定义了一个异步方法,多次调用nextTick会将方法存入队列中,通过这个异步方法清空当前队列
v-model
<font color="#c41230">语法糖</font>
<font color="#c41230">v-model是v-bind:value和v-on:input的简写</font>,<br>所以在父组件你完全可以直接写<font color="#c41230"> :value</font>="name", <font color="#c41230">@input</font>="val => name = val"
vue-router
hash模式 和 history模式
hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用 window.location.hash 读取。<br>特点:hash虽然在URL中,但<font color="#c41230">不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面</font>。<br>
history模式:history<font color="#c41230">采用HTML5的新特性</font>;<br>且提供了两个新方法:<font color="#c41230"> history.pushState()</font>,<font color="#c41230"> history.replaceState()</font>可以对浏览器历史记录栈进行修改,<br>以及<font color="#c41230">popState事件的监听到状态变更</font><br>
vue路由的钩子函数
首页可以控制导航跳转,<font color="#c41230">beforeEach,afterEach</font>等,一般用于页面title的修改。<br>一些需要登录才能调整页面的重定向功能
<ul><li><font color="#c41230">beforeEach</font>主要有3个参数to,from,next。</li><li>to:route即将进入的目标路由对象。</li><li>from:route当前导航正要离开的路由。</li><li>next:function一定要调用该方法resolve这个钩子。执行效果依赖next方法的调用参数。可以控制网页的跳</li></ul>
$route和$router的区别
$route是“<font color="#c41230">路由信息对象</font>”,包括<font color="#c41230">path,params,hash,query</font>,fullPath,matched,name等路由信息参数。
而$router是“<font color="#c41230">路由实例</font>”对象包括了路由的<font color="#c41230">跳转方法,钩子函数</font>等<br>
vuex
state:Vuex 使用<font color="#c41230">单一状态树</font>,即<font color="#c41230">每个应用将仅仅包含一个store 实例</font>,但单一状态树和模块化并不冲突。<br>存放的数据状态,不可以直接修改里面的数据。<br>
mutations:mutations定义的方法<font color="#c41230">动态修改Vuex 的 store 中的状态或数据</font><br>
getters:类似vue的计算属性,主要用来过滤一些数据。<br>
action:actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是<font color="#c41230">异步操作数据</font>。<br>
view 层通过 <font color="#c41230">store.dispath 来分发 action</font>
MVVM
MVVM是<font color="#c41230">Model-View-ViewModel</font>缩写,也就是把MVC中的Controller演变成ViewModel。<br><font color="#c41230">Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁</font>,<br>数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据<br>
diff
Q: Vue2.x和Vue3.x渲染器的diff算法分别说一下
diff算法有以下过程
<ul><li>同级比较,再比较子节点</li><li>先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除)</li><li>比较都有子节点的情况(核心diff)</li><li>递归比较子节点</li></ul>
时间复杂度
O(n)
正常Diff两个树的时间复杂度是O(n^3),但实际情况下我们<font color="#c41230">很少会进行跨层级的移动DOM</font>,<br>所以Vue将Diff进行了优化,从O(n^3) -> O(n),<br>只有当新旧children都为多个子节点时才需要用核心的Diff算法进行同层级比较。
Vue2的核心Diff算法
采用了<font color="#c41230">双端比较</font>的算法<font color="#c41230">,同时从新旧children的两端开始进行比较,借助key值找到可复用的节点,再进行相关操作</font>。<br>相比React的Diff算法,同样情况下可以减少移动节点次数,减少不必要的性能损耗,更加的优雅
虚拟Dom<br>以及<br><font color="#c41230">key属性的作用</font>
Virtual DOM本质就是<font color="#c41230">用一个原生的JS对象去描述一个DOM节点</font>。<br>是对真实DOM的一层抽象<br>VirtualDOM映射到真实DOM要经历<font color="#c41230">VNode的create、diff、patch</font>等阶段<br>
<font color="#c41230">key的作用是尽可能的复用 DOM 元素</font><br><br>新旧 children 中的节点<font color="#c41230">只有顺序是不同</font>的时候,最佳的操作应该是通过<font color="#c41230">移动元素的位置</font>来达到更新的目的。<br>需要在新旧 children 的节点中保存映射关系,以便能够在旧 children 的节点中找到可复用的节点。<br><font color="#c41230">key</font>也就<font color="#c41230">是</font>children中<font color="#c41230">节点的唯一标识</font><br>
Vue complier 实现
Vue complier 是<font color="#c41230">将 template 转化成一个 render</font> 字符串
步骤
<ul><li>parse 过程,将<font color="#c41230"> template</font> 利用<font color="#c41230">正则转化成AST 抽象语法树</font>。</li><li><font color="#c41230">optimize</font> 过程,<font color="#c41230">标记静态节点</font>,后 diff 过程跳过静态节点,提升性能。</li><li>generate 过程,<font color="#c41230">生成 render 字符串</font></li></ul>
vue & react
vue的优点是什么
<ul><li><font color="#c41230">低耦合</font>。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变</li><li><font color="#c41230">可重用性</font>。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑</li><li><font color="#c41230">可测试</font>。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写</li></ul>
0 条评论
下一页