1.什么是SPA应用,它的优缺点分别是什么?
SPA:single page application,单页面应用。仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转,而页面的变化是利用路由机制实现HTML内容的动态更新,避免页面的重新加载。
优点:
缺点: - 首次加载比较慢 - SEO难度较大
SEO是“搜索引擎优化”。也就是通过某些特定规则来优化网站代码,从而使网站能更加容易的被搜索引擎抓取到,提高搜索结果的排名。
针对SPA应用的SEO优化方案有:
2.为什么说Vue是一个渐进式的javascript框架, 渐进式是什么意思?
Vue的渐进式体现在:代码侵入性低,既可以当库使用,也可以当框架使用。简而言之就是,没有多做职责之外的事。
3.谈谈你对MVVM的理解。
MVVM:Model-View-ViewModel。

MVVM的优点: - MVVM实现了视图与数据的双向绑定,而MVC只实现了数据到视图的单向绑定。 - MVVM实现了业务逻辑与页面渲染的解耦,数据与视图的解耦,可以组件化开发。
4.说说v-show和v-if的区别。
共同点:v-if和 v-show都是用来实现元素的显示隐藏的vue指令。
区别: - v-show 是条件隐藏,内部是通过display:none实现。v-if是条件渲染,只有条件为真时才渲染元素。 - v-show 有更高的首次渲染开销,而 v-if的首次渲染开销要小的多。 - v-show 的切换开销小,而v-if有更高的切换开销。 - v-if 可以搭配template使用,而v-show不行。
总结:如果需要非常频繁地切换,则使用v-show较好,如果在运行时条件很少改变,则使用v-if较好。
5.说说v-for为什么要用key,选择什么属性做key适合?
key是给每一个vnode的唯一id,也是diff的一种优化策略,可以根据key,更准确, 更快的找到对应的vnode节点。
实例:
<div id="app">
<ul>
<li v-for="(c,index) in citys" :key="index">
<input type="checkbox" :value="c">{{c}}</input>
</li>
</ul>
<input type="button" @click="removeFirst" value="删除第一个元素"/>
</div>
<script>
let vm = new Vue({
el: '#app',
data() {
return {
citys: ['北京', '上海', '广州', '成都']
}
},
mounted() {
},
methods: {
//每次删除第一个元素
removeFirst() {
this.citys.shift();
}
}
})
</script>
首先选中'北京',然后点击删除后:

我们发现此时'北京'已经删除了,但是'上海'默认选中,显然是不合理的。这是因为Vue,默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染,要选择适合的属性作为key。
代码改写如下:
<div id="app">
<ul>
<li v-for="(c,index) in citys" :key="c.code">
<input type="checkbox" :value="c.name">{{c.name}}</input>
</li>
</ul>
<input type="button" @click="removeFirst" value="删除第一个元素"/>
</div>
<script>
let vm = new Vue({
el: '#app',
data() {
return {
citys: [
{
code: '010',
name: '北京'
},
{
code: '021',
name: '上海'
},
{
code: '020',
name: '广州'
},
{
code: '028',
name: '成都'
}
]
}
},
mounted() {
},
methods: {
removeFirst() {
this.citys.shift();
}
}
})
</script>

总结:v-for通常会指定一个key属性,这个key属性使用一些唯一索引或者主键更为合适。
6.说说computed和watch,methods的区别。
computed和watch都可以用来监听数据的变化,区别如下:
7.Vue子组件和父组件执行顺序。
vue2 中生命周期的执行顺序:
beforeCreate => created => beforeMount => mounted => beforeUpdate => updated => beforeDestroy => destroyed
vue3 中生命周期的执行顺序:
setup =>onBeforeMount => onMounted => onBeforeUpdate => onUpdated => onBeforeUnmount => onUnmounted
对应关系: vue2->vue3
beforeCreate -> setup
created -> setup
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
父子组件执行顺序
挂载阶段的执行顺序为:
父beforeCreate => 父created => 父beforeMount => 子beforeCreate => 子created => 子beforeMount => 子mounted => 父mounted
更新阶段的执行顺序为: 父beforeUpdate => 子beforeUpdate => 子updated => 父updated
销毁阶段的执行顺序为: 父beforeDestroy => 子beforeDestroy => 子destroyed => 父destroyed
规律就是:父组件先开始执行,然后等到子组件执行完,父组件收尾。
8.Vue实现数据双向绑定的原理。
Vue实现数据双向绑定的原理:结合发布-订阅模式,通过ES5新增的Object.defineProperty()方法劫持各个属性的setter和getter,Observer监听数据的变动。
下面是一个极简数据双向绑定的实现。
<input type='text' id='test'>
<span id='spa'></span>
<script>
let obj = {};
Object.defineProperty(obj,'hello',{
set:function(newVal){
document.getElementById('test').value = newVal;
document.getElementById('spa').innerHTML= newVal;
}
});
document.addEventListener('keyup',function(e){
obj.hello = e.target.value
})
</script>
9.Vue的两种路由模式和实现原理
Vue有hash和history两种路由模式。
history和hash的的对比: - history比hash的url美观(没有’#'号) - history修改的url可以是同域的任意url,hash则只能是同文档的url - history模式往往需要后端支持,如果后端nginx没有覆盖路由地址,就会返回404,hash因为是同文档的url,即使后端没有覆盖路由地址,也不会返回404。 - hash模式下,如果把url作为参数传后端,那么后端会直接从’#‘号截断,只处理’#'号前的url,因此会存在#后的参数内容丢失的问题,不过这个问题hash模式下也有解决的方法。
10.谈谈你对keep-alive的了解。
keep-alive顾名思义,保持活跃。就是可以保持组件的状态。keep-alive是Vue的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁。
keep-alive可以实现组件的缓存,当组件切换时不会对当前组件进行卸载,常用的2个属性include / exclude,2个生命周期 activated , deactivated LRU算法,缓存组件,不需要重复渲染时 如多个静态Tab页切换。
注意:使用了keep-alive后,生命周期会增加 activated 和 deactivated两个方法。 初次执行组件时:created > mounted > activated;退出后触发 deactivated。 再次执行组件时:会触发 activated;事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在activated中。