# Vue

# 响应数据原理

Vue底层响应数据的核心是Object.defineProperty。Vue通过数据劫持配合发布者-订阅者的设计模式,内部通过调用object.defineProperty()来劫持各个属性的getter和setter,在数据变化的时候通知订阅者,并触发相应的回调。

Vue主要通过4个步骤实现数据双向绑定:

  1. 实现一个监听器「Observer」。对数据对象进行遍历,利用Object.defineProperty()在属性上都加上getter和setter来给对象赋值触发setter,这样就能监听到数据变化。
  2. 实现一个解析器「Compile」。解析Vue模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者。一旦数据变化,就调用更新函数进行数据更新。
  3. 实现一个订阅者「Watcher」。Watcher订阅者是Observer和Compile之间通信的桥梁,主要任务是订阅Observer中的属性值变化的消息,当收到属性值变化的消息时,触发解析器Compile中对应的更新函数。
  4. 实现一个订阅器「Dep」。订阅器采用发布-订阅设计模式,用来收集订阅者Watcher,对监听器Observer和订阅者Watcher进行统一管理。

# 如何监听对象/数组

Object.defineProerty不能监听数组变化,Vue通过重写push、pop等方法实现数组监听。

# 复杂对象深度监听

# 缺点

  1. 深度监听,需要递归到底,一次性计算量大

  2. 无法监听新增/删除的data属性(需用Vue.set/Vue.delete)

  3. 无法原生监听数组

# 虚拟DOM

虚拟DOM是一个存储有DOM信息的JS对象。当我们修改我们的数据,重新生成新的虚拟DOM,新老虚拟DOM进行DIFF操作之后,框架底层内部会对我们的真实DOM进行操作。

# 优缺点

优点:

  1. 保证性能下限。框架的虚拟Dom需要适配任何上层API可能产生的操作,它的一些Dom操作的实现必须是普遍适用的,所以它的性能并不是最优的,但比起粗暴的Dom操作要好很躲,因此保证了性能的下限。
  2. 跨平台。虚拟Dom本质上是JavaScript对象,而真实Dom与平台相关,相比下虚拟Dom可以更好地跨平台操作。
  3. 无需手动操作DOM。框架会根据虚拟Dom和数据的双向绑定,帮我们更新视图。

缺点:

无法做到极致的优化。虚拟DOM的使用可以保证性能的下限,但也正是因为如此,它也无法做到极致的优化。

# 实现原理

  1. 用JS对象模拟真实Dom树,对真实Dom进行抽象。
  2. 通过diff算法对比两棵虚拟DOM树。
  3. 通过patch算法将两个虚拟DOM对象的差异应用到真实的DOM树上。

# 借鉴的来源

  • Vue2中虚拟DOM借鉴了snabbdom.js
  • Vue3中借鉴inferno.js

# Diff算法

# 核心概念

h、vnode、patch、diff、key

# 模板编译

  1. 通过vue-template-compiler编译为render函数

  2. 执行render函数返回vnode

  3. 基于vnode再执行patch和diff

# 初次渲染过程

  1. 解析模板为render函数

  2. 触发响应式,监听data属性的getter和setter

  3. 执行render函数,生成vnode,patch

# 更新过程

  1. data中的数据被修改后,触发setter

  2. 重新执行render函数,生成newVnode

  3. patch(vnode,newVnode)

# nextTick

# 实现原理

EventLoop事件循环机制

# 作用

dom重新渲染挂载完毕执行的回调,当我们修改数据之后立即使用nextTick()来获取最新更新的dom。(页面渲染时会将data的修改整合,多次修改会合并一次渲染)

# Vue初始化干了什么

合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等

# 对MVVM的理解

# View 层

View 是视图层,也就是用户界面。前端主要由 HTML 和 CSS 来构建 。

# Model 层

Model 是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,对于前端来说就是后端提供的 api 接口。

# ViewModel 层

ViewModel是指视图数据层,数据驱动视图。数据更新相应的视图也发生改变,无需手动操作DOM。

# Vue和React

# 相似之处

