赞
踩
MVVM
的理解MVVM
是Model-View-ViewModel
的简写,是一个软件架构设计模式,是一种简化用户界面的事件驱动编程方式,由微软WPF
和Silverlight
的架构师于2005年发表的
MVVM
源自经典的Model-View-Controller
(MVC
)模式,MVVM
的出现极大促进了前端开发和后端业务逻辑的分离,极大提高了前端开发的效率,其核心是ViewModel
层,负责转换Model
中的数据,对数据进行处理和解析,向上与视图层进行双向数据绑定,向下与数据层通过接口请求进行数据交互
对其构成的三部分进行介绍:
View
:视图层,也就是用户界面,前端主要由HTML
和CSS
来构成Model
:数据模型,泛指后端进行各种业务逻辑处理和数据操控,对于前端来说就是后端提供的api
接口ViewModel
:视图逻辑层,由前端开发人员组织生成和维护的在ViewModel
层,前端开发者对从后端Model
获取的数据进行转换处理和解析,做二次封装,生成符合View
层使用的视图数据模式。需要注意的是ViewModel
所封装出来的数据模型包括视图的状态和行为两部分,而Model
层的数据模型是只包含状态的,比如页面这一块展示什么;但是页面加载进行时发生什么,点击页面发生什么,页面滚动的时候发生什么这些都属于视图行为(用户交互),视图状态和行为都封装在ViewModel
层,这样的封装使得ViewModel
可以更完整的去描述View
层
MVVM
框架实现了双向绑定,这样的ViewModel
的内容会实时展现在View
层,前端开发者不必再去操作dom
去更新视图,框架已经把最脏最累的一块已经做好了,我们开发者只需要处理和维持ViewModel
,更新数据视图也会自动更新。这样的View
层展现的不再是Model
层的数据,而是ViewModel
层的处理后的数据,由ViewModel
负责和Model
交互,完全解耦了View
和Model
,这个解耦是至关重要的,是前后端分离的重要一环
MVC
、MVP
和MVVM
的区别MVC
:View
-用户界面,Controller
-控制器,Model
-数据保存;
用户或View
传送指令给Controller
,Controller
完成业务逻辑,要求Model
改变状态,Model
将新数据发送到View
,用户得到反馈
View
非常厚,业务逻辑都部署在View
;Controller
非常薄,只能起到路由的作用
通信是单向的:v-c-m-v
MVP
:View
-用户界面,Presenter
-控制器,Model
-数据保存;
View
和Model
不发生联系,都通过Presenter
传递View
非常薄,不部署任何业务逻辑,Presenter
非常厚,所有逻辑部署都在Presenter
MVVM
:如第一条
Vue
的生命周期从创建到销毁的过程,被称为生命周期;从开始创建、初始化数据,编译模板,挂载DOM
,更新渲染,销毁这一系列过程,被称为vue
的生命周期
生命周期过程中有对应的钩子函数,开发者可以在对应内周期过程中做合适的事情,在vue
实例的过程中形成良好的代码逻辑
主要有8个钩子函数:
beforeCreate
:初始化空的Vue
实例对象,无法访问data
、methods
、computed
、watch
created
:实例化数据对象data
和methods
,进行数据初始化,无法访问DOM
beforeMount
:模板编译完成,为虚拟的DOM
节点,可对数据进行修改,不触发updated
mounted
:实例el
挂载完成,可访问真实DOM
,完成数据双向绑定,可通过$refs
对DOM
进行操作beforeUpdate
:发生在虚拟DOM
打补丁之前,适合在更新之前访问现有DOM
,可进行数据更改,但是不会重渲染updated
:新的DOM
已更新,避免在这个钩子函数操作数据,防止死循环beforeDestroy
:实例还可获取,this
还可调用,常用于销毁定时器、解绑事件destroy
:实例及其所有子实例均被销毁,数据绑定拆除、监听移除等其实这些钩子函数就是回调函数而已,创建组件过程会调用相应的钩子方法。主要是通过callHook
方法来调用的(源码可读),核心是一个发布订阅者模式,将钩子订阅好(内部才去数组方式存储),在对应的阶段进行发布
Vue
组件间的参数传递(组件通信)主要有三类通信:父子组件通信、兄弟组件通信、隔代组件通信
props
+ $emit
:比较常用就不介绍了refs
+ $parent / $children
:比较常用就不介绍了provide
+ inject
:主要解决跨级组件的通信问题,使用场景是子组件获取上级组件的状态,跨级组件间建立一种主动提供和依赖注入的关系
provide
:父组件提供变量或方法
provide(){
return {
title:'父组件的标题'
}
}
inject
:字组件注入依赖
inject:['title']
$attrs
+ $listeners
:主要用于多级组件嵌套需要传递数据时
$attrs
:(除了class
和style
)包含父作用域中不被props
识别且获取的的特性绑定,在组件上通过v-bind="$attrs"
传入内部组件,通常配合interitAttrs
选项使用$listeners
:(不含.native
修饰器的)包含父作用域中v-on
事件监听器,在组建上通过v-on="$listeners"
传入内部组件$attrs
与$listeners
是两个对象,$attrs
里存放的是父组件中绑定的非props
属性,$listeners
里存放的是父组件中绑定的非原生事件EventBus
:$emit / $on
,通过空的vue
实例作为中央事件总线(事件中心),用来触发事件和监听事件,从而实现通信
let event = new Vue()
event.$emit('sendData',data) //触发事件的组件中编写
event.$on('sendData',data => {console.log('拿到数据处理事情')}) //接收数据变化的组件
Vuex
:状态管理库,将应用状态都存储在store
中,各组件都通过getter
获取数据、mutation
(通过action
提交mutation
)更改数据
Vue
路由实现(两种路由模式:hash
、history
)vuex
vuex
是什么?一般来说,如果用到vue
框架,必不可少的就是使用vuex
这个核心插件。vuex
是专门为vue
服务的,用于管理页面间的数据状态、提供统一数据操作的生态系统,相当于数据库的MongoDB
、MySQL
等,任何组件都可以从仓库中存取数据
vuex
采用的是mcv
架构中的model
层,规定所有的数据都必须通过action-mutation-state
这个流程来改变状态,然后再结合vue
的数据双向绑定实现页面的更新
统一页面状态管理,可以让复杂的组件交互变得简单清晰,让组件间通信变得更方便,大大提高了vue
项目的开发效率
//安装插件 npm install vuex --save //在store目录下的index.js引入插件 import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.store({ state, getter, action, mutation, module }) //最后在main.js中使用 import store from './store' new Vue({ el:'#app', store })
state
:数据源存放地,是响应式的数据getter
: 可以认为是 store 的计算属性mutation
:更改 store 状态的唯一方法就是提交mutation
,接收事件类型和回调函数(必须是同步的),要遵守一些规则:
Vue.set(obj,'newProp',123)
或者state.obj = {...state.obj,newProp:123}
action
:action
提交的是mutation
,而不是直接变更状态,可以包含任何的异步操作module
:对 store 划分为多个模块,便于管理单页应用中,组件间的状态、音乐播放、登录状态、加入购物车等
action
和mutation
有什么区别主要是一个函数能否包含异步操作的区别,action
通过提交mutation
来变更状态,而不是直接变更
vue-router
vue-router
是如何实现的路由就是用来和后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,进行不同页面的渲染等
vue-router
使用 params
与 query
传参有什么区别params
传参路径接收需要params
用name
,query
用path
//路由跳转
this.$router.push({name:'xxx',params:{xx:xxx}})
this.$router.push({path:'xxx',query:{xx:xxx}})
//或者
<router-link :to="{name:'xxx',params:{xx:xxx}}"></router-link>
<router-link :to="{path:'xxx',query:{xx:xxx}}"></router-link>
//参数接收
this.$route.params
this.$route.query
params
:参数不显示在路径上,页面刷新参数丢失
query
:参数会显示在路径上,页面刷新不会丢失参数
$route
和$router
的区别$router
:访问当前路由器,是路由实例对象,包括路由跳转方法,钩子函数等,比如this.$router.push
$route
:访问当前路由,是当前路由信息的对象,包括path
、params
、hash
、query
、fullPath
、matched
、name
等信息
全局路由:beforeEach
、afterEach
、beforeEnter
组件路由:beforeRouteEnter
、beforeRouteUpdate
、beforeRouteLeave
Vue
、Angular
、React
三者区别Vue
和Angular
的区别相同点:都支持指令,包括内置指令和自定义指令;都支持过滤器,包括内置过滤器和自定义过滤器;都支持双向数据绑定;不支持低端浏览器
不同点:Angular
的学习成本高,入门需要更加深厚的js
功底,vue
的api
都比较简单直观;在性能上,Angular
依赖对数据做脏检查,watcher
越多性能越慢;vue
使用基于依赖追踪的观察并使用异步队列更新,所有数据都是独立触发的
Vue
和React
的区别相同点:React
采用特殊的jsx
语法,vue
在组建中推崇编写.vue
特殊文件格式,两者对文件内容都有一些约定;两者都需要编译后使用;中心思想相同(一切都是组件,组件实例之间可以嵌套,都提供合理的钩子函数,可以让开发者定制化的去处理需求);都支持加载插件,支持mixins
特性
不同点:React
采用的Virtual DOM
会对渲染出来的结果做脏检查;vue
在模板中提供了指令,过滤器等,可以方便快捷操作Virtual DOM
vue
组件中,如何让css
只在当前组件起作用在style
标签中添加scoped
属性即可,如<style scoped></style>
v-if
和v-show
的区别v-if
:真正的条件渲染,它会确保在切换过程中条件内的事件监听器和子组件适当的销毁和重建,也是惰性的,直到条件第一次变为真的时候,才会渲染条件块
v-show
:不管条件为真为假,都会进行渲染,只是通过样式设置display
属性来控制DOM
的显示和隐藏
两者应用场景:v-if
适用于条件较少改变不需要频繁切换条件的场景;v-show
适用于频繁切换条件的场景
nextTick
是用来做什么的nextTick
用在下次DOM
更新循环结束之后执行延迟回调,在修数据之后立即调用这个方法,获取更新后的DOM
Vue
组件中data
为什么是函数组件应该是可复用的vue
实例,一个组件被创建好之后就可能被用于各个地方,不管组件被复用多少次,组件中的data
数据都应该是相互隔离、互不影响的;
基于这一理念,如果data
是一个对象,而对象又属于引用类型,如果某一处复用的组件内的data
数据发生改变,其他复用地方的组件data
也会发生改变,这是不应该的
如果data
作为函数返回一个对象,那每一个实例之间的data
属性相互独立,就不会相互影响了
computed
和事件methods
有什么区别computed
是响应式的,methods
并非响应式computed
定义的成员是像属性一样访问,而methods
的成员必须是函数形式调用computed
是带缓存的,只有当其依赖的属性发生变化时才会重新计算,methods
里函数每次调用都会执行computed
中的成员可以定义一个函数作为只读属性也可以定义get/set
变成可读写属性,这点methods
无法实现computed
和监听器watch
有什么区别computed
data
中的属性或者是父组件传过来的props
中的属性,否则会报错get
方法,若设置对象形式设置get
方法和set
方法,当数据变化时,调用set
方法watch
data
中声明过的属性或者父组件传过来的props
属性,否则会报错jQuery
和Vue
有什么不同jQuery
专注于视图层,通过操作DOM
去实现页面的一些逻辑渲染;
Vue
专注于数据层,通过数据的双向绑定,最终表现在DOM
层,减少了DOM
操作;且使用组件化思维,使得项目各组件职责清晰,提高了开发效率,方便重复利用,便于协同开发
Vue
怎么自定义指令使用Vue
中的api
,如下所示
全局注册自定义指令:
Vue.directive('demo',{
inserted: function(el){el.focus()},
bind: function(el,binding,vnode){
console.log(binding.value)
}
})
局部注册自定义指令:
directives:{
demo:{
inserted: function(el){el.focus()}
}
}
Vue
怎么自定义过滤器使用Vue
中的api
,如下所示
//自定义过滤器
Vue.filter('my-filter',function(value){
return value*2
})
//使用
<span v-text="num | my-filter"></span>
keep-alive
的了解keep-alive
是一个抽象组件,自身不会渲染成一个DOM
元素,也不会出现在组件的父组件链中;只能包含一个直属子组件(与一个组件只有一个根元素类似),当包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们;
可以用于缓存组件保留状态,避免重新渲染,具有以下特性:
include
:表示只有名称匹配的组件会被缓存exclude
:表示任何名称匹配的组件都不会被缓存max
:表示最多可缓存的组件实例activated
和deactivated
,在组件激活和销毁时触发Vue
中key
的作用key
的特殊属性主要用在**Vue
的虚拟DOM
算法**,在新旧nodes
对比辨识VNodes
如果不使用key
,Vue
会使用一种最大限度减少动态元素并且尽可能的尝试就地修复或复用相同类型元素的算法,不设置key
可能会在列表更新时引发一些隐蔽bug
,或者使用过渡切换时无效果
如果使用key
,它会基于key
的变化重新排列元素顺序,并且会移除key
不存在的元素;有相同父元素的子元素必须有唯一的key
,重复的key
会造成渲染错误
使用key
的原理是vue
在patch
过程中通过key
可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch
过程更加高效,减少DOM
操作量,提高性能;最常用的用例是结合v-for
做循环渲染时
Vue
的核心是什么数据驱动、组件化
SPA
应用、介绍优缺点SPA
(single page application)单页面应用:只有一个主页面的应用,在Web页面初始化时一次加载相应的html
、css
、javascript
。用户切换不同的功能模块,是利用路由机制切换相关组件,实现的html
内容的替换,仅刷新局部资源,避免整个页面的重新加载
优点
SPA
相对服务器压力较小缺点
SEO
优化不友好SPA
应用首屏加载速度慢的问题主要分为两大部分:资源加载优化和页面渲染优化
http
请求次数
http
强缓存http
请求响应速度
CDN
DNS
:请求就近资源,减少网络传输时间,提高响应速度UI
框架按需加载,引入需要的组件,不要一次性全部引入http
代码
js
外链放在底部css
外链放在顶部DOM
数量js
、css
代码
css
选择器的复杂性Vue
有哪些指令v-for
、v-if
、v-show
、v-text
、v-html
、v-bind
、v-once
、v-on
等
Vue
实现数据双向绑定的原理vue
数据双向绑定是指:数据变化驱动视图,视图变化更新数据
实现数据双向绑定过程如下:
Observer
:对data
数据对象进行遍历,利用Object.defineProperty()
对各个属性进行getter
、setter
劫持Compile
:解析vue
模板指令,将模板中的变量都替换成数据,渲染页面,并为每个指令节点绑定更新函数,添加监听数据的订阅者Watcher
,一旦数据有变动收到通知,调用更新函数进行数据更新Watcher
:是Observer
和Compile
之间通信的桥梁,主要任务是订阅Observer
属性变化的消息,触发解析器Compile
的对应更新函数Dep
:订阅器采用发布-订阅的设计模式,用来收集订阅着Watcher
,对监听器Observe
和解析器Compile
进行统一管理简单说:通过Observer
来监听自己的数据变化,通过Compile
来解析编译模板指令(vue
中是用来解析{{}}
),最终利用Watcher
搭起Observer
和Compile
之间的通信桥梁,达到数据变化->视图更新;视图交互变化(input)->数据变更双向绑定效果
Vue
的响应式原理(第四点比较:Vue
实现数据双向绑定的原理)当一个Vue
实例创建时,Vue
会遍历data
返回对象的所有属性,用Object.defineProperty
将他们转为getter/setter
,并在内部追踪相关依赖,在属性被访问和修改时通知变化
每个组件实例都有相应的watcher
实例 ,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter
被调用时,会通知watcher
重新计算,从而使它关联的组件得以更新
单向数据流:顾名思义,数据流是单向的,数据以单一方向传输,便于追踪变化
比如父子组件,props
的更新会向下传递到子组件,反过来则不行,这样会防止从子组件意外改变父组件的状态,从而导致你的应用的数据流向难以理解;其次就是UI
改变,就要走action-state-view-action
流程
双向数据绑定:数据之间是相通的,数据变更的操作隐藏在框架内部,优点是在表单交互较多的场景下,会简化大量与业务无关的代码;缺点是无法追踪局部状态的变化,增加了出错时debug
的难度
Vue
中如何在组件内部实现一个双向数据绑定假设有一个输入框组件,用户在输入时,同步父组件页面中的数据
具体思路:父组件通过props
传值给子组件,子组件通过$emit
来通知父组件修改相应的props
值,具体实现如下:
//子组件 const component = { props:['value'], template:` <div> <input type="text" @input="handleInput" :value="value"/> </div> `, data(){ return{} }, methods:{ handleInput(e){ this.$emit('input',e.target.value) } } } //父组件 new Vue({ components:{CompOne:component}, el:'#root', template:` <div> <!--><comp-one :value="value" @input="value = arguments[0]"></comp-one>-> <comp-one v-model="value"></comp-one>//简化写法 </div> `, data(){ return{ value:'123' } } })
v-model
的原理是什么v-model
本质上是语法糖,在表单input
、textarea
、select
等元素上创建双向数据绑定,负责监听用的输入事件以更新数据,对一些极端场景进行一些特殊处理
v-model
在不同的表单元素上使用不同属性抛出不同事件
text
和textarea
元素使用value
和input
事件checkBox
和radio
使用checked
和change
事件select
使用value
作为prop
和change
事件如果是自定义组件,v-model
默认会利用名为value
的prop
和名为input
的事件
Vue
中给data
中的对象属性添加一个新的属性时会发生什么,如何解决如果给data
中的对象属性添加一个新的属性,该属性可以添加成功,但是视图并未实时更新,因为其不是响应式属性;Vue
实例在初始化的时候会遍历data
中的所有属性利用Object.defineProperty
为每一个属性添加getter/setter
,并在内部追踪依赖,当数据被读取或者发生变更时会通知watcher
重新计划,使得关联的组件进行更新
解决办法是使用this.$set
,将其处理成一个响应式属性。
delete
和Vue.delete
删除数组有何区别delete
使被删除的元素变为空,其他元素的键值不变
Vue.delete
删除元素,并重新排序数组的键值
大致分为8步:
URL
并回车URL
是否存在缓存,并比较缓存是否过期DNS
解析URL
对应的ip
IP
建立TCP
连接(三次握手)HTTP
请求HTTP
响应DOM
树,解析css
和 js
,渲染页面,直至显示完成TCP
连接(四次挥手)jQuery
获取的DOM
对象和原生的DOM
对象有何区别jQuery
获取的DOM
对象是数组对象;js
原生获取的DOM
对象是一个对象,是不同的对象类型
原生转jQuery
let div = document.getElementById('box')
let $div = $(div)
jQuery
转原生
let $div = $('#box')
let div = $div[0]
jQuery
如何扩展自定义方法//方法一
(jQuery.fn.myMethod = function(){
alert('myMethod')
})
//方法二
(function($){
$.fn.extend({
myMethod:function(){
alert('myMethod')
}
})
})(jQuery)
//使用
$('#div').myMethod()
vue
的mixins
mixins
选项接受一个混入对象的数组,这些混入对象可以像正常的实例对象一样包含实例选项,这些选项最终被合并到实例的选项当中去
mixins
被各组件调用,其属性和方法是独立,不相互影响的mixins
中混合对象的钩子函数在组件钩子函数之前先调用用处:可以定义公用的变量和方法,在每个组件中使用,变量和方法相互独立
组件:在父组件引入子组件,相当于在父组件中开辟出一片独立的空间给子组件使用,根据props
来传值,本质上是互相独立的
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。