Vue.js的优点
体积小

Vue.js的可下载大小非常小,约为18KB,与其他大尺寸框架相比非常出色。但是,有了这样的规模,Vue.js将对前端应用程序的SEO和UX产生积极影响。
单文件组件和可读性
Vue.js使用基于组件的架构,从而将大块代码分成更小的组件。另外,在Vue.js中,一切都是一个组件,每个组件都是用HTML、CSS和Javascript编写的,从而鼓励可读性和简单性。
实体工具系统
Vue.js支持许多开箱即用的前端开发工具,您几乎不需要任何配置。例如,Vue.js支持Babel和Webpack等工具。此外,它还提供单元测试、端到端测试库、灵活易用的路由系统、状态管理器、服务器端渲染 等。
计算属性
计算属性是Vue.js中最常用的特性之一。计算属性使您能够创建可以以高效和可读的方式修改、操作和显示数据的属性。
事件处理
通过$emit和v-on,Vue.js使得与使用的子和父类的沟通变得轻而易举。处理组件层次结构之间的通信变得轻松而直接。
延迟加载/异步组件
延迟加载是Vue.js的最佳性能技巧之一,其中组件是异步或按需添加和呈现的,这将显着减少文件大小、HTTP请求-响应时间等。
全局组件
我们可以通过全局组件在Vue.js中实现显着的可重用性,您只需注册一次组件,然后在Vue.js实例中的任何地方使用它。
单文件组件
Vue.js最强大的特性之一是组件;它可以帮助您扩展基本的HTML元素、CSS和Javascript,以封装可重用的代码。
服务器端渲染
凭借使用Vue.js创建前端应用程序的所有强大功能和优势,Vue.js本身仍然是一个仅渲染和操作DOM元素的客户端库。
部署
Vue.js在开发过程中会出现许多警告、错误和膨胀的文件大小,但是当您打开生产进行部署时,这些问题会立即消失。 Vue.js将自动配置Webpack构建工具、最小化、CSS提取和清除、缓存、跟踪运行时错误等。
vue双向数据绑定原理
mvvm 双向绑定,采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty 来劫持各个属性的 setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:具体步骤:
1、需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter 这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化
2、compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
3、Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情是:
在自身实例化时往属性订阅器里面添加自己
自身必须有一个 update 方法
待属性变动 dep.notice 通知时,能调用自身的 update 方法,并触发 Compile 中绑定的回调,则功成身退。
4、MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过Observer来监听自己的 model 数据变化,通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通信桥梁,达到数据变化 → 视图更新;视图交互变化 → 数据 model 变更的双向绑定效果。
v-show和v-if指令的共同点和不同点
v-show指令是通过修改元素的display的CSS属性让其显示或者隐藏;
v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果;
使用v-show会更加节省性能上的开销,如果需要频繁的切换节点就使用v-show,比如页面上某个图标,点击这个图标,显示关联的地址字段,再点击,隐藏地址字段,这种情况就可以使用v-show;当只需要一次显示或隐藏时,使用v-if更加合理。
页面导入样式时,使用link和@import有什么区别?
link属于XHTML标签,除了加载CSS外,还能用于定义RSS, 定义rel连接属性等作用;而@import是CSS提供的,只能用于加载CSS;
页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载;
import是CSS2.1 提出的,只在IE5以上才能被识别,而link是XHTML标签,无兼容问题;
link支持使用js控制DOM去改变样式,而@import不支持;
什么是 vue 生命周期?有什么作用?
答:每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做 生命周期钩子 的函数,这给了用户在不同阶段添加自己的代码的机会。例如,如果要通过某些插件操作DOM节点,如想在页面渲染完后弹出广告窗, 那我们最早可在mounted 中进行。
第一次页面加载会触发哪几个钩子?
答:beforeCreate, created, beforeMount, mounted
简述每个周期具体适合哪些场景
beforeCreate:在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法
create:data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作
beforeMount:执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的
mounted:执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行
beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步
updated:页面显示的数据和data中的数据已经保持同步了,都是最新的
beforeDestory:Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁
destroyed: 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。
created和mounted的区别
答:created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
vue获取数据在哪个周期函数
答:一般 created/beforeMount/mounted 皆可.
比如如果你要操作 DOM , 那肯定 mounted 时候才能操作.
1、vue初始化页面闪动问题
答:使用vue开发时,在vue初始化之前,由于p是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。
首先:在css里加上[v-cloak] {
display: none;
}。
如果没有彻底解决问题,则在根元素加上 :
2、vue-router 是什么 它有哪些组件
答:vue用来写路由一个插件。router-link、router-view
active-class 是哪个组件的属性?
答:vue-router模块的router-link组件。children数组来定义子路由
怎么定义 vue-router 的动态路由 怎么获取传过来的值?
在router目录下的index.js文件中,对path属性加上/:id。使用router对象的params.id.
vue-router 有哪几种导航钩子
vue-router 的钩子函数
全局前置守卫 router.beforeEach
全局解析守卫 router.beforeResolve
全局后置钩子 router.afterEach
路由独享的守卫 beforeEnter
组件内的守卫 beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
$route 和 $router 的区别
route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
router是“路由实例对象”,包括了路由的跳转方法,钩子函数等。
active-class是哪个组件的属性?
vue-router模块的router-link组件。
vue-router hash 模式和 history 模式有什么区别?vue-router hash 模式和 history 模式是如何实现的?
hash 模式:
#后面 hash 值的变化,不会导致浏览器向服务器发出请求,浏览器不发出请求,就不会刷新页面。同时通过监听 hashchange 事件可以知道 hash 发生了哪些变化,然后根据 hash 变化来实现更新页面部分内容的操作。
history 模式:
history 模式的实现,主要是 HTML5 标准发布的两个 API,pushState 和 replaceState,这两个 API 可以在改变 url,但是不会发送请求。这样就可以监听 url 变化来实现更新页面部分内容的操作。
vue-router实现路由懒加载
答:三种方式
第一种:vue异步组件技术 ==== 异步加载,vue-router配置路由 , 使用vue的异步组件技术 , 可以实现按需加载 .但是,这种情况下一个组件生成一个js文件。
第二种:路由懒加载。
第三种:webpack提供的require.ensure,vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
vue-router是怎么传递参数的
vue-router有两种传参方式
通过在router.js文件中配置path的地方动态传递参数 eg: path: '/detail/:id' 然后在组件内通过this.$route.params.id即可获取
.在router-link标签中传递参数
注意:这里通过router-link传递参数的方式是隐式传参
v-if和v-for一起使用的弊端以及解决办法
由于v-for的优先级比v-if高,所以导致每循环一次就会去v-if一次,而v-if是通过创建和销毁dom元素来控制元素的显示与隐藏,所以就会不停的去创建和销毁元素,造成页面卡顿,性能下降。
解决办法:在v-for的外层或内层包裹一个元素来使用v-if
beforeDestroyed里面一般进行什么操作
beforedestoryed是组件销毁之前执行的一个生命周期,在这个生命周期里,我们可以进行回调函数或定时器的清除,不用的dom元素的清除等
vue同级组件间怎么传值
1. 如果是兄弟组件,可通过父元素作为中间组件进行传值
2.通过创建一个bus,进行传值
// 创建一个文件,定义bus中间件,并导出
const bus = new Vue
// 在一个组件中发送事件
bus.$emit
// 在另一个组件中监听事件
bus.$on
vue中父组件如何获取子组件的属性和方法
vue中通过在子组件上定义ref属性来获取子组件的属性和方法,代码如下:
// 这里是父组件
在 Vue 中,父子组件的关系可以总结为 props down, events up。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息.
1、watch和computed的区别
watch作用通常是由一个影响多个值的改变并且能监听到这个值变化时,会去执行一个回调函数,此时我们可以在这个回调函数中做一些逻辑处理
computed是根据依赖的值衍生出一个新的值,并且依赖的值可以有多个,只有当被依赖的值发生改变时,才会重新去执行计算
2、Vue父组件和子组件生命周期的顺序
1.渲染过程顺序:
父组件beforeCreate -> 父组件created -> 父组件beforeMount -> 子组件beforeCreate ->子组件created -> 子组件beforeMount -> 子组件mounted -> 父组件mounted
2.更新过程顺序:
父组件更新过程:
父组件beforeUpdate -> 父组件updated
子组件更新过程:
父组件beforeUpdate -> 子组件beforeUpdate -> 子组件updated -> 父组件updated
3.销毁过程
父组件beforeDestroy -> 子组件beforeDestroy -> 子组件destroyed -> 父组件destroyed
Vue中父组件能监听到子组件的生命周期吗
父组件能够监听到子组件的生命周期,通过@hook:进行监听代码如下:
// 这里是父组件
Vue中的事件修饰符主要有哪些?分别是什么作用
.stop: 阻止事件冒泡
.native: 绑定原生事件
.once: 事件只执行一次
.self:将事件绑定在自身身上,相当于阻止事件冒泡
.prevent: 阻止默认事件
.caption: 用于事件捕获
10.介绍下什么是
keep-alive是用于做组件缓存的,只会执行一次,不会被销毁。被keep-alive包裹的组件,没有create和beforeDestroyed等方法,但是有activated和deactivated方法。
3、watch能监听到数组的pop行为吗
对于有返回值的数据,watch就能监听到,比如数组的pop,push, unshift,map等行为。
4、watch如何实现深度监听
watch: {
obj: {
handler: function {
},
deep: true // 深度监听
}
}
5、link和@import的区别
1、link是html的标签,不仅可以加载css还可以定义Rss , rel连接属性;@import是css的语法规则,只能引入样式;
2、加载页面时,link是同时加载的,@import是页面加载完后才加载
3、link没有兼容性的问题,而@import只在较高版本的浏览器才可以识别
4、link可以通过js插入操作dom,@import 不可以!
Vuex:Vue的状态管理模式 + 库
1、state 保存vuex中的数据源,通过this.$store.state获取
2、getters 用于监听state中的值的变化,返回计算后的结果。getter的返回值会根据它的依赖被缓存起来
3、mutations 是修改store中的值得唯一方式
4、action 官方建议提交一个actions,在actions中提交mutations再去修改状态值。 this.$store.dispatch
5、modules 模块化
6、Vue的生命周期
Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。通俗说就是 Vue 实例从创建到销毁的过程,就是生命周期。
beforeCreate: vue元素的挂载元素el和数据都为undefined,还未初始化;
created:vue实例的数据对象data有了,el还没有;
beforeMount:vue实例的$el和data都初始化了,但是还挂载在之前的虚拟dom节点上,data.message还未替换;
mounted:vue实例挂载完成,data.message成功渲染。
更新前后:data变化时会触发beforeUpdate和updated方法;
销毁前后:beforeDestory和destoryed,在执行destoryed方法后,对data的改变不会触发周期函数,说明vue实例已经解除了事件监听以及dom绑定,但是dom结构依然存在;
vue生命周期的作用:
他的生命周期中有多个事件钩子,让我们控制整个vue实例的过程时更容易形成良好的逻辑。
生命周期钩子的一些使用方法:
beforeCreate:loading事件,在加载实例时触发。
created:初始化完成事件,异步请求。
mounted:挂载元素,获取dom节点
uptaded:对数据统一处理
beforeDestory:确认事件停止。
nextTick:更新数据后立即操作dom。
Json和Xml数据的区别
1、数据体积方面:xml是重量级的,json是轻量级的,传递的速度更快些。。
2、数据传输方面:xml在传输过程中比较占带宽,json占带宽少,易于压缩。
3、数据交互方面:json与javascript的交互更加方便,更容易解析处理,更好的进行数据交互
4、数据描述方面:json对数据的描述性比xml较差
5、xml和json都用在项目交互下,xml多用于做配置文件,json用于数据交互。
7、http和https的区别
Http:超文本传输协议,它建立在可靠的传输协议之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。SSL握手协议,它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。
HTTP与HTTPS的区别
1、HTTP是超文本传输协议,信息是明文传输,HTTPS是具有安全性的SSL加密传输协议。
2、HTTPS协议需要ca申请证书,一般免费证书少,因而需要一定费用。
3、HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样。前者是80,后者是443。
4、HTTP连接是无状态的,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,安全性高于HTTP协议。
https的优点
尽管HTTPS并非绝对安全,掌握根证书的机构、掌握加密算法的组织同样可以进行中间人形式的攻击,但HTTPS仍是现行架构下最安全的解决方案,主要有以下几个好处:
1)使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
2)HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。
3)HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。
4)谷歌曾在2014年8月份调整搜索引擎算法,并称“比起同等HTTP网站,采用HTTPS加密的网站在搜索结果中的排名将会更高”。
Https的缺点
1)Https协议握手阶段比较费时,会使页面的加载时间延长近。
2)Https连接缓存不如Http高效,会增加数据开销,甚至已有的安全措施也会因此而受到影响;
3)SSL证书通常需要绑定IP,不能在同一IP上绑定多个域名,IPv4资源不可能支撑这个消耗。
4)Https协议的加密范围也比较有限。最关键的,SSL证书的信用链体系并不安全,特别是在某些国家可以控制CA根证书的情况下,中间人攻击
8、Vue-Router 跳转方式
1. this.$router.push
//跳转到不同的url,但这个方法会向history栈添加一个记录,点击后退会返回到上一个页面。
this.$router.push
//获取参数 {{this.$route.query.userId}}
//this.$router.push
获取参数:{{this.$route.params.userId}}
2. query和params 的区别
a) 用法上,query要用path来引入,params要用name来引入:eg
this.$router.push;
b) 展示上,query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
3. this.$router.replace
同样是跳转到指定的url,但是这个方法不会向history里面添加新的记录,点击返回,会跳转到上上一个页面。上一个记录是不存在的。
4. this.$router.go
相对于当前页面向前或向后跳转多少个页面,类似 window.history.go。n可为正数可为负数。正数返回上一个页面
5. router-link标签使用
1) 根据路由路径跳转
2) 根据路由名称跳转
vue中如何解决页面不重新渲染问题
1、修改对象属性后页面未重新渲染可以使用 this.$set
2、使用this.$forceUpdate方法可重新渲染页面
9、什么是闭包?
闭包是指有权访问其他函数所定义的变量的函数。
使用闭包的话只需要将一个函数定义在另一个函数的内部,并将它给暴露出来,比如可以直接返回或者给他传递给其他函数,由于内部函数对外部函数变量还存在着应用,所以在外部函数执行完毕后不会主动将该内存销毁。
闭包最重要的用途是实现对象的私有数据。 对象的内部数据无法被轻易的修改,保证了程序的安全性。
但同时大量的使用闭包会导致内存泄漏。
什么是事件代理?有什么好处?
JS高级程序上的定义:利用事件冒泡,只绑定一个函数就可以处理一类事件。
在JS中,添加到页面上的事件数量直接关乎着页面的性能,多次与dom发生交互访问dom会导致页面重绘和重排,导致拖慢整个页面,这就是为什么优化里中的减少dom操作的原因。而且,每个函数都是一个对象,对象就要占据内存,内存大了性能自然就慢了。
事件委托的实现原理就是利用事件冒泡。
冒泡的顺序 :目标元素->dom结构 直至 body->body->html->document->windon
事件代理的好处:
优化性能,减少dom操作
当新元素绑添加进来的时候不需要再次绑定事件,通过冒泡就可以触发
Js原型,原型链相关知识点
在JS中,每创建出来一个函数js就会默认创建一个prototype的属性,这个属性指向函数的原型对象。
在原型对象里面有一个属性constructor属性指向了构造函数。
每个对象都有一个隐式原型 __proto__ ,指向的是构造该对象的构造函数的原型对象。
原型对象也是对象,所以如果我们让原型对象指向另外的一个实例,这个实例也有自己的原型对象,如果这个实例的原型对象又等于了另外的实例,一层层下去就形成了一个链条。这就是所谓的原型链。
函数也是对象,所以函数也有隐式原型,函数的隐式原型为Function.prototype
Function.prototype的隐式原型为Object.prototype
Object.prototype 的隐式原型为null 这里也就是原型链的顶端
10、组件通信方式有哪些?
父子组件通信:
props 和 event、v-model、 .sync、 ref、 $parent 和 $children
非父子组件通信:
$attr 和 $listeners、 provide 和 inject、eventbus、通过根实例$root访问、vuex、dispatch 和 brodcast
11、子组件为什么不可以修改父组件传递的prop?
Vue提倡单向数据流,即父级 props 的更新会流向子组件,但是反过来则不行。这是为了防止意外的改变父组件状态,使得应用的数据流变得难以理解。如果破坏了单向数据流,当应用复杂时,debug 的成本会非常高。
12、V-model是如何实现双向绑定的?
v-model 是用来在表单控件或者组件上创建双向绑定的,他的本质是 v-bind 和 v-on 的语法糖,在一个组件上使用 v-model,默认会为组件绑定名为 value 的 prop 和名为 input 的事件。
13、Vuex和单纯的全局对象有什么区别?
Vuex和全局对象主要有两大区别:
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
14、为什么 Vuex 的 mutation 中不能做异步操作?
Vuex中所有的状态更新的唯一途径都是mutation,异步操作通过 Action 来提交 mutation实现,这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
每个mutation执行完成后都会对应到一个新的状态变更,如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。
vue组件有哪些生命周期钩子?
beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed。
15、v-show 和 v-if 有哪些区别?
v-if 会在切换过程中对条件块的事件监听器和子组件进行销毁和重建,如果初始条件是false,则什么都不做,直到条件第一次为true时才开始渲染模块。
v-show 只是基于css进行切换,不管初始条件是什么,都会渲染。
所以,v-if 切换的开销更大,而 v-show 初始化渲染开销更大,在需要频繁切换,或者切换的部分dom很复杂时,使用 v-show 更合适。渲染后很少切换的则使用 v-if 更合适。
16、computed vs methods
计算属性是基于他们的响应式依赖进行缓存的,只有在依赖发生变化时,才会计算求值,而使用 methods,每次都会执行相应的方法。
17、keep-alive 的作用是什么?
keep-alive 可以在组件切换时,保存其包裹的组件的状态,使其不被销毁,防止多次渲染。
其拥有两个独立的生命周期钩子函数 actived 和 deactived,使用 keep-alive 包裹的组件在切换时不会被销毁,而是缓存到内存中并执行 deactived 钩子函数,命中缓存渲染后会执行 actived 钩子函数。
Vue 中 v-html 会导致什么问题
在网站上动态渲染任意 HTML,很容易导致 XSS 攻击。所以只能在可信内容上使用 v-html,且永远不能用于用户提交的内容上。
18、Vue 的响应式原理
Vue 的响应式是通过 Object.defineProperty 对数据进行劫持,并结合观察者模式实现。 Vue 利用 Object.defineProperty 创建一个 observe 来劫持监听所有的属性,把这些属性全部转为 getter 和 setter。Vue 中每个组件实例都会对应一个 watcher 实例,
它会在组件渲染的过程中把使用过的数据属性通过 getter 收集为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
Object.defineProperty有哪些缺点?“为什么vue3.0使用proxy实现响应式?”

