# 1. Vue 介绍

Vue.js 是一个构建数据驱动(所谓数据驱动,是指视图是由数据驱动生成的,我们对视图的修改,不会直接操作 DOM,而是通过修改数据。)的 web 界面的 MVVM 渐进式框架。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。核心是一个响应的数据绑定系统。

在 JQuery 时期,如果需要刷新 UI 时,需要先取到对应的 DOM 再更新 UI,这样数据和业务的逻辑就和页面有强耦合。

在 MVVM 中,UI 是通过数据驱动的,数据一旦改变就会相应的刷新对应的 UI,UI 如果改变,也会改变对应的数据。这种方式就可以在业务处理中只关心数据的流转,而无需直接和页面打交道。

# Vue 和 React 的区别:

相同点
 使用 Virtual DOM
 中心思想相同:一切都是组件,组件实例之间可以嵌套;都提供合理的钩子函数

不同点
 在 React 应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树
 在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,所以系统能精确知晓哪个组件确实需要被重渲染
 React 采用特殊的 JSX 语法,Vue.js 在组件开发中推崇编写.vue 特殊文件格式

# Vue 和 Angular 的区别:

相同点
 都支持指令:内置指令和自定义指令,vue 在设计之初参考了很多 angular 的思想(例如 v-if vs ng-if)
 都支持过滤器:内置过滤器和自定义过滤器  都支持双向数据绑定;都不支持低端浏览器

不同点
 在性能上,AngularJS 依赖对数据做脏检查,所以 Watcher 越多越慢;Vue 采用数据劫持实现双向绑定,但是代价是对于 ie9 以下的浏览器无法支持

# MVVM 与 MVC 区别:

 MVVM 与 MVC 两者之间最大的区别就是:MVVM 实现了对 View 和 Model 的自动同步,也就是当 Model 的属性改变时,我们不用再自己手动操作 Dom 元素来改变 View 的变化,而是改变其属性后,该属性对应的 View 层数据会自动改变。

# 2. Vue 指令

# ①、v-if 和 v-show 的区别

相同点:
 v-if 与 v-show 都可以动态控制 dom 元素显示隐藏
不同点:
 v-if 显示隐藏是将 dom 元素整个添加或删除
 而 v-show 隐藏则是为该元素添加 css--display:none,此时 dom 元素还在

TIP

  • 如果需要非常频繁地切换,则使用 v-show 较好
  • 如果在运行时条件很少改变,则使用 v-if 较好

# ②、v-text

<span v-text="msg"></span>
1

v-text 主要用来更新 textContent,可以等同于 JS 的 text 属性

# ③、v-html

双大括号的方式会将数据解释为纯文本,而非 HTML 为了输出真正的 HTML,可以用 v-html 指令 它等同于 JS 的 innerHtml 属性

<div v-html="rawHtml"></div>
1

这个 div 的内容将会替换成属性值 rawHtml,直接作为 HTML 进行渲染

  • 在⽹站上动态渲染任意 HTML,很容易导致 XSS 攻击。所以只能在可信内容上使⽤ v-html,且永远不 能⽤于⽤户提交的内容上

# ④、v-for

用 v-for 指令根据遍历数组来进行渲染 有下面两种遍历形式

<!-- 使用in,index是一个可选参数,表示当前项的索引 -->
<div v-for="(item,index) in items"></div>
1
2
<!-- 使用of -->
<div v-for="item of items"></div>
1
2

# ⑤、v-bind

v-bind 用来动态的绑定一个或者多个特性。没有参数时,可以绑定到一个包含键值对的对象
常用于动态绑定 class 和 style。以及 href 等
简写为一个冒号【 :】

<1>对象语法:

<div :class="{'is-active':isActive, 'text-danger':hasError}"></div>
<!-- data: { isActive: true, hasError: false } -->
1
2

<2>数组语法:

<p :class="[{'is-active':activeClass},errorClass]">12345</p>
<!-- data: { activeClass: false, errorClass: 'text-danger' } -->
1
2
// 三目运算符绑定
<div :class="[loginActive ? 'activeTab' : '','tabpane']"></div>
1
2

<3>直接绑定数据对象:

<div :class="classObject">12345</div>
<!-- data: { classObject:{ 'is-active': false, 'text-danger':true } } -->
1
2

<4>样式三元运算:

:style="{'color': countdown.status ? 'blue' : '#FCB11C'}" ;
1

# ⑥、v-model

这个指令用于在表单上创建双向数据绑定
v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值
因为它选择 Vue 实例数据做为具体的值。

# ⑥、v-on

v-on 主要用来监听 dom 事件,以便执行一些代码块。表达式可以是一个方法名
简写为:【 @ 】

# 自定义指令:

有的情况下,需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令

directives: {  // 局部注册指令
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}

