欢迎来到DIVCSS5查找CSS资料与学习DIV CSS布局技术!
  对于MVVM的理解
 
  由Model、View、ViewModel三部分构成,由MVC衍生。
 
  Model:层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑,
 
  View:代表UI组件,它负责将数据模型转化成UI展现出来,
 
  ViewModel:是一个同步View和Model的对象。
 
  在MVVM架构下,View和Model之间并没有直接的联系,而是通过ViewModel进行交互,Model和ViewModel之间的交互是双向的,因此View数据的变化会同步到Model中,而Model数据的变化也会立即反应到View上。(注意)
 
  ViewModel通过双向数据绑定把View层和Model层连接了起来,而View和Model之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全由MVVM来统一管理。
 
  Vue.js双向数据原理
 
  Vue.js可以说是MVVM架构的最佳实践,专注于MVVM中的ViewModel,不仅做到了数据双向绑定,而且也是一款相对来比较轻量级的JS库,API简洁,很容易上手。
 
  Vue.js是采用Object.defineProperty的getter和setter,并结合观察者模式来实现数据绑定的。当把一个普通Javascript对象传给Vue实例来作为它的data选项时,Vue将遍历它的属性,用Object.defineProperty将它们转为getter/setter。用户看不到getter/setter,但是在内部它们让Vue追踪依赖,在属性被访问和修改时通知变化。(注意:据悉vue3.0将采用Proxy替代Object.defineProperty)
 
  图的解析:
 
  Observer:数据监听器,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者,内部采用Object.defineProperty的getter和setter来实现。
 
  Compile:指令解析器,它的作用对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数。
 
  Watcher:订阅者,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数。
 
  Dep:消息订阅器,内部维护了一个数组,用来收集订阅者(Watcher),数据变动触发notify函数,再调用订阅者的update方法。
 
  执行过程:
 
  当执行newVue()时,Vue就进入了初始化阶段,一方面Vue会遍历data选项中的属性,并用Object.defineProperty将它们转为getter/setter,实现数据变化监听功能;另一方面,Vue的指令编译器Compile对元素节点的指令进行扫描和解析,初始化视图,并订阅Watcher来更新视图,此时Wather会将自己添加到消息订阅器中(Dep),初始化完毕。
 
  当数据发生变化时,Observer中的getter方法被触发(注意这里触发什么),getter会立即调用Dep.notify(),Dep开始遍历所有的订阅者,并调用订阅者的update方法,订阅者收到通知后对视图进行相应的更新。同理当表单输入内容发生变化时,就会触发setter,watcher监听机制就会执行,watcher通知Vue生成新的VDOM树,再通过render函数进行渲染,生成真实DOM。
 
  通过Object.defineProperty实现见简单的双向数据绑定:
 
  <body>
 
  <divid="demo"></div>
 
  <inputtype="text"id="inp">
 
  </body>
 
  <script>
 
  letobj={};
 
  letdemo=document.querySelector('#demo');
 
  letinp=document.querySelector('#inp');
 
  Object.defineProperty(obj,'name',{
 
  get:()=>{
 
  returninp.value;
 
  },
 
  set:(newVal)=>{//当该属性被赋值的时候触发
 
  inp.value=newVal;
 
  demo.innerHTML=newVal;
 
  }
 
  });
 
  inp.addEventListener('input',(e)=>{
 
  //给obj的name属性赋值,进而触发该属性的set方法
 
  obj.name=e.target.value;
 
  })
 
  obj.name='huqinggui';//在给obj设置name属性的时候,触发了set这个方法
 
  </script>
 
  为什么vue3.0要用Proxy替代Object.defineProperty实现双向数据绑定(待补充完善)
 
  替换不是因为不好,是因为有更好的方法使用效率更高
 
  那么到底为什么要用Proxy呢?既然想要替代了,说明一个有缺点,一个有优点的那么我们就来分析下他们的优缺点:
 
  Object.defineProperty的缺点:
 
  总体上说致命的缺点是:
 
  不能监听数组的变化
 
  必须遍历对象的每个属性
 
  必须深层遍历嵌套的对象
 
  细分就是以下几点:
 
  1.对IE11的兼容性(现在除了特殊的需求,基本上对IE都不考虑了)
 
  2.无法检测数组的变化
 
  Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。而且使用这些方法(push,pop,shift,unshift,splice,sort,reverse…)是不能触发set的,Vue中能监听是因为对这些方法进行了重写
 
  vara={},
 
  bValue=1;
 
  Object.defineProperty(a,"b",{
 
  set:function(value){
 
  bValue=value;
 
  console.log("setted");
 
  },
 
  get:function(){
 
  returnbValue;
 
  }
 
  });
 
  a.b=[];//setted
 
  a.b=[1,2,3];//setted
 
  a.b[1]=10;//无输出
 
  a.b.push(4);//无输出
 
  a.b.length=5;//无输出
 
  当a.b被设置为数组后,只要不是重新赋值一个新的数组对象,任何对数组内部的修改都不会触发setter方法的执行。所以要想实现实现数组的双向绑定,则必须通过Arr=newArr;这样的语句实现。同样常见的数组方法也不会触发,在框架中对这些方法进行了重写才能实现效果。
 
  3.只能监听属性,而不是监听对象本身,需要对对象的每个属性进行遍历
 
  对于原本不在对象中的属性难以监听。在Vue2.x里,是通过“callback+遍历data对象”来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象是才是更好的选择,而Proxy就显示了这方面的优势
 
  4.当对象增删的时候,是监控不到的
 
  比如:data={a:"a"},这个时候如果我们设置data.test="test",这个时候是监控不到的。因为在observedata的时候,会遍历已有的每个属性(比如a),添加getter/setter,而后面设置的test属性并没有机会设置getter/setter,所以检测不到变化。同样的,删除对象属性的时候,getter/setter会跟着属性一起被删除掉,拦截不到变化。
 
  ES6中的Proxy的优点:
 
  总的来说呢,Proxy是刚好解决了上述Object.defineProperty的缺点:
 
  针对对象:针对整个对象,而不是对象的某个属性,所以也就不需要对keys进行遍历。
 
  支持数组:Proxy不需要对数组的方法进行重载,省去了众多hack,减少代码量等于减少了维护成本,而且标准的就是最好的。
 
  当然除此之外还有以下几个原因:
 
  Proxy的第二个参数可以有13种拦截方法,这比起Object.defineProperty()要更加丰富
 
  Proxy作为新标准受到浏览器厂商的重点关注和性能优化,相比之下Object.defineProperty()是一个已有的老方法。
 
  vue中key值的作用(v-for)
 
  key的特殊属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes。如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用key,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。(有效的避免就地复用)
 
  有相同父元素的子元素必须有独特的key。重复的key会造成渲染错误。
 
  最常见的用例是结合v-for:
 
  <ul>
 
  <liv-for="iteminitems":key="item.id">...</li>
 
  </ul>
 
  它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用:
 
  完整地触发组件的生命周期钩子
 
  触发过渡
 
  <transition>
 
  <span:key="text">{{text}}</span>
 
  </transition>
 
  当text发生改变时,<span>会随时被更新,因此会触发过渡。
 
  vue中子组件调用父组件的方法
 
  子组件调用父组件的方法可以使用this.$emit()
 
  v-show和v-if指令的共同点和不同点?
 
  v-show指令是通过修改元素的displayCSS属性让其显示或者隐藏。
 
  v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果(注意:v-if可以实现组件的重新渲染),因此我们要尽量减少v-if的使用,因为它消耗性能。
 
  如何让CSS只在当前组件中起作用?
 
  将当前组件的<style>修改为<stylescoped>,关键点在scoped,代表作用域,限制css的作用在当前组件。的作用是什么?
 
  <keep-alive></keep-alive>的作用是什么?
 
  <keep-alive></keep-alive>包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
 
  大白话:比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用<keep-alive></keep-alive>进行缓存,
 
  这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染。
 
  Vue中引入组件的步骤?
 
  引入:
 
  1.采用ES6的import...from...语法
 
  2.CommonJS的require()方法引入组件
 
  注册
 
  Vue.component('my-component',
 
  {template:'<div>Acustomcomponent!</div>'})
 
  3.使用组件<my-component></my-component>
 
  指令v-el的作用是什么?
 
  提供一个在页面上已存在的DOM元素作为Vue实例的挂载目标.可以是CSS选择器,也可以是一个HTMLElement实例
 
  在Vue中使用插件的步骤
 
  1.采用ES6的import...from...语法
 
  2.使用全局方法Vue.use(plugin)使用插件,可以传入一个选项对象,需要
 
  Vue.use(MyPlugin,{someOption:true})
 
  请列举出3个Vue中常用的生命周期钩子函数?
 
  1.created:实例已经创建完成之后调用,在这一步,实例已经完成数据观测,属性和方法的运算,watch/event事件回调.然而,挂载阶段还没有开始,$el属性目前还不可见
 
  2.mounted:el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。如果root实例挂载了一个文档内元素,当mounted被调用时vm.$el也在文档内
 
  3.activated::keep-alive组件激活时调用
 
  请简述下Vuex的原理和使用方法
 
  数据单向流动
 
  一个应用可以看作是由上面三部分组成:View,Actions,State,数据的流动也是从View=>Actions=>State=>View以此达到数据的单向流动.
 
  但是项目较大的,组件嵌套过多的时候,多组件共享同一个State会在数据传递时出现很多问题.Vuex就是为了解决这些问题而产生的.
 
  Vuex可以被看作项目中所有组件的数据中心,我们将所有组件中共享的State抽离出来,任何组件都可以访问和操作我们的数据中心
 
  Vuex的组成:一个实例化的Vuex.Store由state,mutations和actions三个属性组成:
 
  1.state中保存着共有数据
 
  2.改变state中的数据有且只有通过mutations中的方法,且mutations中的方法必须是同步的
 
  3.如果要写异步的方法,需要些在actions中,并通过commit到mutations中进行state中数据的更改.
 
  vuewatch的高级用法--监听对象的属性变化
 
  1.监听对象需要深度监听,如下代码可以监听整个msg对象的变化
 
  watch:{
 
  msg:{
 
  handler(newValue,oldValue){
 
  console.log(newValue)
 
  },
 
  deep:true
 
  }
 
  }
 
  2.监听对象里面某个属性的变化,通过computed做中间层实现
 
  computed:{
 
  channel(){
 
  returnthis.msg.channel
 
  }
 
  },
 
  watch:{
 
  channel(newValue,oldValue){
 
  console.log('new:%s,old:%s',newval,oldVal)
 
  //这里面可以执行一旦监听的值发生变化你想做的操作
 
  }
 
  }
 
  

如需转载,请注明文章出处和来源网址:http://www.divcss5.com/html/h56596.shtml