1.谈谈你对MVVM的理解
定义:MVVM分为Model、View、ViewModel 。
Model:代表数据模型,数据和业务逻辑都在Model层中定义,俗称的data
View:代表UI视图,负责数据的展示,俗称的html部分,也叫模板部分
ViewModel:负责监听Model中数据的改变并且控制视图的更新,处理用户交互操作,在这里是作为一个桥梁来连接Model和View
Model和View并无直接关联,而是通过ViewModel来进行联系的,Model和ViewModel之间有着双向数据绑定的联系。(ps:双向数据绑定的原理什么是双向数据绑定看下文第3个问题),因此当Model中的数据改变时会触发View层的刷新,View中由于用户交互操作而改变的数据也会在Model中同步。
也就是以下两个方向的转化:
那么mvvm与MVC的区别和联系?什么是mvc?
2.谈谈你对MVC的理解,以及现有的新的MVVM与MVC的区别和联系
(1)MVC是Model-View- Controller的简写。即模型-视图-控制器。M和V指的意思和MVVM中的M和V意思一样。
Model:代表数据模型,数据和业务逻辑都在Model层中定义,俗称的data
View:代表UI视图,负责数据的展示,俗称的html部分,也叫模板部分
Controller:即Controller指的是页面业务逻辑。
使用MVC的目的就是将M和V的代码分离。‘MVC是单向通信。也就是View跟Model,必须通过Controller来承上启下。
(2)MVC和MVVM的区别并不是VM完全取代了C,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。也就是说ViewModel只是抽离了Controller中关于数据怎么展示什么时候展示如何展示的逻辑部分,没有抽离关于系统的业务逻辑部分(ps写代码的人都晓得什么是数据展示逻辑什么是业务,业务逻辑)
(3)MVC和MVVM的联系在于本身是没有mvvm的说法的,他本质上还是MVC,只不过是一直MVC的衍生模式
3.vue里面什么是双向数据绑定?双向数据绑定的原理是什么
(1)定义:双向数据绑定就是通俗的来说用户在界面上输入数据自动存入data里面,data数据改变自动渲染在视图上,不需要手动的去操作dom来获取或者改变dom上的value,简而言之就是:数据变化更新视图,视图变化更新数据
(2)双向数据绑定的原理:
简单来说就是通过监听,当数据改变的时候去更新视图,具体实现先看下图:(ps,图为盗用的,想自己画一个的,但是有现成的就拿来用了,一个意思,如有侵权请联系)
首先先介绍以下三个概念:
(1) Compile指令解析器,对每个dom元素节点的指令进行解析,替换模板数据,并绑定对应的更新函数,初始化相应的订阅Watcher 。
(2) Watcher 订阅者,连接 Observer 和 Compile 的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,调用自身的update方法更新视图。Watcher会订阅信息自动添加到 消息订阅器dep中
(3) Dep 消息订阅器,内部维护了一个数组,用来收集订阅者(Watcher),数据变动触发notify 函数,再调用订阅者的 update 方法。
完整的实现过程:
当一个vue组件实例化的时候也就是执行当执行 new Vue() 时会同时执行两个操作:
1.vue会遍历data中的属性,并且用Object.defineProperty给他们加上getter/setter方法,使数据具有可观测性,实现数据的监听的功能,也就是监听者Observer做的事情
(ps:Object.defineProperty方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。不懂参照:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
2.vue的指令编译器Compile 会对元素节点进行指令解析,初始化视图并且订阅Watcher 来更新视图, 此时Wather 会将自己添加到消息订阅器中(Dep)。
这样就完成了视图的初始化
当数据发生变化的时候,监听者Observer 中的 setter 方法被触发,setter 会立即调用Dep.notify(),Dep 开始遍历所有的订阅者Watcher,遍历到对于变化数据的Watcher就调用对应 订阅者Watcher的 update 方法,订阅者收到通知后对视图进行相应的更新。
也就是由于双向数据绑定采用了Object.defineProperty这个方法是es5的写法,所以vue不支持 IE8 以及更低版本浏览器
4.请你说一下Vue的生命周期,以及每个生命周期可以进行哪些操作(关于Vue生命周期的其他提问)
答案请见另一篇博客总结:https://blog.csdn.net/qq_34645412/article/details/88063837
5.v-if和v-show的区别
两者都是控制元素的显示和不显示的
区别:
(1)v-show 只是简单的控制元素的 display 属性,当条件为false的时候dom是存在的相当于display=none,而 v-if 是条件渲染(条件为真,元素将会被渲染,条件为假,元素会被销毁),当条件为false的时候dom是不存的
(2) v-if 有更高的切换开销,v-show 切换开销小;由于(1)导致,因为v-if切换的时候涉及dom重新渲染所以切换开销会比较大,而v-show切换的时候只涉及display属性的切换,不涉及dom的重新渲染
(3) v-show 有更高的首次渲染开销,因为v-show首次渲染的时候不仅要渲染dom,而 v-if 的首次渲染开销要小的多;因为只需要渲染dom,不需要渲染元素对应的属性
6.vue路由缓存
一种场景,vue实现在商品列表页看来一些产品后点击进某个详情页,要求看完详情页返回的时候保存商品列表页的搜索条件,页码等信息,在不发生请求的情况下,你会怎么做?
路由缓存,
是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。被路由缓存的页面再次进入的时候不会调用created生命周期钩子
7.vue路由实现的方式有哪些?区别是什么
(1)hash模式 :类似‘http://www.xxx.com/#/login’有个#,后面 hash 值的变化,由于h5的单页应用,要求页面交互是无刷新的,连页面跳转都是无刷新的,所以#后面 hash 值的变化,并不会导致浏览器向服务器发出请求,浏览器不发出请求,也就不会刷新页面。另外每次 hash 值的变化,还会触发hashchange
这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听hashchange
来实现更新页面部分内容的操作;用window.location.hash读取;
(2)history模式:类似“http://www.xxx.com/login”多了两个 API,pushState
和 replaceState
,通过这两个 API 可以改变 url 地址且不会发送请求。同时还有popstate
事件。通过这些就能用另一种方式来实现前端路由了,但原理都是跟 hash 实现相同的。用了 HTML5 的实现,单页路由的 url 就不会多出一个#,变得更加美观。但因为没有 # 号,所以当用户刷新页面之类的操作时,浏览器还是会给服务器发送请求。为了避免出现这种情况,所以这个实现需要服务器的支持,需要把所有路由都重定向到根页面。提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。
(3)区别:hash后面跟了#,history没有跟#,更美观,但是history需要服务器的支持,hash不会导致页面重载,history会导致页面重载
export default new Router({
mode: 'history', // require service support value is hash or history defalut is hash
scrollBehavior: () => ({
y: 0
}),
routes: constantRouterMap
})
//如果是 history : 路由为http://www.xxx.com/login
如果是 hash 路由为:http://www.xxx.com/#/login
8.vue的优点和缺点,与react框架的区别
(1)学习成本上而言:
vue更简单易学基于html的虚拟dom实现,
react学习曲线更高,基于js的虚拟dom实现
react Virtual DOM是一个映射真实DOM的JavaScript对象,如果需要改变任何元素的状态,那么是先在Virtual DOM上进行改变,而不是直接改变真实的DOM。当有变化产生时,一个新的Virtual DOM对象会被创建并计算新旧Virtual DOM之间的差别。之后这些差别会应用在真实的DOM上。
Vue宣称可以更快地计算出Virtual DOM的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。
而对于React而言,每当应用的状态被改变时,全部子组件都会重新渲染。当然,这可以通过shouldComponentUpdate
这个生命周期方法来进行控制,但Vue将此视为默认的优化。
(2)react不是基于mvc的一个组件库,它非常适合代表经常变化的数据的组件。使用React,您可以通过将它们分解为组件而不是使用模板或HTML来构建可重用的用户界面。react是单向数据流的,而vue是双向数据流的,但数据比较多切变化复杂的系统里面适合用react,数据流清晰,问题定位简单,而小型简单的系统就可以使用vue,vue简单轻便 ,更小,更快,更灵活。丰富的HTML模板,易于开发
(3)生态圈,react的生态圈是facebook的官方团队,vue的生态环境就比较小一点
总结:vue是基于html实现虚拟dom的react是基于js 的,相同点就是都是虚拟dom,都是双向数据绑定。react是通过对比新旧虚拟dom的区别来更新反应在真实视图上,vue是跟踪组件的依赖关系来 实现的。vue是双向数据流,react的是单向数据流。react适合数据逻辑比较复杂的项目,vue适合简单轻便的应用
9.vue和angular的区别
(1).vue简单、易用、轻量、学习曲线低、虚拟dom、基于html的模板语法
(2).angular是一个功能齐全的框架,支持 Model-View-Controller 编程结构,模块化、自动化双向数据绑定、语义化标签、依赖注入等等。非常适合构建动态的单页网络应用程序。
(3)生态圈来看angular的生态圈比vue的生态圈要更强大
(4).小项目,逻辑简单的使用vue,大型复杂项目使用angular
10.vue路由的钩子函数
(1)全局路由钩子
router.beforeEach((to, from, next) => {
console.log('beforeEach')
//next() //如果要跳转的话,一定要写上next()
//next(false) //取消了导航
next() //正常跳转,不写的话,不会跳转
})
router.afterEach((to, from) => { // 举例: 通过跳转后改变document.title
if( to.meta.title ){
window.document.title = to.meta.title //每个路由下title
}else{
window.document.title = '默认的title'
}
})
(2)单个路由钩子
beforeEnter(to, from, next){
console.log('beforeEnter')
next() //正常跳转,不写的话,不会跳转
}
(3)组件内部的路由钩子
beforeRouteEnter(to, from, next){ // 这个路由钩子函数比生命周期beforeCreate函数先执行,所以this实例还没有创建出来
console.log("beforeRouteEnter")
console.log(this) //这时this还是undefinde,因为这个时候this实例还没有创建出来
next((vm) => { //vm,可以这个vm这个参数来获取this实例,接着就可以做修改了
vm.text = '改变了'
})
},
beforeRouteUpdate(to, from, next){//可以解决二级导航时,页面只渲染一次的问题,也就是导航是否更新了,是否需要更新
console.log('beforeRouteUpdate')
next();
},
beforeRouteLeave(to, from, next){// 当离开组件时,是否允许离开
next()
}
11、Vue如何自定义指令
(1)全局指令
Vue.directive('dir2', {
inserted(el) {
console.log(el);
}
})
(2)局部指令
var app = new Vue({
el: '#app',
data: {
},
// 创建指令(可以多个)
directives: {
// 指令名称
dir1: {
inserted(el) {
// 指令中第一个参数是当前使用指令的DOM
console.log(el);
console.log(arguments);
}
}
}
})
(3)自定义指令使用
https://cn.vuejs.org/v2/guide/custom-directive.html
12.如何定义一个过滤器
类似于angular的管道用法
(1)局部过滤器
new Vue({
el:"#app",
data:{
msg:''
},
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value+ value.slice(1)
}
}
})
(2)全局过滤器
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value + value.slice(1)
})
(3)使用
{{msg| capitalize }}
13.其他一些琐碎的问题
https://segmentfault.com/a/1190000016344599