其实都是对Object.defineProperty 和 proxy实现响应式的对比。
Object.defineProperty 只能劫持对象的属性,而 Proxy 是直接代理对象
由于 Object.defineProperty 只能对属性进行劫持,需要遍历对象的每个属性。而 Proxy 可以直接代理对象。
Object.defineProperty 对新增属性需要手动进行 Observe, 由于 Object.defineProperty 劫持的是对象的属性,所以新增属性时,需要重新遍历对象,对其新增属性再使用 Object.defineProperty 进行劫持。 也正是因为这个原因,使用 Vue 给 data 中的数组或对象新增属性时,需要使用 vm.$set 才能保证新增的属性也是响应式的。
Proxy 支持13种拦截操作,这是 defineProperty 所不具有的。
新标准性能红利
Proxy 作为新标准,长远来看,JS引擎会继续优化 Proxy ,但 getter 和 setter 基本不会再有针对性优化。
Proxy 兼容性差 目前并没有一个完整支持 Proxy 所有拦截方法的Polyfill方案
19、Vue中如何检测数组变化?
Vue 的 Observer 对数组做了单独的处理,对数组的方法进行编译,并赋值给数组属性的 __proto__ 属性上,因为原型链的机制,找到对应的方法就不会继续往上找了。
编译方法中会对一些会增加索引的方法进行手动 observe。
20、组件的 data 为什么要写成函数形式?
Vue 的组件都是可复用的,一个组件创建好后,可以在多个地方复用,而不管复用多少次,组件内的 data 都应该是相互隔离,互不影响的,所以组件每复用一次,data 就应该复用一次,每一处复用组件的 data 改变应该对其他复用组件的数据不影响。
为了实现这样的效果,data 就不能是单纯的对象,而是以一个函数返回值的形式,所以每个组件实例可以维护独立的数据拷贝,不会相互影响。
21、nextTick是做什么用的,其原理是什么
在下次 DOM 更新循环结束后执行延迟回调,在修改数据之后立即使用 nextTick 来获取更新后的 DOM。
nextTick 对于 micro task 的实现,会先检测是否支持 Promise,不支持的话,直接指向 macro task,而 macro task 的实现,优先检测是否支持 setImmediate,不支持的再去检测是否支持 MessageChannel,如果仍不支持,最终降级为 setTimeout 0;
默认的情况,会先以 micro task 方式执行,因为 micro task 可以在一次 tick 中全部执行完毕,在一些有重绘和动画的场景有更好的性能。
但是由于 micro task 优先级较高,在某些情况下,可能会在事件冒泡过程中触发,导致一些问题,所以有些地方会强制使用 macro task 。
22、Vue 的模板编译原理
vue模板的编译过程分为3个阶段:
第一步:解析
将模板字符串解析生成 AST,生成的AST 元素节点总共有 3 种类型,1 为普通元素, 2 为表达式,3为纯文本。
第二步:优化语法树
Vue 模板中并不是所有数据都是响应式的,有很多数据是首次渲染后就永远不会变化的,那么这部分数据生成的 DOM 也不会变化,我们可以在 patch 的过程跳过对他们的比对。
此阶段会深度遍历生成的 AST 树,检测它的每一颗子树是不是静态节点,如果是静态节点则它们生成 DOM 永远不需要改变,这对运行时对模板的更新起到极大的优化作用。
生成代码
const code = generate
复制代码
通过 generate 方法,将ast生成 render 函数。
23、v-for 中 key 的作用是什么?
key 是给每个 vnode 指定的唯一 id,在同级的 vnode diff 过程中,可以根据 key 快速的对比,来判断是否为相同节点,并且利用 key 的唯一性可以生成 map 来更快的获取相应的节点。
另外指定 key 后,就不再采用“就地复用”策略了,可以保证渲染的准确性。
Vue-router 导航守卫有哪些
全局前置/钩子:beforeEach、beforeResolve、afterEach
路由独享的守卫:beforeEnter
组件内的守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
完整的导航解析流程如下:
导航被触发。
在失活的组件里调用离开守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 。
在路由配置里调用 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫 。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
24、vue-router hash 模式和 history 模式有什么区别?vue-router hash 模式和 history 模式是如何实现的?
hash 模式:
#后面 hash 值的变化,不会导致浏览器向服务器发出请求,浏览器不发出请求,就不会刷新页面。同时通过监听 hashchange 事件可以知道 hash 发生了哪些变化,然后根据 hash 变化来实现更新页面部分内容的操作。
history 模式:
history 模式的实现,主要是 HTML5 标准发布的两个 API,pushState 和 replaceState,这两个 API 可以在改变 url,但是不会发送请求。这样就可以监听 url 变化来实现更新页面部分内容的操作。
25、一个Vue的应用程序是如何运行起来的
模板通过编译生成AST,再由AST生成Vue的render函数,渲染函数结合数据生成Virtual DOM树,Diff和Patch后生成新的UI。
render函数可以作为一道分割线,render函数的左边可以称之为编译期,将Vue的模板转换为渲染函数。render函数的右边是Vue的运行时,主要是基于渲染函数生成Virtual DOM树,Diff和Patch。
diff 和patch 是一对工具。 diff是广度优先算法---采用深度优先遍历,它只会在同层级进行,不会跨层级比较
vue双向数据绑定原理
mvvm 双向绑定,采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty 来劫持各个属性的 setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:具体步骤:
1、需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter 这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化
2、compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
3、Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情是:
在自身实例化时往属性订阅器里面添加自己
自身必须有一个 update 方法
待属性变动 dep.notice 通知时,能调用自身的 update 方法,并触发 Compile 中绑定的回调,则功成身退。
4、MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过Observer来监听自己的 model 数据变化,通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通信桥梁,达到数据变化 → 视图更新;视图交互变化 → 数据 model 变更的双向绑定效果。
vue的核心是什么
Vue两大核心思想:组件化和数据驱动。组件化:把整体拆分为各个可以复用的个体,数据驱动:通过数据变化直接影响bom展示,避免dom操作。
vue框架的优缺点 ---低耦合、可重用性、独立开发、可测试。
比于Angular.js,Vue.js提供了更加简洁、更易于理解的API
比起 React + Redux 相对复杂的架构,Vue.js 更加轻量级也更加容易上手
Vue的性能是远好于Angular1,并且稍微优于React的
Vue 提供了Vue-cli 脚手架,包括了Webpack,Browserify,甚至路由库,相比于angularjs和react能让你非常容易地构建项目。
用 Vue 语法开发的组件不仅仅可以运行在浏览器端,还能被用于开发 iOS 和 Android 上的原生应用。
但是,Vue明确声明了自己放弃了对IE8的支持。
1.监听数据变化的实现原理不同
Vue 通过 getter/setter 以及一些函数的劫持,能精确快速的计算出 Virtual DOM 的差异。这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。
React 默认是通过比较引用的方式进行的,如果不优化,每当应用的状态被改变时,全部子组件都会重新渲染,可能导致大量不必要的 VDOM 的重新渲染。
Vue 不需要特别的优化就能达到很好的性能,而对于 React 而言,需要通过 PureComponent/shouldComponentUpdate 这个生命周期方法来进行控制。如果你的应用中,交互复杂,需要处理大量的 UI 变化,那么使用 Virtual DOM 是一个好主意。如果你更新元素并不频繁,那么 Virtual DOM 并不一定适用,性能很可能还不如直接操控 DOM。
为什么 React 不精确监听数据变化呢?这是因为 Vue 和 React 设计理念上的区别,Vue 使用的是可变数据,而 React 更强调数据的不可变。
2.数据流的不同 cmd-markdown-logo
Vue 中默认支持双向绑定,组件与 DOM 之间可以通过 v-model 双向绑定。但是,父子组件之间,props 在 2.x 版本是单向数据流
React 一直提倡的是单向数据流,他称之为 onChange/setState模式。
不过由于我们一般都会用 Vuex 以及 Redux 等单向数据流的状态管理框架,因此很多时候我们感受不到这一点的区别了。
3.模板渲染方式的不同
在表层上,模板的语法不同
React 是通过 JSX 渲染模板
而 Vue 是通过一种拓展的 HTML 语法进行渲染
在深层上,模板的原理不同,这才是他们的本质区别:
React 是在组件 JS 代码中,通过原生 JS 实现模板中的常见语法,比如插值,条件,循环等,都是通过 JS 语法实现的
Vue 是在和组件 JS 代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现
缺点:Vue 的做法显得有些独特,会把 HTML 弄得很乱。举个例子,说明 React 的好处:react 中 render 函数是支持闭包特性的,所以我们 import 的组件在 render 中可以直接调用。但是在 Vue 中,由于模板中使用的数据都必须挂在 this 上进行一次中转,所以我们 import 一个组件完了之后,还需要在 components 中再声明下,这样显然是很奇怪但又不得不这样的做法。
vue全家桶包括哪些
Vue全家桶:Vue+Vue-router+Vuex+axios
一、Vue-cli是快速构建这个单页应用的脚手架,
# 全局安装 vue-cli
$ npm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
$ vue init webpack my-project
# 安装依赖,走你
$ cd my-project
$ npm install
$ npm run dev
vue-router -
--是“路由实例对象”,包括了路由的跳转方法,钩子函数等。
安装:npm install vue-router
如果在一个模块化工程中使用它,必须要通过 Vue.use 明确地安装路由功能:
import Vue from'vue'
mport VueRouter from'vue-router'
Vue.use
另外注意在使用中,可以利用vue的过渡属性来渲染出切换页面的效果。
三、vuex
vuex是专门为vue.js应用程序开发的状态管理,可以理解为全局的数据管理。vuex主要由五部分组成:state 、 action、mutation、getters、mudle组成。
使用流程是: 组件中可以直接调用上面四个部分除了mudle,
1、state
类似vue 对象的data, 用来存放数据以及状态。存放的数据为响应式,如果数据改变,那么依赖数据的组件也会发生相应的改变。
注意:可以通过mapState把全局的state和 getters 映射到当前组件的 computed计算属性中。
2、actions
Action 通过 store.dispatch 方法触发:action支持异步调用,mutation只支持操作同步,并且action提交的是 mutation,而不是直接变更状态。
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
3、mutation
每个 mutation 都有一个字符串的 事件类型 和一个 回调函数。这个回调函数就是我们实际进行 状态更改的地方,并且它会接受 state 作为第一个参数。
4、getters
Vuex 允许我们在 store 中定义“getter”。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算
四、axios
axios是一个http请求包,vue官网推荐使用axios进行http调用。
安装:npm install axios --save
26、封装vue组件的过程以及注意点
vue组件的定义
● 组件是Vue.js最强大的功能之一
● 组件可以扩展HTML元素,封装可重用代码
● 在较高层面上,组件是自定义元素,Vue.js的编译器为他添加特殊功能
● 有些情况下,组件也可以表现用 is 特性进行了扩展的原生的HTML元素
● 所有的Vue组件同时也都是Vue实例,所以可以接受相同的选项对象,并提供相同的生命周期钩子
vue组件的功能
1)能够把页面抽象成多个相对独立的模块
2)实现代码重用,提高开发效率和代码质量,使得代码易于维护
Vue组件封装过程
● 首先,使用Vue.extend创建一个组件
● 然后,使用Vue.component方法注册组件
● 接着,如果子组件需要数据,可以在props中接受定义
● 最后,子组件修改好数据之后,想把数据传递给父组件,可以使用emit方法
组件使用流程详细介绍:
1、组件创建---有3中方法
A、调用Vue.extend,创建名为myCom的组件,template定义模板的标签,模板的内容需写在该标签下
B、标签创建,需要加上id属性
C、cript type='text/x-template' id='myCom'>,需加id属性,同时还得加type="text/x-template",加这个是为了告诉浏览器不执行编译里面的代码
2、注册组件----有2中方法,全局注册,局部注册
A1、全局注册:一次注册 ),可在多个Vue实例中使用。
A2、全局注册语法糖:不需要创建直接注册的写法
A3、如果是用template及script标签构建的组件,第二个参数就改为它们标签上的id值
B1、局部注册:只能在注册该组件的实例中使用,一处注册,一处使用
B2、局部注册语法糖:
var app = new Vue
B3、及cript>创建的组件,局部注册
3、调用组件--------只需要在调用组件的地方,写上组件名字的标签即可
注意::注意:
A、props取值的方式
在注册组件的模板内部template,直接通过prop的名称取值就Ok
template: '
我叫:{{name}}, 我来自:{{comeFrom}}
'不在注册组件的模板内部template,用this.prop的方式
console.log
B、在template选项属性中,可以写驼峰命名法,也可以写短横线命名法
在HTML中,只能写短横线命名法
原因:vue组件的模板可以放在两个地方
a、Vue组件的template选项属性中,作为模板字符串
b、放在.html中[ 用script template标签创建的组件 ],作为HTML
问题在于HTML不区分大小写,所以在vue注册组件中通用的驼峰命名法,不适用于HTML中的Vue模板,在HTML中写入props属性,必须写短横线命名法
vue如何实现父子组件通信,以及非父子组件通信
父组件向子组件传值:父组件通过标签上面定义传值,子组件通过props方法接受数据
子组件向父组件传递数据:子组件通过$emit方法传递参数
Vue 组件间通信六种方式
props/$emit
vuex----五种属性,有五种,分别是 State、Getter、Mutation、Action、Module
$emit/$on
$attrs/$listeners
provide/inject
$parent/$children 与 ref
子组件调用父组件的方法:
1、直接在子组件中通过this.$parent.event来调用父组件的方法。
2、在子组件里使用$emit向父组件触发一个事件,父组件监听这个事件。
3、父组件把方法传入子组件中,在子组件里直接调用这个方法。
27、vue中的mvvm模式,以及和mvc模式的不同点
mvc和mvvm都是一种设计思想。主要就是mvc中Controller演变成mvvm中的viewModel。
mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
区别:vue数据驱动,通过数据来显示视图层而不是节点操作。
场景:数据操作比较多的场景,更加便捷
结合router,缓存部分页面,使用$route.meta的keepAlive属性
keep-alive生命周期钩子函数:activated、deactivated
使用
28、vue.cli中怎样使用自定义的组件?有遇到过哪些问题吗?
第一步:在components目录新建你的组件文件,script一定要export default {}
第二步:在需要用的页面中导入:import indexPage from '@/components/indexPage.vue'
第三步:注入到vue的子组件的components属性上面,components:{indexPage}
第四步:在template视图view中使用,
例如有indexPage命名,使用的时候则index-page
vue如何实现按需加载配合webpack设置
webpack中提供了require.ensure来实现按需加载。以前引入路由是通过import 这样的方式引入,改为const定义的方式进行引入。
不进行页面按需加载引入方式:import home from '../../common/home.vue'
进行页面按需加载的引入方式:const home = r => require.ensure => r ))
29、async 和 await
主要考察宏任务 和微任务,搭配promise,询问一些输出的顺序
宏任务:整体代码 script,setTimeout,setInterval
微任务:Promise,process.nextTick
原理:async 和 await 用了同步的方式去做异步,async 定义的函数的返回值都是 promise,await 后面的函数会先执行一遍,然后就会跳出整个 async 函数来执行后面js栈的代码
javascript的执行机制:JS 异步有一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入 Event Queue,然后再执行微任务,将微任务放入 Event Queue,但是,这两个 Queue 不是一个 Queue。当你往外拿的时候先从微任务里拿这个回调函数,然后再从宏任务的 Queue 拿宏任务的回调函数。
30、export 和 export default 的区别?
总结: 1、export 可以有多个; export default 只能有一个
2、外部引用的时候 export 需要花括号 export default不需要花括号
31、虚拟 DOM 实现原理
虚拟DOM本质上是Javascript对象,是对真实DOM的抽象, 状态变更时,记录新树和旧树的差异,最后把差异更新到真正的dom中
32、watch、methods 和 computed 的区别
watch 为了监听某个响应数据的变化。
computed 是自动监听依赖值的变化,从而动态返回内容,主要目的是简化 模板内的复杂运算。
所以区别来源于用法,只是需要动态值,那就用 computed ;需要知道值的改变后执行业务逻辑,才用 watch。
methods是一个方法,它可以接受参数,而computed 不能,computed 是可以缓存的,methods 不会。
computed vs methods
我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。
每一个计算属性都包含一个 getter 函数和 setter 函数;
计算属性会默认使用 getter 函数;
你也可以提供 setter 函数,当修改计算属性的值时,就会触发 setter 函数,执行一些自定义的操作。
computed 可以依赖其他 computed,甚至是其他组件的 data。
33、vue 中怎么重置 data
使用Object.assign,vm.$data可以获取当前状态下的data,vm.$options.data可以获取到组件初始化状态下的data。
Object.assign)
// 注意加this,不然取不到data { a: this.methodA } 中的 this.methodA。
34、组件中写 name 选项有什么作用?
1、项目使用 keep-alive 时,可搭配组件 name 进行缓存过滤
2、DOM 做递归组件时需要调用自身 name
3、vue-devtools 调试工具里显示的组见名称是由vue中组件name决定的
35、Vue 的 nextTick 的原理是什么?
Vue 是异步修改 DOM 的并且不鼓励开发者直接接触 DOM,但有时候业务需要必须对数据更改--刷新后的 DOM 做相应的处理,这时候就可以使用 Vue.nextTick这个 api ,它可以在DOM更新完毕之后执行一个回调
// 修改数据
vm.msg = 'Hello'
// DOM 还没有更新
Vue.nextTick {
// DOM 更新了
})
总结:1、vue用异步队列的方式来控制DOM更新和nextTick回调先后执行
2、microtask因为其高优先级特性,能确保队列中的微任务在一次事件循环前被执行完毕
3、因为兼容性问题,vue不得不做了microtask向macrotask的降级方案
36、vue 首屏加载优化
1. 把不常改变的库放到 index.html 中,通过 cdn 引入
2. vue 路由的懒加载
3. 不生成 map 文件
4. vue 组件尽量不要全局引入
5. 使用更轻量级的工具库
6. 开启gzip压缩
7. 首页单独做服务端渲染
37、vue-cli 替我们做了哪些工作?
它是基于 Vue.js 进行快速开发的完整系统,也可以理解成是很多 npm 包的集合
38、transform、translate、transition 分别是什么属性?CSS 中常用的实现动画方式
三者属性说明
transform 是指变换、变形,是 css3 的一个属性,和 width,height 属性一样;
translate 是 transform 的属性值,是指元素进行 2D维度上位移或范围变换;
transition 是指过渡效果,往往理解成简单的动画,需要有触发条件。
39、javascript 的垃圾回收机制讲一下
Javascript 在创建对象时会为它们分配内存,不再使用对时会“自动”释放内存,这个过程称为垃圾收集。
内存生命周期中的每一个阶段:
分配内存 — 内存是由操作系统分配的,它允许您的程序使用它。在低级语言中,这是一个开发人员需要自己处理的显式执行的操作。然而,在高级语言中,系统会自动为你分配内在。
使用内存 — 这是程序实际使用之前分配的内存,在代码中使用分配的变量时,就会发生读和写操作。
释放内存 — 释放所有不再使用的内存,使之成为自由内存,并可以被重利用。与分配内存操作一样,这一操作在低级语言中也是需要显式地执行。
四种常见的内存泄漏:全局变量,未清除的定时器,闭包,以及 dom 的引用
1、全局变量 不用 var 声明的变量,相当于挂载到 window 对象上。如:b=1; 解决:使用严格模式
2、被遗忘的定时器和回调函数
3、闭包
4、没有清理的 DOM 元素引用
40、对前端性能优化有什么了解?一般都通过那几个方面去优化的?
减少请求数量;减小资源大小;优化网络连接;优化资源加载;减少重绘回流;性能更好的API;webpack优化
41、判断 js 类型的方式
1. typeof
可以判断出'string','number','boolean','undefined','symbol'
但判断 typeof 时值为 'object'; 判断数组和对象时值均为 'object'
2. instanceof
原理是 构造函数的 prototype 属性是否出现在对象的原型链中的任何位置
复制
function A {}
let a = new A;

a instanceof A //true,因为 Object.getPrototypeOf === A.prototype;
3. Object.prototype.toString.call
常用于判断浏览器内置对象,对于所有基本的数据类型都能进行判断,即使是 null 和 undefined
4. Array.isArray
用于判断是否为数组