# 虚拟DOM

vue 和 react 中都使用了虚拟DOM(virtual DOM)技术。

# 组件化

Vue和React都提倡组件化。

# 不同之处

# 设计理念

  • React更偏向于构建稳定大型的项目
  • Vue偏向于小型灵活的项目

# 模板语法

**Vue:**接近HTML的语法。

React:JS语法拓展——JSX,它是JavaScript混合着XML语法。

# 组合功能方式

  • React一开始使用mixin,后来转HoC(高阶组件)。高阶组件的本质是高阶函数,而React的组件是一个纯粹的函数。所以,React使用HoC很简单。
  • Vue一直都是使用mixin。Vue中的组件是一个被包装的函数,Vue经过一系列处理才返回高阶组件的。所以,处理起来没有那么方便。

# 数据流

**Vue:**Vue2.0之后,父子组件变成了单向绑定。

**React:**从一开始就不支持双向绑定,使用的是单向数据流。

# 状态管理

  1. Redux 使用的是不可变数据,而Vuex的数据是可变的。Redux每次都是用新的state替换旧的state,而Vuex是直接修改。
  2. Redux 在检测数据变化的时候,是通过 diff 的方式比较差异的,而Vuex其实和Vue的原理一样,是通过 getter/setter来比较的。

# Vue常用指令

  1. v-bind,缩写为:
  2. v-on,缩写为@
  3. v-show
  4. v-if
  5. v-for
  6. v-model
  7. v-text,等价{{}}
  8. v-html,用来识别HTML标签并进行渲染
  9. v-once

# 常用修饰符

# 表单修饰符

# lazy——光标离开更新

# trim——过滤首尾空格

# number

如果你先输入数字,那它就会限制你输入的只能是数字。 如果你先输入字符串,那它就相当于没有加.number 而不是单一的限制输入数字或者输入的东西转换成数字

# 事件修饰符

# stop——阻止事件冒泡

阻止事件向父级传递,相当于调用了event.stopPropagation()

# self——点击元素本身触发

<div class="blue" @click.self="shout(2)">
  <button @click="shout(1)">ok</button>
</div>

# 按键修饰符

.ctrl    Alt或者Shift被同时按下时触发

.ctrl.exact    有且只有ctrl按下时触发

.exact    没有任何系统修饰符时触发

# prevent——阻止事件默认行为

用于阻止事件的默认行为,例如,当点击提交按钮时阻止对表单的提交。相当于调用了event.preventDefault()方法。

# once——只触发一次

# capture——向下捕获

默认事件触发是从目标开始往上冒泡的,但 当加了这个.capture以后就反过来了

<div @click.capture="shout(1)">
  obj1
  <div @click.capture="shout(2)">
    obj2
    <div @click="shout(3)">
      obj3
      <div @click="shout(4)">
        obj4
      </div>
    </div>
  </div>
</div>

# 滚动事件延迟

当我们在监听元素滚动事件的时候,会一直触发onscroll事件,在pc端是没啥问题的,但是在移动端,会让我们的网页变卡,因此我们使用这个修饰符的时候,相当于给onscroll事件整了一个.lazy修饰符

# native——转化为原生事件

# v-bind修饰符

  • prevent :拦截默认事件
  • passive :不拦截默认事件
  • stop :阻止事件冒泡
  • self :当事件发生在该元素而不是子元素的时候会触发
  • capture :事件侦听,事件发生的时候会调用

# 动态绑定Class/Style

# 对象

<div :class="{ active: isActive, 'text-danger': hasError }"></div>
<div :class="[isActive ? activeClass : '', errorClass]"></div>
<p :style="styleData">使用style</p>

data: {
  activeClass: 'active',
  errorClass: 'text-danger',
  isActive: true,
  hasError: false,
  styleData: {
    fontSize: '24px',
    color: 'red'
  }
}

# v-if和v-show区别

# v-if

渲染:只有条件为true时,才会渲染页面。

切换:在切换的过程中,子组件会被销毁和重建。

开销:有更高的切换开销。

# v-show