<input v-focus> // 在元素上使用指令
1
2
3
4
5
6
7
8
9
10

指令注意事项:

WARNING

  • 1、当 v-for 和 v-if 处于同一节点,v-for 的优先级比 v-if 更高,永远不要把 v-if 和 v-for 同时用在同一个元素上
  • 2、如果一组 v-if + v-else 的元素类型相同,最好使用 key

# 3.父子组件间通信

# 3-1、 父组件 传数据 子组件

parent.vue:

<children v-bind:toChildData="parentSourceData"></children>
1

children.vue:

props: ["toChildData"];
1

# 3-2、 父组件 调用 子组件 方法

parent.vue:

<children ref="refChildrenName"></children>
1

method:

this.$refs.refChildrenName.子组件的方法名();
1

# 3-3、 子组件 传数据 父组件

parent.vue:

<children v-on:fromChild="parentMethod"></children>
1

children.vue:

this.$emit("fromChild", args);
1

# 3-4、 子组件 调用 父组件方法

parent.vue:

<children></children>
1

children.vue:

this.$parent.parentMethod(args);
1

或者在子组件里用$emit 向父组件触发一个事件,父组件监听这个事件就行了

<child @fatherMethod="fatherMethod"></child>

childMethod() { this.$emit('fatherMethod'); }
1
2
3

# 3-5、 子组件使用.sync 修饰符

# 4.组件上总是必须用 key

key 的作用是为了在 diff 算法执行时更快的找到对应的节点,提高 diff 速度。
key 一般用每个元素对应固定不变的值,如 id,对于数组索引 index 由于在插入数据时会变化,不推荐使用
注意:有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误,常见于 v-for 循环渲染。

# 5.Proxy 与 Object.defineProperty 对比

Object.defineProperty 虽然已经能够实现双向绑定了,但是他还是有缺陷的

1、只能对属性进行数据劫持,所以需要深度遍历整个对象
2、对于数组不能监听到数据的变化
3、Proxy 的第二个参数可以有 13 种拦截方法,比 Object.defineProperty() 要更加丰富
4、Proxy 的兼容性不如 Object.defineProperty() 不能使用 polyfill 来处理兼容性 Proxy 能够原生支持监听数组变化,并且可以直接对整个对象进行拦截

所以在 Vue3.0 中使用 Proxy 代替 Object.defineProperty

# 备注:vue2 对数组的监听:

Vue 包含一组观察数组的变异方法(改变原数组),所以它们也将会触发视图更新。这些方法如 push()等 7 种:
对于非变异方法如 slice(),可以用新数组替换旧数组 arr = arr.slice(1)
由于 JavaScript 的限制,Vue 不能检测以下变动的数组
1、直接设置一个项时,例如:vm.items[indexOfItem] = newValue
2、修改数组的长度时,例如:vm.items.length = newLength 或者 vm.items.length++
解决方法:
对于第一种:Vue.set(vm.items, indexOfItem, newValue) 或者 vm.$set(vm.items, indexOfItem, newValue)
对于第二种:vm.items.splice(newLength)

# 6.组件的 data 必须是一个函数

因为组件是要共享的,但他们的 data 是私有的。 如果 data 是一个普通的对象,则所有的实例将共享引用同一个数据对象。 因此组件的 data 必须是一个函数,这样每个实例可以维护一份被返回对象的独立的拷贝

# 注: 在一 Vue 的根实例上 data 直接使用对象是可以的

因为只存在一个这样的实例

new Vue({
  data: {
    foo: "bar"
  }
});
1
2
3
4
5

# 7.keep-alive

vue2.0 提供了一个 keep-alive 组件, 用来缓存组件,主要用于保留组件状态或避免重新渲染。
activated: keep-alive 组件激活时调用
deactivated: keep-alive 组件停用时调用

# 8.方法(methods)、计算属性(computed)、侦听属性(watch)

计算属性是基于它们的依赖进行缓存,只有在相关依赖发生改变时它们才会重新求值
缓存的作用:对于性能开销较大的计算不需重复执行
缺点:像 Date.now()的计算属性就不再更新,因为 Date.now() 不是响应式依赖,如果你不希望有缓存,用方法来替代。
计算属性默认只有 getter ,也可以提供一个 setter :

computed: {
    comItem: {
        get: function(){},
        set: function(newval){}
    }
}
// 触发顺序:页面首次加载触发get,数据变动时先触发set,然后在触发get
1
2
3
4
5
6
7

# methods VS computed

重新计算开销很大的话,选 computed; 不希望有缓存的选 methods

# computed VS watch

watch 有新旧值两个参数, 计算属性没有,但是计算属性可以从 setter 获得新值,computed 对于多数据变动,watch 适用于一个数据变动,watch 的对象必须事先声明,而 computed 则不用。

