1.v-if、v-show、v-html 的原理
v-if 会调用 addIfCondition 方法, 生成 vnode 的时候会忽略对应节点, render 的时候就不会渲染
v-show 会生成 vnode, render 的时候也会渲染成真实节点, 只是在 render 过程中会在节点的属性中修改 show 属性值, 也就是常说的 display
v-html 会先移除节点下的所有节点, 调用 html 方法, 通过 addProp 添加 innerHTML 属性, 归根结底还是设置 innerHTML 为 v-html 的值
2.v-if和v-show的区别
这两个指令的共同点:都可以控制标签显示或隐藏,给变量赋予true/false,显示/隐藏
不同点:v-show是用css方式显示/隐藏标签,v-if直接从DOM树上添加/移除,v-if可以配合v-else使用
手段: v-if 是动态的向 DOM 树内添加或者删除 DOM 元素, v-show 是通过设置 DOM 元素的 display 样式属性控制显隐
编译过程: v-if 切换有一个局部编译/卸载的过程, 切换过程中合适地销毁和重建内部的事件监听和子组件, v-show 只是简单的基于 css 切换
编译条件: v-if 是惰性的, 如果初始条件为假, 则什么也不做, 只有在条件第一次变为真时才开始局部编译, v-show 是在任何条件下, 无论首次条件是否为真, 都被编译, 然后被缓存, 而且 DOM 元素保留
性能消耗: v-if 有更高的切换消耗, v-show 有更高的初始渲染消耗
使用场景: v-if 适合运营条件不大可能改变, v-show 适合频繁切换
语法:
v-show=“vue变量”
v-if=“vue变量”
原理
v-show 用的display:none隐藏 (频繁切换使用)
v-if 直接从DOM树上移除(属于一个销毁和创建的过程)
3.v-model 是如何实现双向数据绑定的?
Vue中使用v-model可以实现表单元素和数据之间的双向绑定,即修改表单的值,data中对应变量的值也会被修改。在data对应变量中修改值,被绑定的表单值也会被修改;所以称之为双向绑定。
简单举例理解一下:
<!--
v-model 可以用在input中也可以用在textarea中 。
他包含两个指令:
一个v-bind,把message的值时时放到value中,
另一个v-on ,给当前元素绑定input事件
-->
<input type="text" v-model="message">
<!--上面的代码等同于下方的 -->
<input type="text" v-bind:value="message" @input="changeValue">
<!-- 可以直接写在监听事件里 -->
<input type="text" v-bind:value="message" @input="message = $event.target.value">
```javascript
export default {
data() {
return {
message:'学前端'
}
}
methods: {
changeValue(event) {
//有事件时会产生event(里面包含想要的信息)
//在上面的html中不需要加,在此传的event会自动传过去
//这个target.value是最新的value,复制给message即可
//所以input的value值发生变化时,message的值也会变化 ,同时message的值也是value值
this.message = event.target.value
}
}
}
v-module双向绑定的底层原理:
数据绑定+事件绑定
通过v-bind:value=‘message’,将value属性和message数据进行绑定,那么msg的值就会影响value的值;
然后通过通过v-on:input=‘msg=$event.target.value’,给文本添加了一个input事件
4.data为什么是一个函数而不是对象
组件是可复用的vue实例,一个组件被创建好之后,就可能被用在各个地方,而组件不管被复用了多少次,组件中的data数据都应该是相互隔离,互不影响的,基于这一理念,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响。
组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。
总结:防止数据污染,每个组件都会有自己全新的data
5.对keep-alive的理解,它是如何实现的,具体缓存的是什么?
keep-alive实现原理
- 获取 keep-alive 包裹着的第一个子组件对象及其组件名
- 根据设定的 include/exclude(如果有)进行条件匹配,决定是否缓存。不匹配,直接返回组件实例
- 根据组件 ID 和 tag 生成缓存 Key,并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值并更新该 key 在
this.keys
中的位置(更新 key 的位置是实现 LRU 置换策略的关键) - 在
this.cache
对象中存储该组件实例并保存 key 值,之后检查缓存的实例数量是否超过 max 的设置值,超过则根据 LRU 置换策略删除最近最久未使用的实例(即下标为 0 的 key) - 最后组件实例的 keepAlive 属性设置为 true,这个在渲染和执行被包裹组件的钩子函数会用到。
LRU 缓存淘汰算法
LRU(Least recently used)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
keep-alive 的实现用到了 LRU 策略,将最近访问的组件 push 到 this.keys
最后面,this.keys[0]
就是最久没被访问的组件,当缓存实例超过 max 设置值,删除 this.keys[0] 。
6. Vue 单页应用与多页应用的区别
单页面,顾名思义只有一个界面。(SinglePage Web Application,SPA)
只有一张Web页面的应用,是一种从Web服务器加载的富客户端,单页面跳转仅刷新局部资源 ,公共资源(js、css等)仅需加载一次,常用于PC端官网、购物等网站
页面跳转:使用js中的append/remove或者show/hide的方式来进行页面内容的更换;或者使用Vue里面的路由跳转进行页面的更换
数据传递:可通过全局变量或者参数传递,进行相关数据交互界面是通过URL来定位的,所以单页面应用从头到尾它的html地址都是不变的,注意哦,是html地址,而不是URL地址,这两者还是有点区别的。html地址是截止到.html的界面地址,比如:http://about.html#setting这个地址中,html地址是http://about.html,而完整的URL是http://about.html/#/setting。
而多页面应用,顾名思义就是多个界面间的跳转,会伴随着html地址的改变。(MultiPage Application,MPA)
多页面跳转刷新所有资源,每个公共资源(js、css等)需选择性重新加载,常用于 app 或 客户端等
页面跳转:使用window.location.href = “./index.html"进行页面间的跳转;
数据传递:可以使用path?account=“123”&password=”"路径携带数据传递的方式,或者localstorage、cookie等存储方式在单页面应用中,通常是由一个外部框架和一个一个组件组成的,界面之间的切换其实就是组件的移除和新组建的添加。
在多页面中,则可以看到导航栏中地址的变化,是从一个完整的页面跳转到另一个完整的页面(注意区分页面和界面)
7. Vue template 到 render 的过程
-
问我们template到render过程,其实是问Vue
编译器
工作原理; -
思路
- 1.引入vue编译器概念;
- 2.说明编译器的必要性;
- 3.阐述编译器的工作流程;
-
回答范例
- 1.Vue中有个独特的编译器模块,称为
"compiler"
,它的主要作用是将用户编写的template编译为js中可执行的render函数; - 2.之所以需要这个编译过程是为了便于前端程序员能高效的编写视图模板;相比而言,我们还是更愿意用HTML来编写视图,直观且高效。手写render函数不仅效率底下,而且失去了编译期的优化能力,因此compiler的过程是必须的;
- 3.在Vue中编译器会先对template进行解析,这一步称为
parse
,结束之后会得到一个JS对象,我们成为抽象语法树AST,然后是对AST进行深加工的转换过程,这一步称为transform
,最后将前面得到的AST生成(generate
)JS代码,也就是render函数;
- 1.Vue中有个独特的编译器模块,称为
8. Vue data 中某一个属性的值发生改变后,视图会立即同步执行重新渲染
吗?
它是不会立即同步执行重新渲染。因为Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化, Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。
如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环tick中,Vue 刷新队列并执行实际(已去重的)工作。
9. 描述下Vue常用指令
vue常用指令有:v-once指令、v-show指令、v-if指令、v-else指令、v-else-if指令、v-for指令、v-html指令、v-text指令、v-bind指令、v-on指令、v-model指令等等。
v-once
只会执行一次渲染,当数据发生改变时,不会再变化
v-show
v-show接受一个表达式或一个布尔值。相当于给元素添加一个display
属性
v-if、v-else、v-else-if
v-if和v-show有同样的效果,不同在于v-if是重新渲染,而v-show使用display属性来控制显示隐藏。频繁切换的话使用v-show减少渲染带来的开销。
说明一下:v-if可以单独使用,而v-else-if,v-else必须与v-if组合使用
v-if、v-else-if都是接受一个条件或布尔值,v-else不需要参数。
v-for
v-for可用来遍历数组、对象、字符串。
v-text和v-html
v-text
是渲染字符串,会覆盖原先的字符串
v-html
是渲染为html。{{}}
双大括号和v-text
都是输出为文本。那如果想输出为html。使用v-html
v-bind
是用可以将标签内的属性值解析成js代码,在标签的属性中使用v-bind,双引号里的内容会被当作js解析(只能解析变量或三元表达式),如下:
如果给属性值设置为一个变量,那么可以使用v-bind
可以缩写为:<属性>="<变量>"
v-on
v-on
用于事件绑定
语法: v-on:<事件类型>="<函数名>"
简写:@<事件类型>="<函数名>"
v-model
数据双向绑定指令,限制在 <input>、<select>、<textarea>
、components中使用
语法: v-model="<变量名>"
10.描述下Vue自定义指令
1. 什么是自定义指令
vue 官方提供了v-text、v-for、v-model、v-if 等常用的指令。除此之外vue 还允许开发者自定义指令。
2. 自定义指令的分类
vue 中的自定义指令分为两类,分别是:
私有 自定义指令 在每个vue 组件中,可以在directives 节点下声明私有自定义指令
全局 自定义指令 全局共享的自定义指令需要通过“Vue.directive()”进行声明