1,new Vue()都做了什么
1,new Vue ( )是创建 Vue 实例,它内部执行了根实例的初始化过程。
2, 初始化过程具体包括以下操作:
- 合并配置
- 初始化数据 props、data、computed、watcher 等
- 初始化事件中心
- 初始化生命周期 (new Vue()时只调用了beforeCreated、created两个生命周期)
- 初始化渲染
3,new Vue( ) 创建了根实例并准备好数据和方法,以备将来执行挂载进使用。
2,说一说你对Vue响应式的理解
1,所谓数据响应式就是数据的更改导致视图层做出更新的机制
2, vue2 中的数据响应式会根据数据类型来做不同处理:
- 如果是对象则采用 object.defineproperty的方式定义数据拦截,当数据被访问或发生变化时,触发set方法并作出晌应;
- 如果是数组则通过vue变更后的数组原型方法(push,shift,unshift,splice,pop,sort,reverse ),从而作出响应。
- 如果是基础类型的值,比如说String、Number、Boolean等,它是通过放到对象中,作为对象的属性,从而利用 object.defineproperty对值的变化进行监听。这也就是为什么vue组件中的所有状态都是在一个对象中的原因。
数组的这种机制很好的解决了数据响应化的问题,但在实际使用中也存在一些缺点
:比如:
1,新增或删除属性时,无法监听到变化,需要用户使用 vue.set
2,对于 es6 中新产生的 Map 、 Set 这些数据结构不支持等问题。
为了解决Vue数组中的变更方法引起的问题, vue3 重新编写了这一部分的实现:利用ES6的Proxy机制代理要响应化数据,这样我们就不需要使用特殊api, 初始化性能和内存消耗都得到了大幅改善.
3,最后,Vue通过操作数据,再使用virtual Dom 和 patch算法,就可以使我们只需要操作数据,完全不用接触 dom 操作来更新视图,从而大大提升开发效率,降低开发难度。
3,你知道nextTick吗?
这个考查的是对vue异步更新队列的理解
1,由于 vue更新DOM采用是的异步更新策略,导致我们对数据的修改不会立刻体现在 dom 变化上,nextTick的作用就是,在修改数据之后立即使用这个方法,可以获取更新后的 DOM。
2,Vue data 中某一个属性的值发生改变后,视图会立即同步执行重新渲染吗?
`不会,因为Vue 是异步执行 DOM 更新的,具体过程如下:`
-
1、修改数据,这是同步任务,但是此时还未去修改 DOM 。
-
2、数据发生变化之后,Vue 开启一个异步队列,并
缓冲
在此事件循环中所有发生改变的数据。如果同一个数据被多次触发修改,那么也只会被推入到队列中一次。 在缓冲时去除重复数据,对于避免不必要的计算和 DOM 操作。
-
3、在此事件中所有的同步任务执行完毕后,开始执行异步队列中的任务,更新 DOM。
nextTick 传入的方法,会在异步任务执行后,作为回调来调用,此时就能获取到更新后的DOM了。
3,简单来说,Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环 中的所有数据变化完成之后,再统一进行dom更新。
参考链接:https://segmentfault.com/a/1190000012861862
4,你知道key的作用吗
1). key通常用在通过某个列表,对template中的某块模版,进行循环渲染的时候。
2). 这样的话,循环渲染出来的dom就是一模一样的,以致于,在把模版转化成vnode后,其相应的vnode节点也就是一样的。如果不加以区分的话,当数据变化,重新编译模版,再次将模版转化为新的vnode后,在进行新旧vnode比较时。
3)如果设置了key,key就是 vnode 的唯一标记,通过这个 key,我们可以更快的找到新旧vnode 中对应的节点,从而进行比较, 这样就降低了 diff算法的复杂度,使diff 操作更准确、更快速
。
比如说:我们在列表中间新增了一个数据,
我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的------ 同级节点进行比较。
这样由于顺序的问题,就导致了原先不需要更新的节点,也变的需要更新了。
即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
所以我们需要使用key来给每个节点做一个唯一标识,这样通过Diff算法就可以正确的识别此节点所对应的新vnode中对应的节点,从而进行更准确的比较,这样就能减少不必要的dom更新。
从而找到正确的位置区插入新的节点。
4). 从源码角度来说
:
-
在vnode中,用key区分两个相同的节点
实际的标签中可能存在两个一模一样的两个节点,但是在virtual Dom中无法体现这个区别,这就用到了key以作区分。 -
加快diff算法的速度
在新旧vnode的对比中,即在diff算法中,大量使用了tagName和key组合判断节点之间差异的逻辑,以判断这个节点是被修改了、删除了还是新增的。这样就能够尽可能的复用已有元素而不是从头开始渲染。
5,keep-alive的作用是什么
<keep-alive></keep-alive>
包裹组件时,主要用于保留组件状态或避免重新渲染。
keep-alive 独有的生命周期,分别为 activated 和deactivated。
用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,再次显示时,会执行 activated 钩子函数
6, vue-loader是什么?使用它的用途有哪些?
- 定义:vue-loader 是 webpack 的一个 loader,用于处理 .vue 文件,是解析.vue文件的一个加载器。
7,scss在vue-cli中的安装使用步骤是什么?有哪几大特性?
7.1 使用步骤:
(1) 安装
css-loader、node-loader、sass-loader等加载器模块。
npm install node-sass --save-dev
npm install sass-loader --save-dev
(2) 配制webpack.base.config.js
// 在 rules中添加
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass']
}
(3)使用
在组件的style标签上加上lang属性,如lang=“scss”
<style lang="scss" scoped>
/* 写入scss */
</style>
7.2 特性
(1)可以使用变量,如($变量名称=值)。
(2)可以嵌套。
(3)可以用混合器,@mixin,可重用性高
@mixin banner {
width: 100%;
position: relative;
color: $deeepBlue;
}
.lead-banner {
@include banner;
}
(4)使用@extend:允许一个选择器继承另一个选择器
.a1 {
color: blue;
}
.a2 {
@extend .a1;
font-size: 12px;
}
(5)计算功能
p {
margin: 20px + 30px;
width: (100% / 6);
}
(6) if、for循环语句(用的不多)
@mixin bgcolor($b) {
@if($b==5) {
background-color: #fff;
} @else if($b == 6) {
background-color: green;
} @else {
background: blue;
}
}
8、为什么避免v-if和v-for一起使用?
1、当vue处理指令时,当v-for,v-if处于同一节点时,v-for比v-if具有更高的优先级。这意味着v-if将分别重复运行于每个v-for循环中。
2、解决:可以将v-if放在一个包装元素内。
<ul v-if="shouldRenderTodos">
<li v-for="todo in todos">
todo
</li>
</ul>
9、diff算法的逻辑
:
1、当页面的数据发生变化时,Diff算法只会比较同一层级的节点:
- 如果
节点类型不同
,不会再比较这个节点及其以后的子节点了,直接干掉旧的节点,再创建并插入新的节点。 - 如果
节点类型相同
,则会重新设置该节点的属性,从而实现节点的更新
10、简述 mixin、extends 的覆盖逻辑
10.1、mixin 和 extends
mixin 和 extends 均是用于合并、拓展组件的,两者均通过mergeOptions
方法实现合并。
区别
- extends会比mixins先执行。执行顺序:extends > mixins > 组件
- extends只能暴露一个extends对象,而mixins可以有多个mixin对象,
多个mixin时,按照传入顺序依次调用
let mixin = {
created() {
console.log('mixin say hi')//mixin比组件先输出
},
data() {
return {
msg: 10
}
},
methods: {
foo(){
console.log('mixin foo()'+this.msg++)
}
}
}
let extend={
created() {
console.log('extend say hi')//extend比先输出mixin
},
data() {
return {
msg: 20
}
},
methods: {
foo(){
console.log('extend foo()'+this.msg++)
}
}
}
Vue.component('component-a',{
template:`<div><button @click="foo">componentA</button>{{msg}}</div>`,
created() {
console.log('componentA say hi')//后输出
},
methods:{
},
extends:extend,
mixins:[mixin]
})
10.2、合并规则
mixin 和 extends的配制与组件自身的配制合并时,如果出现相同时,
组件自身的配制 > mixins > extends;
11、子组件可以直接改变父组件的数据吗?
子组件不可以直接改变父组件的数据。这样做主要是为了维护父子组件的单向数据流。
Vue 提倡单向数据流,即父级 props 的更新会流向子组件,但是反过来则不行。
这是为了防止意外的改变父组件状态,使得数据流混乱。
因此,子组件如果想要修改父组件的数据时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改;
12、vue-cli中assets 和 static 的区别
相同点
- assets 和 static 两个都是存放静态资源文件,比如说:图片、css、字体图标等
不同点
- assets 中存放的静态资源文件在项目打包时,会通过打包工具进行压缩体积,代码格式化。而static中的资源则不会。
建议
- 将 template 需要的样式文件 、js 文件等都可以放置在assets 中,走打包这一流程。减少体积。
- 项目中引入的第三方的资源文件如 iconfoont.css 等文件可以放置在 static 中,因为这些文件已经经过处理,不需要再处理了;
13、delete和Vue.delete的区别
delete和和Vue.delete都是对数组或对象进行删除的方法。
- 对于对象来说,没有区别的,使用方法会直接删除对象的属性(物理删除)
let obj = {
name: 'fufu',
age: 20
}
// delete obj.age => {name: 'fufu'}
// Vue.delete(obj, 'age') => {name: 'fufu'}
// 测试发现对于对象来说delete和Vue.delete是没有任何区别的
- 对于数组来说,区别比较大
- delete只是被删除的元素变成了 empty/undefined,其他的元素的键值还是不变。数组长度也不变。(逻辑删)
- Vue.delete是直接删除该元素,长度发生变化。(物理删)
let arr = [1,2,3,4,5]
delete arr[2] //[1,2,empty,4,5]
Vue.delete arr[2] //[1,2,4,5]
14,对 vue 设计原则的理解
1. 渐进式 JavaScript 框架
与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用
。
Vue 的核心库只关注视图层
,
如果你需要多个页面,再添加路由router,如果还需要状态管理,再添加vuex,如果还需要其它插件,再安装相应插件。
2.灵活性
渐进式框架的最大优点就是灵活性,如果应用足够小,我们可能仅需要 vue 核心特性即可完成功能
;
随着应用规模不断扩大,我们才可能逐渐引入路由、状态管理、vue-cli 等库和工具
,不管是应用体积还是学习难度都是一个逐渐增加的平和曲线。
3.易用性
vue 提供数据双向绑定、声明式模板语法等。这些使我们只需要关注应用的核心业务即可,只要会写 js、html 和 css 就能轻松编写 vue 应用
。
4.高效性
一方面,虚拟DOM使得开发者避免了大量的DOM操作;
另一方面,不断优化的diff算法,使我们的应用拥有最佳的性能表现(从最开发的diff算法—》静态标记优化避免不必要的对比)
最后,从vue2到vue3响应式原理的变化,即从Object.defineProperty() ---> Proxy()