一、对于MVVM的理解
MVVM 是 Model-View-ViewModel 的缩写。
- Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。
- View 代表视图模型,它负责将数据模型转化成UI 展现出来。View 层不负责处理状态,View 层做的是 数据绑定的声明、 指令的声明、 事件绑定的声明。
- ViewModel监听数据的改变和控制视图行为、处理用户交互,它就是一个同步View 和 Model的对象,连接Model和View。
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 View 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
ViewModel通过双向数据绑定把View层和Model层连接起来,而View和Model之间的同步工作完全是自动的,无需人为干涉,因此开发者只需要关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全由MVVM来统一管理
MVVM优缺点
- 优点:
1)分离视图(View)和模型(Model),降低代码耦合,提高视图或者逻辑的重用性
2)提高可测试性: ViewModel的存在可以帮助开发者更好地编写测试代码
3)自动更新dom: 利用双向绑定,数据更新后视图自动更新,让开发者从繁琐的dom操作中解放 - 缺点:
1)Bug很难被调试:数据绑定使得一个位置的Bug被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了。另外,数据绑定的声明是指令式地写在View的模版当中的,这些内容是没办法去打断点debug的
2)一个大的模块中model也会很大,虽然使用方便也并保证了数据的一致性,当时长期持有,不释放内存就造成了花费更多的内存
3)对于大型的图形应用程序,视图状态较多,ViewModel的构建和维护的成本都会比较高
vue对css的操作可以通过绑定class或者绑定style。
二、vue框架与jQuery类库的区别
Vue直接操作视图层,它通过Vue对象将数据和View完全分离开来了。对数据进行操作不需要引用相应的DOM节点,只需要关注逻辑,完全实现了视图层和逻辑层的解耦;
Jquery的操作是基于DOM节点的操作,jQuery是使用选择器($)选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的js的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的。它的优势在于良好的封装和兼容,使调用简单方便。
三、vue的生命周期
Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。
vue的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后。
第一次页面加载会触发 beforeCreate, created, beforeMount, mounted 这几个钩子函数;DOM 渲染在 mounted 中就已经完成了。官方实例的异步请求是在mounted生命周期中调用的,而实际上也可以在created生命周期中调用。
beforeCreate(创建前) :数据观测和初始化事件还未开始
created(创建后):完成数据观测,属性和方法的运算,初始化事件,el属性还没有显示出来。
beforeMount(挂载前) :在挂载开始之前被调用,相关render函数首次被调用。实例完成以下配置:编译模板,把data里面的数据和模板生成html,但是没有挂载html到页面中。
mounted(挂载后):挂载到实例之后被调用,实例完成以下配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。
beforeUpdate(更新前):在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
updated(更新后):在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
beforeDestroy(销毁前): 在实例销毁之前调用。实例仍然完全可用。
destroyed(销毁后): 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
activited:keep-alive专属,组件被激活时调用
deactivated:keep-alive专属,组件被激活时调用
四、Vue实现数据双向绑定的原理:Object.defineProperty()
vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。
要想实现mvvm,主要包含两个方面,视图变化更新数据,数据变化更新视图.
- 1)view变化更新data:可以通过事件监听实现
- 2)data变化更新view:通过
Object.defineProperty( )
对属性设置一个set函数,当属性变化时就会触发这个函数,所以我们只需要将一些更新的方法放在set函数中就可以实现data变化更新view了. - 3)具体过程:
首先
要对数据进行劫持监听,所以要设置一个监听器Observer,用来监听所有的属性,当属性变化时,就通知订阅者Watcher,看是否需要更新。属性可能是多个,所以会有多个订阅者,故需要一个消息订阅器Dep来专门收集这些订阅者,并在监听器Observer和订阅者Watcher之间进行统一的管理。
因为在节点元素上可能存在一些指令,所以还需要一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令初始化成一个订阅者Watcher,并替换模板数据并绑定相应的函数,这时候当订阅者Watcher接受到相应属性的变化,就会执行相对应的更新函数,从而更新视图.
总结:
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
详情请读:
https://www.jianshu.com/p/0c0a4513d2a6
五、vue-cli是什么?
Vue.js
提供一个官方命令行工具,可用于快速搭建大型单页应用(在一个完成的应用或者站点中,只有一个完整的HTML页面,这个页面有一个容器,可以把需要加载的代码(以组件的方式)插入到该容器中)。
该工具提供开箱即用的构建工具配置,带来现代化的前端开发流程。只需几分钟即可创建并启动一个带热重载、保存时静态检查以及可用于生产环境的构建配置的项目。
assets文件夹是放静态资源;components是放组件;router是定义路由相关的配置;view视图;app.vue是一个应用主组件;main.js是入口文件等等
六、Vue组件如何通信
props/$emit+v-on
: 通过props将数据自上而下传递,而通过$emit和v-on来向上传递信息。- 中央事件总线
EventBus
: 通过EventBus进行信息的发布与订阅,实现非父子组件之间的通信 - vuex: 是全局数据管理库,可以通过vuex管理全局的数据流
v-model
方式:直接绑定父组件变量,把数据从子组件传回父组件
七、vuex是什么?
Vuex 类似 Redux 的状态管理器,用来管理Vue的所有组件状态。
八、vue组件中的data为什么是一个函数?
组件是可复用的vue实例,一个组件被创建好之后,就可能被用在各个地方,而组件不管被复用了多少次,组件中的data数据都应该是相互隔离,互不影响的,基于这一理念,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响。
类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。
九、computed和watch有什么区别?
- computed:
1、computed是计算属性,也就是计算值
2、computed具有缓存性,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算
3、computed适用于计算比较消耗性能的计算场景
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
- ** watch**
1、Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。
2、无缓存性,页面重新渲染时值不变化也会执行
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},