渲染:不管初始条件是什么,v-show里面的元素总是会被渲染。

切换:只是简单地基于 CSS 进行切换。(display: none)

开销:有更高的初始渲染开销。

# computed和watch区别

# computed

  1. computed主要是计算值得,并且具有缓存功能。只要在它依赖的值变化时才会重新计算。
  2. 不支持异步,当computed中有异步操作时,无法监听数据的变化。

# watch

  1. watch主要是监听属性变化的。
  2. 支持异步监听。

computed缓存值原理: computed拥有自己的watcher,它内部有个dirty属性,用来决定是否要重新计算当前的值。第一次求值的时候,会将dirty设置为false,当与它相关的data属性发生了变化之后,会通知相对应的watcher把自身的dirty设置为true。下次再调用的时候,就会重新计算了。

# Watch中的deep:true实现原理

因为 Vue 内部对需要 deep watch 的属性会进行递归的访问,而在此过程中也会不断发生依赖收集。

注意

  1. watch监听引用类型是拿不到oldVal的,引用类型复制是指针赋值的关系

  2. 监听引用类型需要深度监听

  watch: {
    list(oldValue, value) {
      console.log(oldValue, value);
    },
    person: {
      handler(oldValue, value) {
        console.log(oldValue, value);
      },
      deep: true
    },
  }

# 生命周期

Vue的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。

  • beforeCreate

  • Created

    • 数据观测
    • 属性和方法的运算
    • 事件回调
    • 发送请求
    • 还没有$el。
  • beforeMount

  • mounted

    • DOM操作
  • beforeUpdate

  • updated

  • beforeDestroy

  • destroyed

    • 清空定时器
    • 清理缓存

# 父子组件生命钩子执行顺序

  • 加载渲染过程

    父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted

  • 子组件更新过程

    父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated

  • 父组件更新过程

    父 beforeUpdate -> 父 updated

  • 销毁过程

    父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed

# 绑定事件

       <h3 @click="handleWatch">Ecosystem</h3>
       <h3 @click="handleWatch1(1, $event)">Ecosystem</h3>


     handleWatch(event) {
      console.log(event.__proto__.constructor);
    },
    handleWatch1(1,event) {
      console.log(event.__proto__.constructor);
    },

# 插槽

# 原理

当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在vm.$slot中,默认插槽为vm.$slot.default,具名插槽为vm.$slot.xxx,xxx 为插槽名,当子组件执行渲染函数时候,遇到slot标签,使用$slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

# 分类

# 默认插槽

# 具名插槽

多个插槽

# 作用域插槽

让插槽内容能够访问子组件中才有的数据

# 组件间通信

# 父子组件通信

# props/$emit

# 父传子(props)

父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed

父组件
<compB  :moreBtn="moreBtn" @more="onMore('form~')"/>

<script>
  data() {
    return {
      title: 'title~',
      moreBtn: true
    }
  },

</script>
// 子组件数据写在props里面,而不是data
props:{
    users:{  //这个就是父组件中子标签自定义名字
        type:Array,
            required:true
    }
}
# 子传父(emit和回调函数)
// 子组件
this.$emit("titleChanged","子向父组件传值");//自定义事件  传递值“子向父组件传值

子组件

// 父组件
<app-header v-on:titleChanged="updateTitle" ></app-header>//与子组件titleChanged自定义事件保持一致
// updateTitle($event)接受传递过来的文字
<h2>{{title}}</h2>
<script>
    ...
   data(){
        title:"传递的是一个值"
    }
  methods:{
    updateTitle(e){   //声明这个函数
      this.title = e;
    }
  },
    ...
</script>

# $parent/$children

$children 的值是数组,而$parent是个对象

 // 获取到子组件A
 this.$children[0].messageA = 'this is new value'

// 获取父组件msg的值
computed:{
  parentVal(){
    return this.$parent.msg;
  }
}

# ref/refs

ref在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据。

# 跨级通信

# provide/inject

父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。provide 和 inject 绑定并不是可响应的。但是,如果你传入了一个可监听的对象,那么这个对象的属性还是可响应的。

