mvc和mvvm理解
MVC
MVC即Model View Controller,简单来说就是通过controller的控制去操作model层的数据,并且返回给view层展示。
- View 接受用户交互请求
- View 将请求转交给Controller处理
- Controller 操作Model进行数据更新保存
- 数据更新保存之后,Model会通知View更新
- View 更新变化数据使用户得到反馈
MVVM
MVVM即Model-View-ViewModel,将其中的 View 的状态和行为抽象化,让我们可以将UI和业务逻辑分开。MVVM的优点是低耦合、可重用性、独立开发。
- View 接收用户交互请求
- View 将请求转交给ViewModel
- ViewModel 操作Model数据更新
- Model 更新完数据,通知ViewModel数据发生变化
- ViewModel 更新View数据
MVVM模式和MVC有些类似,但有以下不同
- ViewModel 替换了 Controller,在UI层之下
- ViewModel 向 View 暴露它所需要的数据和指令对象
- ViewModel 接收来自 Model 的数据
概括起来,MVVM是由MVC发展而来,通过在Model之上而在View之下增加一个非视觉的组件将来自Model的数据映射到View中。
响应原理
vue采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty劫持data属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
生命周期函数
- beforeCreate(创建前) vue实例的挂载元素$el和数据对象 data都是undefined, 还未初始化
- created(创建后) 完成了 data数据初始化, el还未初始化
- beforeMount(载入前) vue实例的$el和data都初始化了, 相关的render函数首次被调用
- mounted(载入后) 此过程中进行ajax交互
- beforeUpdate(更新前)
- updated(更新后)
- beforeDestroy(销毁前)
- destroyed(销毁后)
组件data为什么返回函数
组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data。如果单纯的写成对象形式,就使得所有组件实例共用了一份data,造成了数据污染。
vue给对象新增属性页面没有响应
由于Vue会在初始化实例时对属性执行getter/setter转化,所以属性必须在data对象上存在才能让Vue将它转换为响应式的。Vue提供了$set方法用来触发视图更新。
export default { data(){ return { obj: { name: 'fei' } } }, mounted(){ this.$set(this.obj, 'sex', 'man') }}复制代码
v-if和v-show区别
v-if 是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。
所以,v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。
v-model双向绑定原理
v-model本质上是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件。
- text 和 textarea 元素使用 value 属性和 input 事件
- checkbox 和 radio 使用 checked 属性和 change 事件
- select 字段将 value 作为 prop 并将 change 作为事件
所以我们可以v-model进行如下改写:
// 等同于复制代码
这个语法糖必须是固定的,也就是说属性必须为value,方法名必须为:input。
知道了v-model的原理,我们可以在自定义组件上实现v-model。
//Parent {{num}} export default { data(){ return { num: 0 } }}//Child
Add
export default { props: ['value'], methods:{ add(){ this.$emit('input', this.value + 1) } }}复制代码
key的作用
- 让vue精准的追踪到每一个元素,高效的更新虚拟DOM。
- 触发过渡
{{ text }}复制代码
当text改变时,这个元素的key属性就发生了改变,在渲染更新时,Vue会认为这里新产生了一个元素,而老的元素由于key不存在了,所以会被删除,从而触发了过渡。
scoped属性作用
在Vue文件中的style标签上有一个特殊的属性,scoped。当一个style标签拥有scoped属性时候,它的css样式只能用于当前的Vue组件,可以使组件的样式不相互污染。如果一个项目的所有style标签都加上了scoped属性,相当于实现了样式的模块化。
scoped属性的实现原理是给每一个dom元素添加了一个独一无二的动态属性,给css选择器额外添加一个对应的属性选择器,来选择组件中的dom。
dom
复制代码
vue将代码转译成如下:
.box[data-v-11c6864c]{ background:red;}
dom
复制代码
scoped样式穿透
scoped虽然避免了组件间样式污染,但是很多时候我们需要修改组件中的某个样式,但是又不想去除scoped属性。
- 使用/deep/
//Parent//Child复制代码
- 使用两个style标签
//Parent//Child复制代码
ref的作用
- 获取dom元素this.$refs.box
- 获取子组件中的datathis.$refs.box.msg
- 调用子组件中的方法this.$refs.box.open()
computed和watch区别
1.当页面中有某些数据依赖其他数据进行变动的时候,可以使用计算属性computed。
{{fullName}}export default { data(){ return { firstName: 'xie', lastName: 'yu fei', } }, computed:{ fullName: function(){ return this.firstName + ' ' + this.lastName } }}复制代码
2.watch用于观察和监听页面上的vue实例,如果要在数据变化的同时进行异步操作或者是比较大的开销,那么watch为最佳选择。
{{fullName}}export default { data(){ return { firstName: 'xie', lastName: 'xiao fei', firstName: 'xie xiao fei' } }, watch:{ firstName(val) { this.fullName = val + ' ' + this.lastName }, lastName(val) { this.fullName = this.firstName + ' ' + val } }}复制代码
vue路由有几种模式
- hash模式
- history模式
组件之间的传值通信
- 父组件给子组件传值通过props
- 子组件给父组件传值通过$emit触发回调
- 兄弟组件通信,通过实例一个vue实例eventBus作为媒介,要相互通信的兄弟组件之中,都引入eventBus
//main.jsimport Vue from 'vue'export const eventBus = new Vue()//brother1.vueimport eventBus from '@/main.js'export default{methods: { toBus () { eventBus.$emit('greet', 'hi brother') }}}//brother2import eventBus from '@/main.js'export default{ mounted(){ eventBus.$on('greet', (msg)=>{ this.msg = msg }) }}复制代码
axios拦截器怎么配
// 添加请求拦截器axios.interceptors.request.use(function (config) { // 在发送请求之前做些什么 return config;}, function (error) { // 对请求错误做些什么 return Promise.reject(error);});// 添加响应拦截器axios.interceptors.response.use(function (response) { // 对响应数据做点什么 return response; }, function (error) { // 对响应错误做点什么 return Promise.reject(error); });复制代码
链接:https://juejin.im/post/5df1e312f265da33d039d06d