1、如何理解mvvm原理?
MVVM分为Model、View、ViewModel三者。
Model 代表数据模型,数据和业务逻辑都在Model层中定义;
View 代表UI视图,负责数据的展示;
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom
2、响应式数据的原理是什么?
当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。
每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
3、vue是如何检测数组变化的?
通过原型链去拦截对数组的操作,从而实现对操作数组这个行为的监听。
重写数组的方法,执行方法之后通知setter变动
vue2不可以通过下标、数组长度来响应修改数组数据
4、为何vue采用异步渲染
异步渲染和熟悉的节流函数最终目的是一致的,将多次数据变化所引起的响应变化收集后合并成一次页面渲染,从而更合理的利用机器资源,提升性能与用户体验。
提高性能,不频繁更新组件,因为vue是组件级更新视图,每一次update都要渲染整个组件,为了提高性能,
采用了队列的形式,存储同一个watcher的所有data属性变化,然后统一调用nextTick 方法进行更新渲染(有且只调用一次)。
5、nextTick实现原理?
当val第一次赋值时,页面会渲染出对应的文字,但是实际这个渲染变化会暂存,val第二次赋值时,再次暂存将要引起的变化,这些变化操作会被丢到异步API,Promise.then的回调函数中,等到所有同步代码执行完后,then函数的回调函数得到执行,然后将遍历存储着数据变化的全局数组,将所有数组里数据确定先后优先级,最终合并成一套需要展示到页面上的数据,执行页面渲染操作操作。
异步队列执行后,存储页面变化的全局数组得到遍历执行,执行的时候会进行一些筛查操作,将重复操作过的数据进行处理,实际就是先赋值的丢弃不渲染,最终按照优先级最终组合成一套数据渲染。
这里触发渲染的异步API优先考虑Promise,其次MutationObserver,如果没有MutationObserver的话,会考虑setImmediate,没有setImmediate的话最后考虑是setTimeout。
调用了 nextTick 之后,将watcher队列回调函数暂时存入了一个数组callbacks 中,然后才依次调用 timeFun()方法执行,
6、vue组件的生命周期
1.beforeCreate(){}在执行的时候,data还有methods都没有被初始化
2.created(){} data还有methods都被初始化好了,如果要调用methods方法或者操作data里面的数据,最早只能在created里面进行操作。
3.beforeMount(){} 表示模板已经在内存中编辑完成了,但是尚未渲染到模板页面中。即页面中的元素,没有被真正的替换过来,只是之前写的一些模板字符串。
4.mounted(){} 表示内存中模板已经真实的挂载到页面中去了,用户可以看到渲染好的界面了
注意这是一个生命周期函数的最后一个函数了,执行完这个函数表示 整个vue实例已经初始化完成了,组件脱离了创建阶段,进入运行阶段。
下面是运行期间的两个生命周期函数的钩子:
5.beforeUpdate(){} 表示我们的界面还没更新 但是data里面的数据是最新的。即页面尚未和最新的data里面的数据包吃同步。
6.update(){} 表示页面和data里面的数据已经包吃同步了 都是最新的。
7.beforeDestory(){} 当执行这个生命周期钩子的时候 vue的实例从运行阶段进入销毁阶段 此时实例身上的data 还有 methods处于可用的状态。
8.Destoryed(){} 表示组件已经完全被销毁了 组件中所有的实例方法都是不能用了
7、ajax请求放到哪一个生命周期
beforMouted与mouted
8、何时需要使用beforeDestory
解除自定义事件 event.$off时;清除定时器时;解除自定义的DOM事件,如window scroll等等
9、vue父子组件生命周期的调用顺序
10、vue中computed 的特点
11、watch 中的deep:true是如何实现的?
12、vue中事件绑定的原理
13、vue中v-html会导致哪些问题
可能会导致xss攻击
V-html更新的是元素的 innerHTML 。内容按普通 HTML 插入, 不会作为 Vue 模板进行编译 。
但是有的时候我们需要渲染的html片段中有插值表达式,或者按照Vue模板语法给dom元素绑定了事件。
在单文件组件里,scoped 的样式不会应用在 v-html 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。如果你希望针对 v-html 的内容设置带作用域的 CSS,你可以替换为 CSS Modules 或用一个额外的全局 <style>元素手动设置类似 BEM 的作用域策略。
后台返回的html片段,以及css样式和js,但是返回的js是不执行的,因为浏览器在渲染的时候并没有将js渲染,这时要在$nextTick中动态创建script标签并插入
14、vue中v-if和v-show的区别
v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;
而v-if会控制这个 DOM 节点的存在与否。
当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;
当只需要一次显示或隐藏时,使用v-if更加合理。
15、为什么v-for与v-if不能同时使用
当 Vue 处理指令时, v-for比 v-if 具有更高的优先级,v-if无法访问v-for里面变量
修改方案 使用空标签 template,让v-if在template上面
16、v-model中实现原理及如何自定义v-model
1.当在input输入框输入内容时,会自动的触发input事件,更新绑定的name值。
2.当name的值通过JavaScript改变时,会更新input的value值
17、组件中的data为什么是一个函数
组件复用时,各自的数据相互隔离,不受影响
18、vue组件如何通信
父传子通过poprs来接受;
子传父通过$emit定义时间来更新父组件上的值
兄弟组件可以通过ubus来通信
不相关联的组件多个的话推荐使用vuex共享数据
19、什么是作用域插槽
20、用一个vnode来描述一个DOM结构
21、diff算法的时间复杂度
22、简述vue中diff算法原理
23、v-for为什么要用key?
必须要使用key,且不能是index和random;vue中的diff算法要通过tag和key来判断,是否是sameNode;减少渲染次数,提升渲染性能;
24、描述组件渲染和更新过程
初次渲染过程:解析模板为render函数,然后触发vue响应式,监听data属性getter setter,执行render函数,生成vnode,patch(elem,vnode)。
更新过程:修改data,触发setter,重新执行render函数,生成newVnode,patch(vnode, newVnode)
25、vue中模板编译原理
第一步是将 模板字符串 转换成 element ASTs(解析器)
第二步是对 AST 进行静态节点标记,主要用来做虚拟DOM的渲染优化(优化器)
标记静态节点有两个好处:
每次重新渲染的时候不需要为静态节点创建新节点
在 Virtual DOM 中 patching 的过程可以被跳过
优化器的实现原理主要分两步:
第一步:用递归的方式将所有节点添加 static 属性,标识是不是静态节点
第二步:标记所有静态根节点
第三步是 使用 element ASTs 生成 render 函数代码字符串(代码生成器)
26、vue中常见的性能优化
v-for使用key值;加速虚拟DOM对比
路由使用懒加载
keep-alive缓存组件
v-if与v-show的合理使用
合理使用computer,有缓存
27、vue中相同的逻辑如何抽离
28、为什么要使用异步组件
29、谈谈你对keep-alive的了解
返回dom不让其重新刷新,在vue-view外面包一层, 当引入keep-alive的时候,页面第一次进 入,钩子的触发顺序created-> mounted-> activated,退出时触发deactivated。
当再次进入(前进或者后退)时,只触发activated。
只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中;
30、vue-router中的导航守卫有哪一些
全局前置守卫:router.beforEach((to, from, next)=>{})
路由独享的守卫:beforeEnter
组件内的守卫:beforeRouteEnter(to, from, next) { next(vm => {// 通过 `vm` 访问组件实例})}
(还不能使用this,因为当前组件还没有渲染出来,回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。)
beforeRouteUpdate (2.2 新增)
beforeRouteLeave
31、实现hash路由和history路由
32、action与mutation区别
33、简述vuex的工作原理
34、vue3.0ni知道有哪一些改进
35、vue-router基本使用
命名路由router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况
36、vue-router传参的两种方式,并说明两者区别
params与query这两种方式
query要用path来引入,params要用name来引入
query相当于get请求,页面跳转的时候,可以在地址栏看到请求参数 params相当于post请求,参数不会再地址栏中显示
query 刷新不会丢失 query里面的数据
params 刷新 会会 丢失 params里面的数据
37、vue与React的区别
react整体是函数式的思想,把组件设计成纯组件,状态和逻辑通过参数传入,所以在react中,是单向数据流,推崇结合immutable来实现数据不可变。react在setState之后会重新走渲染的流程,如果shouldComponentUpdate返回的是true,就继续渲染,如果返回了false,就不会重新渲染,PureComponent就是重写了shouldComponentUpdate,然后在里面作了props和state的浅层对比。