export default {
  name: "A",
  // 提供变量
  provide: {
    for: "demo"
  },
  components:{
    comB
  }
}

// 注入变量
export default {
  name: "C",
  inject: ['for'],
  data() {
    return {
      demo: this.for
    }
  }
}

# 事件总线(自定义事件)

可用在跨组件或者兄弟组件之间

发送事件用event.$emit

event.$emit("get-footer", "Fendy's Footer");

接收事件用event.$on

event.$on("get-footer", function (content) {
  // ...
});

注意

  1. 记得在destroyed生命周期用$off解绑on绑定的事件
  2. event为Vue实例

原理:可以使用一个空的 Vue 实例作为事件总线来实现自定义事件

# $attrs/$listeners

  1. 父组件跟props一样传值
  2. 中间组件在使用子组件时,需要v-bind="$attrs"将值传下去
  3. 子组件通过this.$attrs获取值
// 中间组件
<template class="border">
  <div>
    <p>name: {{ name}}</p>
    <p>childCom1的$attrs: {{ $attrs }}</p>
    <child-com2 v-bind="$attrs"></child-com2>
  </div>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
  components: {
    childCom2
  },
  inheritAttrs: false, // 关闭当前组件根元素上没有用props声明的属性
  props: {
    name: String // name作为props属性绑定
  },
  created() {
    console.log(this.$attrs);
     // { "age": "18", "gender": "女", "height": "158", "title": "程序员成长指北" }
  }
};
</script

# Vuex

# 兄弟通信

# 事件总线

# Vuex

# Vuex

Vuex 是一个专为Vue.js 应用程序开发的状态管理模式。

# 优缺点

优点:

  1. 解决了非父子组件的消息传递(将数据存放在state中)
  2. 减少了Ajax请求次数,有些情景可以直接从内存中的State获取
  3. 存储在vuex里面的数据都是响应式的,能够实时保持数据与页面同步

缺点:

  1. 刷新浏览器后,Vuex中state恢复初始状态。

# 常见属性

  1. State:vuex的基本数据,用来存储变量。
  2. Getter :从基本数据state派生的数据,相当于state的计算属性。
  3. Mutation :提交更新数据的方法,必须是同步的。
  4. Action :和mutation的功能大致相同,不同在于它不是直接更改状态的,可以包含任何异步操作。
  5. Module:模块化vuex,可以让每一个模块拥有自己的state,mutation,action,getter,使得结构清晰,方便管理。

# Vue Router

  1. route表示路由信息对象,包括:path,params,hash,query,fullPath,matched,name等路由信息参数。
  2. router表示路由实例对象,包括了路由的跳转方法,钩子函数等。

# 导航守卫

# 全局前置钩子

  1. beforeEach,
  2. afterEach,
  3. beforeResolve,

# 路由独享守卫

  1. beforeEnter

# 组件内部守卫

  1. beforeRouteEnter,
  2. beforeRouteUpdate,
  3. beforeRouteLeave

# 路由模式

hash/history

# 区别

  1. hash模式会在url上显示'#',而history模式没有。
  2. 刷新页面的时候,hash可以根据#号后面的内容加载到相应的页面,但是history模式不行,会返回404。
  3. 实现原理不一样。hash模式主要依靠onhashchange事件监听location.hash的;而history主要是依靠H5中history新增的pushState()和replaceState()这两个方法。
  4. 兼容性上,hash模式可以支持低版本浏览器和IE。

# 实现

# hash

后面的hash值不会刷新页面的,同时通过监听hash的变化而执行相应的实践,从而实现局部刷新。

# history

history模式最要用到HTML5里面的pushState和replaceState这两个API,这两个api可以更改url但是不会重新刷新页面,只会进行局部更新。

# 传参

# 通过params

  1. 只能用name,不能用path
  2. 参数不会显示在url上
  3. 浏览器强制刷新会清空参数

# 通过query

  1. 只能用path,不能用name
  2. 参数会显示在url上
  3. 浏览器刷新不清空参数
{
    path:'/details/:id',
    name:'Details',
    components:Details
}

