1. 对于MVVM的理解
『View』:视图层(UI 用户操作界面),前端主要由 HTML ,CSS 和模板文件(vue)来构建
『ViewModel』:业务逻辑层(一切 js 可视为业务逻辑),连接视图与数据的中间件**,监听模型数据的改变和控制视图行为、处理用户交互
『Model』:数据层(存储数据及对数据的处理如增删改查)
- MVVM 将数据双向绑定(data-binding)作为核心思想,View 和 Model 之间没有联系,它们通过 ViewModel 这个桥梁进行交互。
- Model 和 ViewModel 之间的交互是双向的,因此 View 的变化会自动同步到 Model,而 Model 的变化也会立即反映到 View 上显示。
- 当用户操作 View,ViewModel 感知到变化,然后通知 Model 发生相应改变;反之当 Model 发生改变,ViewModel 也能感知到变化,使 View 作出相应更新。
- Viewmodel就相当于一个观察者,监控着双方的动作,并及时通知对方进行相应的操作
- View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,是前后端分离方案实施的重要一环
2. Vue实现数据双向绑定的原理(数据对于视图的驱动)
采用数据劫持结合发布者-订阅者模式
实现mvvm的双向绑定,就必须要实现:
1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
具体实现
- 首先,vuejs在实例化的过程中,会遍历实例化对象中data的所有属性,并使用 Object.defineProperty实现对属性的劫持, 把这些属性全部转为 getter/setter。
- 同时每一个实例对象都有一个watcher实例对象,他会在模板编译的过程中,用getter去访问data的属性,watcher此时就会把用到的data属性记为依赖,这样就建立了视图与数据之间的联系。
- 当之后我们渲染视图的数据依赖发生改变(即数据的setter被调用)的时候,watcher会对比前后两个的数值是否发生变化,然后确定是否通知视图进行重新渲染
3. Vue组件间的参数传递(有几种方法)
参考: https://www.cnblogs.com/barryzhang/p/10566515.html
4.Vue的路由实现:hash模式 和 history模式
-
hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取
- 不会重加载页面
- hash虽然在URL中,但不被包括在HTTP请求中
-
history模式:对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更
- 前端的 URL 必须和实际向后端发起请求的 URL 一致
-
histroy模式如何实现url变了,页面局部刷新
history.pushState、history.replaceState用于操作浏览器历史,可以做到无刷新改变页面URL
- pushState是将指定的URL添加到浏览器历史里
- replaceState是将指定的URL替换当前的URL
-
如何响应浏览器的前进、后退操作
window对象上提供了onpopstate事件,传递的state对象会成为event的子对象,可以拿到存储的title和URL,可以结合ajax和pushState完美的进行无刷新浏览
5.vue data, 计算属性,watcher区别
计算属性是基于它们的依赖进行缓存的计算属性只有在它的相关依赖发生改变时才会重新求值
通过其他变量计算得来的另一个属性,提供相对简单的数据计算
要在数据变化时执行异步或开销较大的操作时,你可以使用 watch,侦听一个特定的值,当该值变化时执行特定的函数自身值得改变前后的动作,观察某一特定的值,执行特定的函数
data定义以及初始化数据,对象或函数
6. 生命周期(在vue中渲染指定页数列表是在生命周期的哪个环节实现)
beforeCreate:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用
created:在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
beforeMount:在挂载开始之前被调用:相关的 render 函数首次被调用。
该钩子在服务器端渲染期间不被调用。以下周期在服务端渲染期间都不被调用。
mounted:el 被新创建的 vm,el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.el 也在文档内。注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted
beforeUpdate:数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
updated:由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
beforeDestroy: 实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁
7. vuex 是什么?有几个模块? 使用场景?
vuex 是一个全局仓库,里放了很多对象
store的状态是响应式的,也就是说在某一个组件里修改store,则可以得到全局的响应变更
有五种模块,分别是 State、 Getter、Mutation 、Action、 Module
State是数据源存放地,对应于与一般Vue对象里面的data
state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新,它通过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中
Getter是Store的计算属性,来实时监听state值的变化(最新状态)
虽然在组件内也可以做计算属性,但是getters 可以在多组件之间复用
Mutation定义的方法动态修改Vuex 的 store 中的状态或数据
Action异步操作数据
通过将mutations里面处理数据的方法变成可异步的处理数据的方法,view 层通过 store.dispath 来分发 action
使用场景:vuex 更多地用于解决跨组件通信以及作为数据中心集中式存储数据
-
解决非父子组件之间通信问题
-
存储的数据
1、组件之间全局共享的数据
2、通过后端异步请求的数据 比如做加入购物车、登录状态等都可以使用Vuex来管理数据状态。
8. vue数组监听实现
Vue.js 不能检测到下面数组变化
-
直接用索引设置元素,如
vm.items[0] = {}
;添加了一个$set()
方法 -
修改数据的长度,如
vm.items.length = 0
只需用一个空数组替换items
$remove()从目标数组中查找并删除元素
修改数组原型方法
-
push()
向数组末端添加元素 -
pop()
移除最后一个元素 -
shift()
移除数组中的第一个项并返回该项 -
unshift()
在数组前端添加任意个数组项并返回新数组的长度 -
splice()
向/从数组中添加/删除项目,然后返回被删除的项目,改变原始数组 arrayObject.splice(index,howmany,item1,.....,itemX) index 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。 howmany 必需。要删除的项目数量。如果设置为 0,则不会删除项目。 item1, ..., itemX 可选。向数组添加的新项目
-
sort()
按字符串排序 -
reverse()
反转
9. axios及axios请求拦截和响应拦截
一、Axios 是一个基于 promise 的 HTTP 库,支持promise所有的API
二、它可以拦截请求和响应
三、它可以转换请求数据和响应数据,并对响应回来的内容自动转换成 JSON类型的数据
四、安全性更高,客户端支持防御 XSRF
- axios请求拦截和响应拦截
- 首先自己新建一个axios文件夹用于存放请求和响应拦截器
- 在main.js中引入axios然后将其挂载到原型链上
axios.interceptors.request.use((request)
axios.interceptors.response.use((response)
10. 路由异步加载(懒加载)
- 异步组件
const Foo = () => Promise.resolve({ /* 组件定义对象 */ })
-
使用动态 import语法来定义代码分块点 或webpack中利用require.ensure()实现按需加载
-
通过
import(*)
语句来控制加载时机,webpack内置了对于import(*)
的解析,会将import(*)
中引入的模块作为一个新的入口在生成一个chunk,import()会返回一个Promise对象,所以为了让浏览器支持,需要事先注入
Promise polyfill -
把js模块独立导出一个个js文件,然后使用这个模块时,webpack会构造这个script dom元素,加入到document.head中,由浏览器自动发起异步请求这个js文件,再写个回调,去定义得到这个js文件后的业务逻辑
-
webpack 在编译时,会静态地解析代码中的 require.ensure(),同时将模块添加到一个分开的 chunk 当中。这个新的 chunk 会被 webpack 通过 jsonp来按需加载
11. vue运行机制
引入vue.js,new Vue()干了什么呢?
- 初始化
- 挂载组件
- 编译
- 响应式
- 虚拟DOM
- 更新视图
12. vue中key列表渲染时也会要求给每个组件添加上key这个属性?
默认用就地复用
策略;列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改,则重新渲染这一项,否则复用之前的元素;
vue实现了一套虚拟DOM,可以不直接操作DOM元素,只操作数据便可以重新渲染页面。而隐藏在背后的原理便是其高效的Diff算法
实现步骤
-
用JavaScript对象模拟DOM
-
把此虚拟DOM转成真实DOM并插入页面中
-
如果有事件发生修改了虚拟DOM
-
比较两棵虚拟DOM树的差异,得到差异对象
-
把差异对象应用到真正的DOM树上
当页面的数据发生变化时,Diff算法只会比较同一层级的节点
如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点以后的子节点了。
如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新
1. 两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构。
2. 同一层级的一组节点,他们可以通过唯一的id进行区分
为了高效的更新虚拟DOM
Diff算法
在采取diff算法比较新旧节点的时候,比较只会在同层级进行, 不会跨层级比较
比较两棵DOM树的差异是Virtual DOM算法最核心的部分
比较后会出现四种情况:
1、此节点是否被移除 -> 添加新的节点
2、属性是否被改变 -> 旧属性改为新属性
3、文本内容被改变-> 旧内容改为新内容
4、节点要被整个替换 -> 结构完全不相同 移除整个替换
网友评论