computed 计算属性,是依赖其他属性的计算值,并且有缓存,只有当依赖的值变化时才会更新。
watch 是在监听的属性发⽣变化时,在回调中执⾏⼀些逻辑。
所以, computed 适合在模板渲染中,某个值是依赖了其他的响应式对象甚⾄是计算属性计算⽽来,
⽽ watch 适合监听某个值的变化去完成⼀段复杂的业务逻辑。

# 9.过滤器

过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示:

<!-- 在双花括号中 -->
{{ message | capitalize }}

<!--`v-bind`-->
<div v-bind:id="rawId | formatId"></div>

filters: {
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 10.Vue ref

ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。
如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。

<p ref="p">hello</p>

<child-component ref="child"></child-component>
1
2
3

TIP

  • 当 v-for 用于元素或组件的时候,引用信息将是包含 DOM 节点或组件实例的数组。
  • 除了可以获取dom元素,还能获取子组件中的data和去调用子组件中的方法

# 11.Vue hooks

# 1、内部监听生命周期函数

mounted() {
  // 监听窗口发生变化,resize组件
  window.addEventListener('resize', this.$_handleResizeChart)
  // 通过hook监听组件销毁钩子函数,并取消监听事件
  this.$once('hook:beforeDestroy', () => {
    window.removeEventListener('resize', this.$_handleResizeChart)
  })
}
1
2
3
4
5
6
7
8

# 2、外部监听生命周期函数

<template>
  <!--通过@hook:updated监听组件的updated生命钩子函数-->
  <!--组件的所有生命周期钩子都可以通过@hook:钩子函数名 来监听触发-->
  <custom-select @hook:updated="$_handleSelectUpdated" />
</template>

<script>
import CustomSelect from '../components/custom-select'
export default {
  components: {
    CustomSelect
  },
  methods: {
    $_handleSelectUpdated() {
      console.log('custom-select组件的updated钩子函数被触发')
    }
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 12.v-text,v-html和{{}}的区别

v-text:是操作网页元素中的纯文本内容 {{}}是它的另一种写法, v-text与{{}}等价,{{}}叫模板插值,v-text叫指令

区别:在渲染数据比较多的时候,可能会把大括号显示出来,俗称屏幕闪动

v-html:可以渲染出html

# 13.Vue常用的修饰符

.lazy(当光标离开标签时,才会将值赋值给value)
.trim(过滤掉两边的空格)
.stop(阻止事件的冒泡,相当于调用了event.preventPropagation方法)
.prevent(阻止了事件的默认行为,相当于调用了event.preventDefault方法)
.once(绑定了事件以后只能触发一次,第二次就不会触发)
.native(在自定义组件标签上绑定原生事件)

# 14. Vue在哪个生命周期发起Ajax请求

  • 在获取数据后,对数据的处理如果不涉及DOM,可在 created 阶段获取,毕竟速度更快一些
  • 如果数据涉及到DOM的处理,则要在mounted阶段获取数据

# 15. Vue.nextTick 的原理和用途

  • 说明:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。
Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新

//改变数据
vm.message = 'changed'
//想要立即使用更新后的DOM。这样不行,因为设置message后DOM还没有更新
console.log(vm.$el.textContent) // 并不会得到'changed'
//这样可以,nextTick里面的代码会在DOM更新后执行
Vue.nextTick(function(){
    console.log(vm.$el.textContent) //可以得到'changed'
})
1
2
3
4
5
6
7
8
  • 用途:需要在视图更新之后,基于新的视图进行操作

# 16. Vue单向数据流

子组件不可以修改父组件传递的Prop

  • 子组件如何修改父组件的值

1、通过$emit
2、通过.sync修饰符

# 16. v-for 和 v-if 不建议⽤在⼀起

当 v-for 和 v-if 处于同⼀个节点时, v-for 的优先级⽐ v-if 更⾼,这意味着 v-if 将分别重复 运⾏于每个 v-for 循环中。如果要遍历的数组很⼤,⽽真正要展示的数据很少时,这将造成很⼤的性 能浪费。 这种场景建议使⽤ computed ,先对数据进⾏过滤。

# 17. Vue的性能优化

尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
v-if和v-for不能连⽤
如果需要使⽤v-for给每项元素绑定事件时使⽤事件代理
SPA ⻚⾯采⽤keep-alive缓存组件
key保证唯⼀
使⽤路由懒加载、异步组件
第三⽅模块按需导⼊ ⻓列表滚动到可视区域动态加载 图⽚懒加载

# 其他

  • Vue 不能挂载在 body、html 这样的根节点上

  • router.push 只能跳转路由内部的页面,要想跳转到外部页面,可以使用 window.location.href

lastUpdate: 9/14/2022, 9:26:14 PM