this.$route.params.id

# 路由配置

动态路由、懒加载(异步加载组件)

# Vue实现对象和数组监听

由于Object.defineProperty()只能对属性进行数据劫持,而不能对整个对象(数组)进行数据劫持,因此Vue框架通过遍历数组和对象,对每一个属性进行劫持,从而达到利用Object.defineProperty()也能对对象和数组(部分方法的操作)进行监听。

# Vue检测数组变化原理

# 核心思想

使用了函数劫持的方式,重写了数组方法。(push、unshift、pop、shift)

Vue将data中的数组,进行了原型链的重写,指向了自己所定义的数组原型方法,当调用数组的API时,可以通知依赖更新,如果数组中包含着引用类型,会对数组中的引用类型再次进行监控。

# 常见问题

data中新增了数组或者对象属性,视图没有更新

解决方案

  1. 使用$set进行更新。
  2. 直接使用Vue重写的那起个数组方法进行修改。

$set原理

对新增的对象进行了依赖收集,调用触发更新视图的方法notify。

# 过滤器

过滤器是用来过滤数据的。

<li>商品价格:{{item.price | filterPrice}}</li>

filters: {
  filterPrice (price) {
    return price ? ('¥' + price) : '--'
  }
}

# Object.defineProperty缺点

  1. Object.defineProperty只能劫持对象的属性,因此需要遍历对象的每个属性,而Proxy可以直接代理对象。
  2. Object.defineProperty对新增属性需要手动进行观察。($set)
  3. Proxy性能高,支持13种拦截方式。

# data写成函数形式原因

维护每个组件间数据的独立性,不会相互影响。由于组件都是可复用的,所以组件内的data必须相互隔离。由于JS对象是引用类型的,如果以对象的形式返回的话,作用域没有隔离。

# Vue循环

# Vue中key的作用

key的作用是为了高效精准地更新DOM,减少渲染次数,提升渲染性能。因为diff算法是通过tag和key来判断是否为相同节点的。

不推荐使用数组索引作为key的原因

index 在同一个页面会有重复的情况,违背了高效渲染的初衷。

例如数组删除了一个元素,那么这个元素后方元素的下标全都前移了一位,之前key对应的数据和dom就会乱了。

# v-if和v-for不推荐同时使用

不推荐同时使用 v-if 和 v-for。 当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。

解决方案:使用computed过滤再for循环。

# vue的单向数据流

  1. 父组件可以通过prop将数据传递给子组件,但这个prop只能由父组件来修改,子组件修改的话会抛出错误。
  2. 如果是子组件想要修改数据,只能通过$emit由子组件派发事件,并由父组件接收事件进行修改。

# keep-alive

keep-alive是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中;使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

# 作用

用来缓存组件,一般结合动态路由和动态组件一起使用。

# 场景

用户在某个列表页面选择筛选条件过滤出一份数据列表,由列表页面进入数据详情页面,再返回该列表页面,我们希望:列表页面可以保留用户的筛选(或选中)状态。keep-alive就是用来解决这种场景。当然keep-alive不仅仅是能够保存页面/组件的状态这么简单,它还可以避免组件反复创建和渲染,有效提升系统性能。 总的来说,keep-alive用于保存组件的渲染状态。

# 独立生命周期

# activated

切换回组件时,渲染后执行activated钩子。

# deactivated

切换到别的组件时,将该组件缓存到内存中并执行deactivated钩子。

# 属性

# include

表示只有名称匹配的组件才会被缓存,

# exclude

表示只有名称匹配的组件都不会被缓存,优先级高于include。

# 实现原理

  1. created钩子会创建一个cache对象,用来作为缓存容器,保存vnode节点。
  2. destroyed钩子则在组件被销毁的时候清除cache缓存中的所有组件实例。

# Vue首屏加载优化

# UI组件按需加载

# 路由异步加载

# SPA单页面

SPA是指当页面加载完成,不会因为用户的操作而重新加载或跳转。它只是进行Html内容的变换,避免重新加载。

