1、this.$set() (Vue.set())
在vue中直接给一个数组项赋值,vue并不能检测到变化
//在vue中给对象数组项赋值,没办法赋值,vue渲染不出来
this.dataForm.arr1= [1,2]
//用$set给对象的数组项赋值,则能渲染出来
this.$set(this.dataForm,'arr1', [1,2])
2、vue computed 和 watch 的区别和运用的场景
computed :是计算属性,依赖其他属性的值,并且computed的值有缓存,只有它依赖的属性值发生改变,下一次获取computed的值时才会重新计算computed的值。
watch:更多的是【观察】的作用,类似于某些数据的监控回调,每当监听的数据发生改变时都会执行回调进行后续操作
3、vue的父组件和子组件生命周期钩子函数的执行顺序】
加载渲染过程
父beforeCreated —> 父created —> 父beforeMounted —> 子beforeCreated —> 子created —> 子beforeMounted —> 子mounted —>父mounted
子组件更新过程
父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
父组件更新过程
父beforeUpdate -> 父updated
销毁过程
父beforeDestroy -> 子beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
4、在哪个生命周期内调用异步请求合适?
可以在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。但是本人推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:
能更快获取到服务端数据,减少页面 loading 时间;
ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;
(参考https://www.jianshu.com/p/9f460e66ce01)
5、组件中的data为什么是一个函数
为什么组件中的data必须是一个函数,然后return一个对象,而new Vue实例中data可以直接是一个对象?
因为组件是用来复用的。且js里的对象是引用关系。如果组件中data是一个对象,那么这样作用域没有隔离,子组件中data属性值会相互影响,如果组件中data选项是一个函数,那么每个实例可以维护一份被返回对象的独立的拷贝,组件实例之间的data属性值不会相互影响;而new Vue的实例是不会被复用的,因此不存在引用对象的问题;
(参考https://www.jianshu.com/p/9f460e66ce01)
6、vue双向绑定
首先,我们通过Object.defineProperty方法实现了对object数据的可观测,并且封装了Observer类,让我们能够方便的把object数据中的所有属性(包括子属性)都转换成getter/seter的形式来侦测变化。
接着,我们学习了什么是依赖收集?并且知道了在getter中收集依赖,在setter中通知依赖更新,以及封装了依赖管理器Dep,用于存储收集到的依赖。
最后,我们为每一个依赖都创建了一个Watcher实例,当数据发生变化时,通知Watcher实例,由Watcher实例去做真实的更新操作。
其整个流程大致如下:
1.Data通过observer转换成了getter/setter的形式来追踪变化。
2.当外界通过Watcher读取数据时,会触发getter从而将Watcher添加到依赖中。
3.当数据发生了变化时,会触发setter,从而向Dep中的依赖(即Watcher)发送通知。
4.Watcher接收到通知后,会向外界发送通知,变化通知到外界后可能会触发视图更新,也有可能触发用户的某个回调函数等。
7、对vue项目进行过哪些优化?
(1)代码层面的优化
- v-if和v-show区分使用场景
- computed和watch区分使用场景
- v-for遍历必须为item添加key,且避免同时使用v-if(v-for的优先级大于v-if,造成不必要的计算,影响性能,尤其是当之需要渲染很小一部分的时候),为了避免可以使用computed `
computed: {
activeUsers: function () {
return this.users.filter(function (user) {
return user.isShow;//返回isShow=true的项,添加到activeUsers数组
})
} - 长列表性能优化
- 事件的销毁
- 图片资源懒加载
- 第三方插件按需引入
- 优化无限列表性能
- 服务端渲染SSR or 预渲染
(1)webpack层面的优化
- 减少es6转为es5冗余代码
- 提取公共代码
- 模板预编译
- 提取组件css
- 优化SourceMap
- 构建结果输出分析
- vue项目的编译优化
(3)基础web技术优化
- 开启gzip压缩
- 浏览器缓存
- CDN的使用
- 使用chrome performance查找性能瓶颈
8、vue-router有哪几种导航钩子?
一、全局守卫
1、router.beforeEach((to,from,next)=>{})
回调函数中的参数,to:进入到哪个路由去,form:从哪个路由离开,next:函数决定是否展示你要看到的路由页面
2、后置钩子 router.afterEach((to,from)=>{})
to:进入到哪个路由去,from:从哪个路由离
二、组件内的守卫
1、到达这个组件时 beforeRouteEnter:(to,from,next)=>{}
在Admin.vue文件中,点击转到admin路由时,执行beforeRouteEnter函数
to,from参数与上面使用方法一致。next回调函数略有不同。
如下例,data 组件内守卫有特殊情况,如果我们直接以
beforeRouteEnter:(to,from,next)=>{ alert("hello" + this.name);}进行访问admin页面,
会发现alert输出hello undefined。这是因为,现在访问不到我们的data属性,执行顺序是不一致,
这与的声明周期有关。在执行完之前,data数据还未渲染。所以这里,next()会给一个对应的回调,帮助完成。
data(){
return{
name:"通过审核!"
}
},
beforeRouteEnter:(to,from,next)=>{
next(vm=>{
alert("恭喜你" + vm.name);
})
},
2、到达这个组件时 beforeRouteLeave:(to,from,next)=>{}
点击其他组件时,判断是否确认离开。确认执行next();取消执行next(false),留在当前页面。
beforeRouteLeave:(to,from,next)=>{
if(confirm("确定离开此页面吗?") == true){
next();
}else{
next(false);
}
},
三、路由独享的守卫
beforeEnter:(to,from,next)=>{},用法与全局守卫一致。只是,将其写进其中一个路由对象中,只在这个路由下起作用。
{
path: '/demo',
name: 'Demo',
component: Demo,beforeEnter:(to,from,next)=>{
alert("非登录状态,不能访问页面");
next('/login');
},
},