一、Vue.js

1. Vue.js 是什么

  1. Vue.js是一个轻巧、高性能、可组件化的MVVM库,拥有非常容易上手的API;
  2. Vue.js是一个构建数据驱动的Web见面的库
  3. 官方解释:Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

2. Vue.js 的特性

  1. 轻量级的框架
  2. 双向数据绑定
  3. 指令
  4. 插件化(组件化)

2. MVVM 框架

  • MVVM(Model-View-ViewModel)是对 MVC(Model-View-Control)和 MVP(Model-View-Presenter)的进一步改进。


『View』:视图层(UI 用户界面)
『ViewModel』:业务逻辑层(一切 js 可视为业务逻辑)
『Model』:数据层(存储数据及对数据的处理如增删改查)

  • MVVM 将数据双向绑定(data-binding)作为核心思想,View 和 Model 之间没有联系,它们通过 ViewModel 这个桥梁进行交互。
  • Model 和 ViewModel 之间的交互是双向的,因此 View 的变化会自动同步到 Model,而 Model 的变化也会立即反映到 View 上显示。
  • 当用户操作 View,ViewModel 感知到变化,然后通知 Model 发生相应改变;反之当 Model 发生改变,ViewModel 也能感知到变化,使 View 作出相应更新。

MVVM.jpeg

3. 简述 Vue.js 的优点

  • 低耦合。视图(View)可以独立于 Model 变化和修改,一个 ViewModel 可以绑定到不同的 "View" 上,当 View 变化的时候 Model 可以不变,当 Model 变化的时候 View 也可以不变。
  • 可重用性。你可以把一些视图逻辑放在一个 ViewModel 里面,让很多 View 重用这段视图逻辑。
  • 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
  • 方便测试。界面素来是比较难于测试的,开发中大部分 Bug 来至于逻辑处理,由于 ViewModel 分离了许多逻辑,可以对 ViewModel 构造单元测试。
  • 易用 灵活 高效。

4. Vue中响应式数据的理解

  • 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
  • 这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。
  • 每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
  • 然而他的缺点就很明显了;只能监控最外层的属性,如果是多层的,就要进行全量递归。get里面会做依赖搜集(dep[watcher, watcher]) set里面会做数据更新(notify,通知watcher更新)

data.png

5. Vue中如何检测数组对象的变化

由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。

一、对于对象

Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。

var vm = new Vue({
  data:{
    a:1
  }
})

// `vm.a` 是响应式的

vm.b = 2
// `vm.b` 是非响应式的
  • 对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。
Vue.set(vm.someObject, 'b', 2)
  • 您还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:
this.$set(this.someObject,'b',2)
  • 有时你可能需要为已有对象赋值多个新 property,比如使用 Object.assign() 或 _.extend()。但是,这样添加到对象上的新 property 不会触发更新。在这种情况下,你应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

二、对于数组

Vue 不能检测以下数组的变动:

  1. 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如:vm.items.length = newLength
var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
  • 为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue相同的效果,同时也将在响应式系统内触发状态更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
  • 你也可以使用 vm.$set 实例方法,该方法是全局方法 Vue.set 的一个别名:
vm.$set(vm.items, indexOfItem, newValue)
  • 为了解决第二类问题,你可以使用 splice :
vm.items.splice(newLength)
  • push 向数组的末尾添加一个或更多元素,并返回新的长度。
let fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.push("Kiwi")
//console.log(fruits) //["Banana", "Orange", "Apple", "Mango"]
  • shift 删除并返回数组的第一个元素。
let arr = [1,2,3,4,5];
let b = arr.shift();
console.log(b) // 1
//取出第一个元素
console.log(arr) //[2, 3, 4, 5]
//取出第一元素后的数组
  • pop 删除数组的最后一个元素并返回删除的元素。
let arr = [1,2,3,4,5];
let b = arr. pop();
console.log(b) // 5
//取出第一个元素
console.log(arr) //[1,2, 3, 4]
//取出最后一个元素后的数组
  • splice() 方法向/从数组添加/删除项目,并返回删除的项目。
let fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2, 0, "Lemon", "Kiwi");  //// 在位置 2,添加 2 个元素
console.log(fruits) //["Banana","Orange","Lemon","Kiwi","Apple","Mango"]
  • unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。
let fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.unshift("Lemon","Pineapple");
console.log(fruits) //["Lemon","Pineapple","Banana","Orange",Apple,"Mango"]
  • sort 方法用于对数组的元素进行排序。
let fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits. sort();
console.log(fruits) //["Apple","Banana","Mango","Orange"]
  • reverse 方法用于颠倒数组中元素的顺序。
let fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.reverse();
console.log(fruits) //["Mango","Apple","Orange","Banana"]

因为这些方法都会改变数组本身。
数组里的索引和长度是无法被监控的。

5. Vue中如何进行依赖收集

Vue初始化的时候,挂载之后会进行编译。生成renderFunction。

当取值的时候,就会搜集watcher,放到dep里面。

当用户更改值的时候,就会通知watcher,去更新视图。

6.如何理解Vue中的模板编译原理

这个问题的核心是如何将template转换成render函数。

  1. 将template模块转换成ast语法书 - parserHTML
  2. 对静态语法做标记(某些节点不改变)
  3. 重新生成代码 - codeGen,使用with语法包裹字符串

7.Vue生命周期钩子是如何实现的

Vue的生命周期钩子是回调函数,当创建组件实例的过程中会调用相应的钩子方法。 内部会对钩子进行处理,将钩子函数维护成数组的形式。

8.Vue组件生命周期有哪些

  • beforeCreate 在实例初始化之后,数据观测observer 和event、watcher事件配置之前被调用
  • created 实例已经创建完成,在这一步,以下配置被完成

    • 数据观测
    • 属性和方法的运算
    • watch/event时间回调
    • $el尚未生成
  • beforeMount 在挂载之前被调用,render尚未被调用
  • mounted el被新创建的vm.$el替换,并挂载到实例上去之后调用
  • beforeUpdate 数据更新时,被调用,发生在虚拟Dom重新渲染和打补丁之前
  • update 由于数据更改导致的虚拟Dom重新渲染和打补丁,在这之后调用
  • beforeDestroy 实例销毁之前调用
  • destroyed 实例销毁之后调用,调用后Vue实例的所有东西都会被解绑,所有的事件监听会被移除,子实例被销毁,该钩子在服务端渲染期间不被调用
  • keep-alive(activated & deactivated

9.vue.mixin的使用场景和原理

Vue的mixin的作用就是抽离公共的业务逻辑,原理类似对象的继承,当组件初始化的时候,会调用mergeOptions方法进行合并,采用策略模式针对不同的属性进行合并。如果混入的数据和本身组件的数据有冲突,采用本身的数据为准。

缺点:命名冲突、数据来源不清晰

10.Vue的组件data为什么必须是一个函数

组件中的 data 写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的 data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份 data,就会造成一个变了全都会变的结果

11. nextTick的原理

nextTick是一个微任务。

  • nextTick中的回调是在下次Dom更新循环结束之后执行的延迟回调
  • 可以用于获取更新后的Dom
  • Vue中的数据更新是异步的,使用nextTick可以保证用户定义的逻辑在更新之后执行

未完待续……

最后修改:2022 年 03 月 09 日
如果觉得我的文章对你有用,请随意赞赏