# 优点

  1. 用户体验好,页面切换速度快。
  2. SPA相对于服务器压力较小,因为不需要加载整个页面。
  3. 前后端分离,架构更清晰。

# 缺点

  1. 不利于SEO
  2. 首次加载耗时长。
  3. 不能使用前进后退功能。

# SSR

服务端渲染,是指Vue将浏览器渲染HTML的工作交给服务端,服务端渲染完成直接发送HTML给浏览器。

# 优点

  1. 更好的SEO。由于服务端返回已经渲染完成的页面,数据已经包含在页面中了。所以,搜索爬虫可以更好的抓取页面的里面的信息。
  2. 首屏加载更快。由于服务端返回已经渲染完成的页面,无需在等待下载JS文件后在渲染。所以,SSR有更快的内容到达时间。

# 缺点

  1. 增加服务器压力。
  2. 更多的开发条件限制。需要在NodeJs的环境中运行。

# Vue小技巧

# vue v-for 中更改item 属性值后,v-show不生效的问题

添加this.$forceUpdate();进行强制渲染,效果实现。 因为数据层次太多,render函数没有自动更新,需手动强制刷新。

# 组件中 data 为什么是一个函数,而 new Vue 实例里,data 可以直接是一个对象?

因为组件是用来复用的,且 JS 里对象是引用关系,如果组件中 data 是一个对象,那么这样作用域没有隔离,子组件中的 data 属性值会相互影响,如果组件中 data 选项是一个函数,那么每个实例可以维护一份被返回对象的独立的拷贝,组件实例之间的 data 属性值不会互相影响;而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。

# axios中断请求

# 如何取消请求

通过Axios提供的cancelToken来取消请求

config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
  if (!pendingRequest.has(requestKey)) {
    pendingRequest.set(requestKey, cancel)
  }
})

# 如何取消重复请求

新建一个map对象来维护已经发送但是还没有响应的请求,一般以请求的方法、url、参数这几个联合为key。在响应拦截器那里判断map对象是否存在当前的请求,如果不存在就添加进去。如果存在的话,就调用cancel方法取消请求,在响应请求拦截器中删掉map对象中当前的请求。

# CancelToken工作原理

# 修改ElementUI样式

# 使用全局样式统一覆盖

# 修改组件的style样式

# ElementUI官方修改样式的api

# 使用v-deep穿透

# !important

# v-model

# 原理

v-model 本质上是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  • text 和 textarea 元素使用 value 属性和 input 事件;
  • checkbox 和 radio 使用 checked 属性和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

# 自定义v-model

<template>
  <div>
    <input
      type="text"
      :value="text1"
      @input="$emit('change1', $event.target.value)"
    />
  </div>
</template>

<script>
export default {
  model: {
    prop: "text1",
    event: "change1",
  },
  props: {
    text1: String,
    default() {
      return "";
    },
  },
};
</script>

# vue-router 路由模式有几种?

其中,3 种路由模式的说明如下:

  • hash: 使用 URL hash 值来作路由。原理很简单,location.hash 的值就是 URL 中 # 后面的内容。
  • history : 依赖 HTML5 History API 和服务器配置。其中做最主要的 API 有以下两个:history.pushState() 和 history.repalceState()。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史纪录。
  • abstract : 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式.

# 事件总线原理

它的工作原理是发布/订阅方法,通常称为Pub/Sub 。 由于是全局的,必然所有事件都订阅它, 所有组件也发布到它,订阅组件获得更新。 也就是说所有组件都能够将事件发布到总线,然后总线由另一个组件订阅,然后订阅它的组件将得到更新。

# Mixin

# 缺点:

  1. 变量来源不明确,不利于阅读

  2. 多个mixin可能造成命名冲突

# Vue常见的性能优化

  1. v-if v-show

  2. 合理使用computed

  3. 自定义事件、DOM事件及时销毁

  4. 合理使用keep-alive

  5. data数据不要太深

Last Updated: 4/21/2022, 5:35:47 PM