1.0. 什么是MVC,什么是MVVM

1- 什么是MVVM

  1. MVVMModel-View-ViewModel的缩写。MVVM是一种设计思想。Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View Model的对象(桥梁)。
  2. modelview不直接通信,通过vm来双向绑定连接,不需要操作dom视图也会更新
  3. MVVM架构下,View Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
  4. ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

2- 什么是MVC

  1. MVC是一个架构模式,它分离了表现与交互。它被分为三个核心部件:模型、视图、控制器。下面是每一个部件的分工:
  2. 视图是用户看到并与之交互的界面。
  3. 模型表示业务数据,并提供数据给视图。
  4. 控制器接受用户的输入并调用模型和视图去完成用户的需求。

3- MVVM和MVC的区别

  1. MVCModel-View-Controller,即模型-视图-控制器,使用MVC的目的是为了将MV相分离。
  2. MVVMMVC最大的区别就是:它实现了ViewModel的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变。

1.1. watch和computed(计算属性)的区别

  • 当模板中的某个值需要通过一个或多个数据计算得到时,就可以使用计算属性,还有计算属性的函数不接受参数;
  • 监听属性主要是监听某个值发生变化后,对新值去进行逻辑处理。
  • 当我们试图通过数据对象来创造另一个属性时,推荐使用computed,computed默认有缓存效果,当计算属性没有发生变化时,不会重新计算更不会重新渲染。
  • 当我们试图通过侦听数据对象的改变来做点什么(比如执行一个函数),我们就可以使用watch,在使用watch时尤其要注意它支持异步。

1.computed有缓存,依赖数据未变动时调用读取缓存,watch没有
2.watch可以进行异步操作,computed不行

1.2. v-if和v-show的区别

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好

1.3. vue-router

路由中有三个基本的概念 route, routes, router。

1, route,它是一条路由,由这个英文单词也可以看出来,它是单数, Home按钮 => home内容, 这是一条route, about按钮 => about 内容, 这是另一条路由。

2, routes 是一组路由,把上面的每一条路由组合起来,形成一个数组。[{home 按钮 =>home内容 }, { about按钮 => about 内容}]

3, router 是一个机制,相当于一个管理者,它来管理路由。因为routes 只是定义了一组路由,它放在哪里是静止的,当真正来了请求,怎么办? 就是当用户点击home 按钮的时候,怎么办?这时router 就起作用了,它到routes 中去查找,去找到对应的 home 内容,所以页面中就显示了 home 内容。

4,客户端中的路由,实际上就是dom 元素的显示和隐藏。当页面中显示home 内容的时候,about 中的内容全部隐藏,反之也是一样。客户端路由有两种实现方式:基于hash 和基于html5 history api.

5.$router 和 $route 的区别

  • $router : 包含所有的方法
    • $router.push({path:’home’})
    • $router.replace({path:’home’})//替换路由,没有历史记录
  • $route : 包含所有的属性

1.4. v-for 和 v-if 是否能在 同一层级使用

  1. <div v-for="item of arr" v-if="item==1">{{item}}</div>
  2. 不能
  3. 原因:vue在处理指令时,v-for 的执行,会优于v-if
  4. vue3中优化了v-ifv-for优先级高
  5. 导致就算只是一小部分符合条件能够渲染出来,每次重渲染也都会遍历一次
  6. 这样使用的时候会造成额外的开销
  7. 推荐 直接使用计算属性处理后遍历
  8. <div v-for="item of arr" :key="item">
  9. <template v-if="item==1">
  10. {{item}}
  11. </template>
  12. </div>

1-5. $nextTick 的作用

  1. //因为当改变数据时vue渲染dom是异步的,所以为了性能考虑,vue 会在本轮数据更新后,再去异步更新视图
  2. this.$nextTick(()=>{
  3. // 等待DOM异步更新完毕之后,再执行里面的code
  4. console.log(this.$refs.test.children.length)
  5. )

1-6. a 标签和 router-link 区别

  1. router-link 避免了不必要的重渲染,它只更新变化的部分从而减少DOM性能消耗

1-7. vue中的data为什么是函数

  1. 1.当我们将组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,拥有自己的作用域,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
  2. 2.当我们组件的date单纯的写成对象形式,这些实例用的是同一个构造函数,由于JavaScript的特性所导致,所有的组件实例共用了一个data,就会造成一个变了全都会变的结果。
  3. 多个组件复用时,每次调用data函数的时候都会return一个新的对象,它们的内存地址都是不一样的,这样就不会相互影响,
  4. 怕重复创建实例造成多实例共享一个数据对象
  5. !!!总结:组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data。如果单纯的写成对象形式,就使得所有组件实例共用了一份data,造成了数据污染。

1-8. 重~要 vue双向数据绑定的原理(响应式原理)

  1. vue2原理:vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的settergetter,在数据变动时发布消息给订阅者,触发相应的监听回调。通过追踪依赖的方式进行发布
  2. reduce进行遍历
  3. 1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
  4. 2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。,每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
  5. 3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
  1. var obj = {};
  2. Object.defineProperty(obj, 'name', {
  3. get: function() {
  4. console.log('我被获取了')
  5. return val;
  6. },
  7. set: function (newVal) {
  8. console.log('我被设置了')
  9. }
  10. })
  11. obj.name = 'fei';//在给obj设置name属性的时候,触发了set这个方法
  12. var val = obj.name;//在得到obj的name属性,会触发get方法
  1. vue是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的settergetter,在数据变动时发布消息给订阅者,触发响应的监听回调。
  2. 1.首先vue示例创建时内部通过object.defineProperty()劫持了各个属性的settergetter。(就是给他们添加getset方法)并且让dep保存了依赖,然后是组件示例创建时会对应一个watchew,会记录依赖一些属性
  3. 当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。
  4. 每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

image.png

  1. 2.vue3改动:通过Proxy来劫持
  1. Object.defineProperty()和Proxy对比
  2. 1.Proxy是对整个对象的代理,而Object.defineProperty只能代理某个属性。
  3. 2.对象上新增属性,Proxy可以监听到,Object.defineProperty不能。
  4. 3.数组新增修改,Proxy可以监听到,Object.defineProperty不能。
  5. 4.若对象内部属性要全部递归代理,Proxy可以只在调用的时候递归,而Object.definePropery需要一次完成所有递归,性能比Proxy差。
  6. 5.Proxyie浏览器上存在兼容问题
  7. //如果问了还是这样答也阔以,也讲了一半了

1-9 说说你对 SPA 单页面的理解,它的优缺点分别什么?

SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;
优点:对服务器压力小,良好的交互体验,前后端分离开发;
缺点:SEO难度较高,前进、后退由路由管理,初次加载耗时多;

1-10 Class 与 Style 如何动态绑定?

Class 和 Style可以通过对象语法和数组语法进行动态绑定:

  1. 1.对象语法:
  2. <div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
  3. data: {
  4. isActive: true,
  5. hasError: false
  6. }
  7. 2.数组语法:
  8. <div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
  9. data: {
  10. activeClass: 'active',
  11. errorClass: 'text-danger'
  12. }