1、vue是什么?
2、vue有哪些优点?
轻量级
易于开发,中文文档,对国人友好
数据驱动视图,减少dom操作
渐进式开发
*双向数据绑定
3、父组件如何向子组件传递数据?
4、子组件如何向父组件通信?
一:在父组件中子组件上绑定自定事件
二:在子组件中通过this.$emit()触发自定义事件
5、平行组件之间如何传递数据?
一:在入口文件main.js 中,通过Vue.protptype.this.bus = new Vue()创建中央事件总线
二:然后通过this.bus.$emit()和this.bus.$on()来实现平行组件之间传递数据
6、为什么使用key?
答:需要使用key来为每一个节点做一个唯一标识,让vue(Diff算法)更好的正确识别此节点
作用为了高效的更新虚拟DOM
7、什么生命周期函数?
每个Vue实例在创建是都要经过一系列的初始化的过程,从开始创建,初始化数据,编译模板,挂载Dom,数据变化时更新Dom,卸载等一系列过程,这一系列过程称之为生命周期函数
8、生命周期钩子(即vue实例创建时经历的一系列过程每一个过程所执行的函数)
beforeCreate():在new vue创建后,只有默认的钩子函数和事件被创建,这个时候的data和methods还没有初始化,这个阶段不能使用data中的数据和methods中的方法
created():实例创建完成后,data中的数据和methods中的方法已经初始化,最早可以在这个时候进行调用(Dom还没有生成)
beforeMount():将编译完成的html挂载到对应的虚拟DOM时触发的钩子,此时页面还没有内容
(即将挂载)
mounted():执行到这个时候的钩子函数表明vue实例已经初始化完成,组件已经脱离创建阶段,进入到运行阶段,如果需要操作DOM上的节点,最早可以在这个阶段进行
beforeUpdate():这个阶段data中的数据已经更新,但是页面中的数剧还没有与data同步,还是原始的数据
update():这个阶段的页面和data中的数据都是最新的
beforeDestroy():vue实例从运行阶段进入到销毁阶段,这个时候的所有data和methods,指令,过滤器都是可用的,还没有被真正销毁
dastroyed():这个阶段的这个时候的所有data和methods,指令,过滤器都是不可用的,组件已经被销毁
9、Vue实现双向绑定原理
Object.difindProperty():能够直接在一个对象上定义一个新属性,或者修改已经存在的属性
vue实现双向数据绑定主要是采用数据劫持结合发布者-订阅者模式,通过Object.difindProperty()来劫持各个属性的setter,getter,数据变动时发布消息给订阅者,触发相应监听回调 
所以要实现一个mvvm的双向数据绑定,我们必须实现以下几点:
- 一个数据监听器-Observer:能够对数据对象的所有属性进行监听,如有变化则拿到那个最新的值通知订阅者
- 一个解析指令的指令解析器-Compile:对每个元素节点进行扫描和解析根据指令模板替换数据以及绑定相应的更新函数
- 一个Watcher:作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
- mvvm入口函数,整合以上三者
Observer的简单实现:
//observer要实现的的是,通过obj.defineProperty()来劫持数据对象的各个属性//通过setter和getter来监听数据对象的属性, 然后通知订阅者触发相关的监听函数//实现observer的思路//1、将observer的数据对象遍历递归,包括子属性对象的属性,都加上 setter和getter 当给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化//2、obj.defineProperty()监听各个属性的变动var data = {name: "LZH",age: 18}function observer(data) {if (!data || typeof data !== "object") {return console.log("data is not a object");}//Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致// console.log(Object.keys(data));Object.keys(data).forEach(function (key) {//key为属性名//2 给每一个属性通过obj.defineProperty()劫持属性的setter getterdefineReactive(data, key, data[key]);})}function defineReactive(data, key, keyVal) {//observer(keyVal) //监听子属性对象//configurable:false,//能否使用delete、能否需改属性特性、或能否修改访问器属性、,false为不可重新定义,默认值为true//enumerable:false,//对象属性是否可通过for-in循环,flase为不可循环,默认值为true//writable:false,//对象属性是否可修改,flase为不可修改,默认值为true//value:'xiaoming' //对象属性的默认值,默认值为undefinedObject.defineProperty(data, key, {enumerable: true, //可枚举configurable: false,get: function () {return keyVal;},set: function (newVal) {console.log('监听到值变化了 ', keyVal, ' --> ', newVal);keyVal = newVal}})}observer(data);data.age = 20;
10、Vue-router中hash和history的区别
前端路由的实现方式
路由需要实现三个功能:
- 当浏览器地址变化时,切换页面;
- 点击浏览器【后退】、【前进】按钮,网页内容跟随变化;
- 刷新浏览器,网页加载当前路由对应内容;
在单页面应用web网页中,单纯的浏览器地址改变,网页不会重载,如单纯的hash网址改变网页不会变化,因此我们的路由主要通过监听事件,并利用js实现动态改变网页内容,有两种实现方式:
- hash模式:监听浏览器地址hash值变化,执行相应的js切换网页
- history模式:利用history API实现url地址的改变,网页内容改变
他们的区别最明显的就是hash在浏览器地址后面会带#,而history可以自定义地址
hash模式
利用window.location.hash属性及窗口的onhashchange事件,可以实现监听浏览地地址hash值得变化,实现网页的切换。下面具体介绍几个使用过程中必须理解的要点:
- hash指的是地址中#号以及后面的字符,也称为散列值。hash也称作锚点,本身是用来做页面跳转定位的。如http://localhost/index.html#abc,这里的#abc就是hash;
- 散列值是不会随请求发送到服务器端的,所以改变hash,不会重新加载页面;
- 监听 window 的 hashchange 事件,当散列值改变时,可以通过 location.hash 来获取和设置hash值;location.hash值的变化会直接反应到浏览器地址栏;
vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载
history模式
- window.history 属性指向 History 对象,它表示当前窗口的浏览历史。当发生改变时,只会改变页面的路径,不会刷新页面。
- History 对象保存了当前窗口访问过的所有页面网址。通过 history.length 可以得出当前窗口一共访问过几个网址。
- 由于安全原因,浏览器不允许脚本读取这些地址,但是允许在地址之间导航。
- 浏览器工具栏的“前进”和“后退”按钮,其实就是对 History 对象进行操作
history对象主要有两个属性:
- history.length:当前窗口访问过的网址数量(包括当前网页)
- history.state:history堆栈最上层的状态值
history.pushState()
该方法用于在历史记录中添加一条记录。pushState()方法不会触发页面刷新,只会导致history对象发生变化,地址栏会有变化
语法:pushState(obj,title,url)
- object:是一个对象,通过 pushState 方法可以将该对象内容传递到新页面中。如果不需要这个对象,此处可以填 null。
- title:指标题,几乎没有浏览器支持该参数,传一个空字符串比较安全。
- url:新的网址,必须与当前页面处在同一个域。不指定的话则为当前的路径,如果设置了一个跨域网址,则会报错。
缺点:history模式下,前端的URL必须和实际向后端发起请求的URL一致。如htttp://www.abc.com/book/id。如果后端缺少对/book/id 的路由处理,将返回404错误、
