1、MVC和MVVM区别?
MVC全名是Model View Controller,是模型(model)-试图(view)-控制器(controller)的缩写,一种软件设计典范。
Model(模型):是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
View(视图):是应用程序中处理数据显示的部分。通常试图是依据模型数据创建的。
Controller(控制器):是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
MVC的思想:一句话描述就是Controller负责将Model的数据用View显示出来,换句话说就是Controller里面把Model的数据赋值给View。
MVVM新增了VM
ViewModel层:做了两件事达到了数据的双向绑定,一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM事件监听。
MVVM与MVC最大的区别就是:它实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作DOM元素。因为在MVVM中,View不知道Model的存在,Model和ViewModel也观察不到View,这种低耦合模式提高了代码的可重用性。
注意:Vue并没有完全遵循MVVM的思想,这一点官网也有说明。
那么问题来了,为什么官网要说Vue没有完全遵循MVVM思想呢?
答:严格的MVVM要求View不能和MOdel直接通信,而Vue提供了$refs这个属性,让Model可以直接操作View,违反了这一规定,所以说Vue没有完全遵循MVVM。
2、为什么data是一个函数?
组件中的data写成一个函数,数据以函数返回值定义,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有的组件实例共用一份data,就会造成一个变了全都会变的结果。
3、Vue组件通讯有哪几种方式?
Props和emit父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件来做到的。
$parent/children获取当前组件的父组件和当前组件的子组件。
$refs获取组件实例
eventBus兄弟组件数据传递,这种情况下可以使用事件总线的方式
vuex状态管理
4、Vue生命周期方法有哪些,一般在哪一步请求?
beforeCreate在实例初始化之后,数据观测(data observer)和event/watcher事件配置之前被调用。在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。
created实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算,watch/event事件回调。这里没有
e
l
,如果非要想与
D
o
m
进行交互,可以通过
v
m
.
el,如果非要想与Dom进行交互,可以通过vm.
el,如果非要想与Dom进行交互,可以通过vm.nextTick来访问Dom。
beforeMount在挂载开始之前被调用:相关的render函数首次被调用。
mounted在挂载完成之后发生,在当前阶段,真实的Dom挂载完毕,数据完成双向绑定,可以访问到Dom节点。
beforeUpdate数据更新时调用,发生在虚拟Dom重新渲染和打补丁(patch)之前。可以在这个钩子中进一步地更改状态,这不会触发附加的冲渲染过程。
updated发生在更新完成之后,当前阶段组件的Dom已完成更新。要注意的是在此期间更改数据,因为这可能会导致无限循环的更新,该钩子在服务器端渲染期间不被调用。
beforeDestroy实例销毁之前调用。在这一步实例仍然完全可用。我们可以在这时进行善后收尾工作,比如清除计时器。
destroyed Vue实例销毁后调用。调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
activated keep-alive专属,组件被激活时调用。
deactivated keep-alive专属,组件被销毁时调用。
异步请求在哪一步发起?
可以在钩子函数created、beforeMOunt、mounted中进行,因为在这三个钩子函数中,data已经创建,可以将服务端返回的数据进行赋值。
如果异步请求不需要依赖Dom推荐在created钩子函数中调用异步请求,因为在created钩子函数中调用异步请求有以下优点:
能更快获取服务端数据,减少页面loading时间;
ssr不支持beforeMount、mounted钩子函数,所以放在created中有助于一致性。
5、v-if和v-show的区别
v-if在编译过程中会被转化成三元表达式,条件不满足时不渲染此节点。
v-show会被编译成指令,条件不满足时控制样式将对应的节点隐藏(display:none)。
使用场景:
v-if适用于运行时很少改变条件,不需要频繁切换条件的场景;
v-show适用于需要非常频繁切换条件的场景。
扩展补充:display:none visibility:hidden和opacity:0之间的区别?
三者共同点都是隐藏。不同点:
一.是否占据空间
Display:none,不占据位置;visibility:hidden和opacity:0占据位置。
二.子元素是否继承
display:none不会被子元素继承,父元素都不存在了,子元素也不会显示出。
visibility:hidden会被子元素继承,通过设置子元素visibility:visible来显示子元素。
Opacity:会被子元素继承,但是不能设置子元素opacity:0来重新显示。
三.事件绑定
Display:none的元素都已经不在页面存在了,因此无法触发它绑定的事件。
visibilty:hidden不会触发它上面绑定的事件。
opacity:0元素上面绑定的事件是可以触发的。
四.过渡动画
Transition对于display是无效的
Transitioon对于visibility是无效的
Transition对于opacity是有效的
6、怎么理解vue的单向数据流
数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改。这样会防止从子组件意外改变父组件的状态,从而导致你的应用的数据流向难以理解。
注意:在子组件直接用v-model绑定父组件传过来的prop,这样是不规范的写法,开发环境会报警告。
如果实在要改变父组件的prop值,可以在data里面定义一个变量,并用prop的值初始化它,之后用$emit通知父组件去修改。
7、computed和watch的区别和运用场景
computed是计算属性,依赖其他属性计算值,并且computed的值有缓存,只有当计算值变化才会返回内容,它可以设置getter和setter.
watch监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。
计算属性一般用在模板渲染中,某个值是依赖了其他的响应式对象甚至是计算属性计算而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑。
8、v-if 与 v-for 为什么不建议一起使用
1.v-if不能和v-for一起使用的原因是v-for的优先级比v-if高,一起使用会造成性能浪费。
解决方案有两种:把v-if放在v-for的外层或者把需要v-for的属性先从计算属性中过滤一次。
2.v-if和v-for的优先级问题在vue3中不需要考虑,vue3更新了v-if和v-for的优先级,使v-if的优先级高于v-for。