vue2初总结

7/8/2025 vue2

# 1 Vue是什么?

Vue是一套用于构建用户界面渐进式Javascript框架。

# 核心特点

  1. 采用组件化模式,提高代码复用率、且让代码更好的维护。
  2. 声明式编码,让编码人员无需直接操作DOM,提高开发效率。
  3. 使用虚拟DOM,提高复杂页面数据的渲染效率。
  4. 数据发生变化,页面自动刷新?

# 2 Vue 模板语法

# 插值语法

双花括号包裹的 js表达式 ,可以读取 data 中的所有属性。 一般用于标签体的内容。

# 指令语法

功能:用于解析标签(包括:标签属性、标签体内容、绑定事件...) 一般用 v-... 来绑定

# v-bind

在标签属性前添加 v-bind: 或者简写成 : 对属性值进行绑定

<div v-bind:name="xxx">div标签</div>
1

name属性值 xxx 也是js表达式,可以是 data 中的任意属性名。

# 3 数据绑定

# 单向数据绑定

v-bind data 属性变化后会通知页面更新,但是页面值变化后不会影响 data

# 双向数据绑定

v-model data 属性变化后会通知页面更新,页面值变化后也会影响 data 发生变化。 v-model 只能用于表单类元素中。 v-model:value 简写 v-model=""

# 4 MVVM 模型

MVVM、MVC和MVP是常见的架构模型

# MVC模型

MVC 将应用分为三个部分:

  • Model(模型):负责数据管理
  • View(视图):负责用户界面
  • Controller(控制器):负责业务逻辑,连接模型和视图

在 MVC 中,控制器接收用户输入,操作模型数据,然后更新视图。视图和模型之间可能存在直接通信。

# MVP模型

MVP 是 MVC 的改进版:

  • Model(模型):负责数据管理
  • View(视图):负责用户界面
  • Presenter(展示器):作为视图和模型的中间人

在 MVP 中,视图和模型完全分离,所有交互都通过 Presenter 进行。视图只负责显示,不包含业务逻辑。

# MVVM模型

  • Model(模型):数据模型
  • View(视图):用户界面
  • ViewModel(视图模型):连接视图和模型的桥梁

MVVM 的核心特点是数据绑定机制,实现了视图和模型的自动同步。

# Vue中的MVVM

pasted_image1745291611881.png

# 5 数据代理

Vue中的 data 是经过数据劫持后的代理,数据劫持后挂在Vue实例的 _data 属性上。

Vue2中的数据代理的基本原理是: 通过 Object.defineProperty() 把 data 对象中的所有属性添加到 vue实例上。并且为每个属性都指定了一个 getter/setter , 在getter/setter内部去操作 data 中对应的属性。

Vue3的话把 Object.defineProperty() 改为 ES6的 Proxy(),更加强大,属性对象的属性也可以监测。更多后续学习。

# 6 事件处理

# 事件基本使用

#事件基本使用

  1. 使用 v - on:xxx 或 @xxx 绑定事件,其中 xxx 是事件名;
  2. 事件的回调需要配置在 methods 对象中,最终会在 vm 上;
  3. methods 中配置的函数,不要用箭头函数!否则 this 就不是 vm 了;
  4. methods 中配置的函数,都是被 Vue 所管理的函数,this 的指向是 vm 或 组件实例对象;
  5. @click="demo" 和 @click="demo ($event)" 效果一致,但后者可以传参

指令:v-on 绑定事件: v-on:click="xxx" 可以简写 @click=”xxx“

...
<button @click="showInfo">无参</button>
<button @click="showInfo2(abc)">有参</button>
<button @click="showInfo3($event, haha)">有参,携带event对象</button>
...

const vm = new Vue({
  el: '#root',
  data: {
    aa: '123'
  },
  methods: {
	showInfo(event) {
	  // event.target.current 获取 dom 对象
	  console.log(event);
	},
	showInfo2(str) {
	  // 无法获取 event 对象
	  console.log(str)
	},
	showInfo3(event, str) {
	  // 有 event 对象
	}
  }
})
const 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 事件修饰符

  • @click.prevent 阻止默认事件,不用手动调用 e.preventDefalut();
  • stop 阻止事件冒泡,不用手动调用 e.stopPropagation()
  • once 事件只触发一次
  • capture 使用事件的捕获模式(由外到内,与冒泡相反,正常是先捕获再冒泡,事件一般是冒泡阶段处理)
  • self 只有 event.target 是当前操作的元素才触发事件
  • passive 事件的默认行为立即执行,无需等待事件回调执行完毕(移动段滚动的时候,可能用得较多点)

修饰符可以连着写,如先阻止冒泡,再阻止默认行为: @click.stop.prevent

# 键盘事件

@keyup 键盘弹起事件 @keydown 键盘按下事件 可以设定指定按键触发,

@keyup="showInfo"

showInfo(e) {
  if (e.keyCode == 13) { // 回车
    console.log(e.target.value)
  }
}
1
2
3
4
5
6
7

或者使用按键别名来控制: @keyup.enter="showInfo" Vue 中常用的按键别名:

  • 回车 => enter
  • 删除 => delete(捕获 “删除” 和 “退格” 键)
  • 退出 => esc
  • 空格 => space
  • 换行 => tab (用法特殊,一般配合 keydown 使用)
  • 上 => up
  • 下 => down
  • 左 => left
  • 右 => right

Vue 未提供别名的按键,可以使用按键原始的 key 值(e.key)去绑定,但注意要转为 kebab-case(短横线命名)

系统修饰键(用法特殊):ctrl、alt、shift、meta

  • (1) 配合 keyup 使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
  • (2) 配合 keydown 使用:正常触发事件。
  • (3) 可以连写变组合建(@keyup.ctrl.y,只有按住ctrl+y 弹起时触发)

也可以使用 keyCode 去指定具体的按键(不推荐)

Vue.config.keyCodes. 自定义键名 = 键码,可以去定制按键别名

# 7 计算属性-computed

# 基础概念和细节

  1. 定义:要用的属性不存在,要通过已有属性计算得来。
  2. 原理:底层借助了 Object.defineProperty 方法提供的 getter 和 setter。
  3. get 函数什么时候执行?
    • (1). 初次读取时会执行一次。
    • (2). 当依赖的数据发生改变时会被再次调用。
  4. 优势:与 methods 实现相比,内部有缓存机制(复用),效率更高,调试方便。
  5. 备注:
      1. 计算属性最终会出现在 vm 上,直接读取使用即可。
      1. 如果计算属性要被修改,那必须写 set 函数去响应修改,且 set 中要引起计算时依赖的数据发生改变。
new Vue({
  // ...
  computed: {
    myComputedAttr: {
      get(){
      },
      set(value){
      }
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11

# 简写方式

如果只有 get 方法,不考虑 set 方法时,则可以将计算属性改为 函数。

new Vue({
  // ...
  computed: {
    myComputedAttr(){
      // 计算逻辑
    }
  }
})
1
2
3
4
5
6
7
8

# 8 监视属性- watch

# 定义及基础使用

  1. 当被监视的属性变化时,回调函数自动调用,进行相关操作
  2. 监视的属性必须存在,才能进行监视!!
  3. 监视的两种写法:
    • (1). new Vue 时传入 watch 配置
    • (2). 通过 vm.$watch 监视,(动态开启监视)
const vm = new Vue({
  el:'#root',
  data: {
    age: 18,
    user: {
      name: 'wawa'
    }
  },
  computed: {
    aage100(){
      return this.age + 100
    }
  },
  watch: {
    age: {
      handler(newVal, oldVal) {
        console.log("新值"+newVal, "旧值"+oldVal);
      }
    },
    aage100(newVal, oldVal){ // 1.只有一个 handler 配置项时 可以简写。 2.计算属性也可以监视
    },
    'user.name':{ // 嵌套属性监视
      handler(newVal, oldVal) {
      },
      deep: true,    // 深度监视对象内部变化
      immediate: true // 立即执行一次,初始化时调用一下,触发 handler
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 深度监视

(1). Vue 中的 watch 默认不监测对象内部值的改变(一层)。
(2). 配置 deep:true 可以监测对象内部值改变(多层)。
备注:
(1). Vue 自身可以监测对象内部值的改变,但 Vue 提供的 watch 默认不可以!
(2). 使用 watch 时根据数据的具体结构,决定是否采用深度监视。

# 9 watch 对比 computed

  1. computed能实现的,watch 都能实现。
  2. watch 能实现的, computed 不一定能实现,比如 watch 可以进行异步操作。 小注意点:
  3. 当watch 和 computed 都能实现的时候,推荐使用 computed 实现,更加简洁、性能也更高,同时避免滥用 watch。

# 10 绑定样式

# 1. 绑定 class

正常的样式 正常写,需要变化的样式 通过 绑定属性来处理。

<div v-bind:class="绑定的方式"></div>
1

绑定的方式可以是:

  1. 基础方式:<div :class="demo"></div>
  2. 数组方式:<div :class="[demo1, demo2]"></div>
  3. 或者对象(对象属性是类名,属性值是布尔值,真值(truthy)是用,假值(falsy)是不用):<div :class="{demo1: true}"></div> demo、demo1、demo2 都是 data 中的属性。

组件上使用:

当在一个自定义组件上使用 class property 时,这些 class 将被添加到该组件的根元素上面。这个元素上已经存在的 class 不会被覆盖。

# 2. 绑定 style

一般直接用对象,注意原生短横线需要改为驼峰写法。

<div v-bind:style="styleObject"></div>

data: {  
	styleObject: {  
		color: 'red',  
		fontSize: '13px'  
	}  
}
1
2
3
4
5
6
7
8

# 11 条件渲染

# v-show 控制

指令 v-show 来控制, DOM结构在,不显示。类似 display: none, 适合频繁切换显示隐藏的情况。

# v-if 控制

DOM结构都不在。 判断,结构不能被打断,需要连续:

<div v-if=""></div> 
<div v-else-if =""></div>
1
2

# 12 循环渲染

指令 v-for 用法:v-for="(item,index) in obj" 循环的元素不能忘了:key=""` 可以遍历 数组、对象、字符串

# 13 key的作用

虚拟dom中key是对象的标识,当状态中的数据发生变化的时候,Vue会根据新数据生成新的虚拟dom,随后新的虚拟dom会和旧的虚拟dom按照 key 进行差异比较(DIFF): 1)旧虚拟dom找到与新虚拟dom相同的key时, 若虚拟dom的内容没有发生变化,则直接使用之前的真实dom; 若虚拟dom的内容变了,则生成新的真实dom,随后替换之前的真实dom。 2)旧虚拟dom没有找到与新虚拟dom相同的key 则创建新的真实dom,随后渲染到页面上。

# 14 Vue监测数据的原理

Vue.set() | vm.$set

Vue 会监视 data 中所有层级的数据。 其通过数据劫持,进行加工后给 data 的每个对象属性增加了 gettersetter 进行监视,setter 调用后会通知页面进行更新。 需要注意的是,如果直接给vue实例对象或其_data上增加新的对象属性,Vue是不会做响应式处理的也就不会更新页面,可以通过Vue提供的API —— Vue.set() 来添加,Vue.set() 添加的属性也是会进行加工处理的,但 set 不能给 vue 实例对象或者对象的根数据对象 添加属性。 还需要注意的是,data数组如果通过索引方式重新赋值,Vue是不会进行更新页面操作的,只有通过其包装后的7个方法改变数组元素才行:push、pop、shift、unshift、splice、sort、reverse

# 15 表单数据收集

主要还是通过 v-model 来处理,但是表单元素多,需要看看有哪些注意点。

v-model 收集的是 表单的 value 值, 如果是非输入框(下拉、单选、多选)别忘了 value 属性,其中一组多选框得将绑定的变量设置为数组,否则有问题,如果单选、多选框没有设置 value 属性,则收集的是是否勾选的Boolean值。

<!-- 例如 多选框,如果没有设置 value 属性,双向绑定的 title 收集的就是 是否勾选的 Boolean值 -->
标题1<input type="checkbox" name="title" v-model="title" value="标题1"/>
标题2<input type="checkbox" name="title" v-model="title" value="标题2"/>
1
2
3

变量要求数字类型:v-model.number='' 去除前后空格: v-model.trim=''

应该还有其他的注意点,只有在后面练习的时候才能发现了。

# 16 过滤器

不常用,Vue3也移除了 分全局、局部过滤器 特点:filters属性 配置的方法默认第一个参数就是 过滤前的值,过滤器可以按顺序多个执行。 过滤器不会改变原始值。

# 创建

局部过滤器:

// 配置项的方式注册
new Vue({
  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

全局过滤器:

// 注册
Vue.filter('capitalize', function(value){
  // 处理逻辑,并返回处理后的值
});
// 可以注册多个, 名称可以用小驼峰方式
Vue.filter('formatId', function(value){
  // 处理逻辑,并返回处理后的值
});
1
2
3
4
5
6
7
8

# 使用

插值或者 v-bind 表达式中用管道符使用, 表达式 | 过滤器名称

<div v-bind:id="rawId | formatId">{{ name | capitalize }}</div>
1

# 17 Vue内置指令

# v-bind

动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。 在绑定 class 或 style attribute 时,支持其它类型的值,如数组或对象。 缩写: :

# v-on

绑定事件监听器。有多个事件修饰符。 缩写:@

# v-model

跟表单结合使用,双向绑定。 可用修饰符:

# v-if

当和 v-if 一起使用时,v-for 的优先级比 v-if 更高。

# v-show

根据表达式之真假值,切换元素的 display CSS property。

# v-for

# v-text

将值全部替换该元素所有的内容,不同于插值语法只改变插值部分。

# v-html

v-text一样全部替换,但是可以解析标签,同 reactdangerouslySetInnerHTML,有风险,必须确保这个内容是无害的才用。

# v-cloak

结合 css 属性选择器,防止出现未经解析的模板出现在页面上。

# v-once

绑定的节点就渲染一次,然后就不改了。

# v-pre

vue会跳过绑定了v-pre的节点,加快编译速度。 一般不用,优化时考虑。

# v-slot

插槽指令后续单独列出

# 18 自定义指令

在实例的配置项中设置:directives

自定义指令使用函数方式的调用时机:1.模板初次解析的时候;2.指令所在模板再次被解析时; 解析并非渲染到页面上,所以一些 dom 操作会有点小问题,如想操作 元素放入(挂载到)页面后的操作: 聚焦、找父元素等。 解决方法是,不用函数方式,改为详细写法:

new Vue({
  //...
  directives:{
    fun(element, binding){
      // 执行时机:1.模板初次解析的时候;2.指令所在模板再次被解析时;
    },
    'fun-directive': function(){
      // 不能写成 funDirective(){}
    },
    'custom-directive': {
      bind(element, binding){
        // 初次解析时执行
      },
      inserted(element, binding){
        // 渲染到页面时执行
      },
      update(element, binding){
        // 指令所在模板再次被解析时执行
      }
    }
  },
  //...
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

注意点:自定义的指令不能出现小驼峰写法——aaBbCc,改为 字符串形式即可。

# 19 生命周期

pasted_image1746236866747.png

# 挂载阶段

# beforeCreated

此时,Vue才初始化生命周期、事件,还未进行数据检测和数据代理,无法通过 实例对象vm 访问到 data 数据和 methods 方法。

# created

此时,Vue已经初始化完成,进行了数据代理和数据监测,可以通过 实例对象 访问到data中的数据和methods中的方法。

# beforeMount

此时,页面呈现的是未经Vue编译的DOM结构,虚拟DOM还没替换真实DOM。

# mounted

同 react 的 componentMounted 作用一样。将虚拟dom第一次挂载到页面时执行的生命周期钩子。

# 更新阶段

# beforeUpdate

此时,数据已改变,但是页面上还是旧数据。

# updated

此时,数据和页面已同步。

# 卸载阶段

# beforeDestroy

此时,实例上的所有都还能用,同 react 的 componentWillUnmount 钩子一样。 此时即使更新了数据,页面也不会再重新渲染了,一般用来关闭定时器、取消订阅、解除自定义事件等操作。

# destroyed

此时,vm没了。一般这个钩子不用。

# 20 Vue组件的使用

分为三步:

  1. 定义组件 使用Vue.extentd(options)创建,其中配置项 options 几乎和 new Vue(options) 中的一样,但是有点区别: a. el 只能在 new Vue({}) 中写; b. 组件的data属性只能写成函数方式,避免在复用组件的时候存在引用关系。
  2. 注册组件(局部、全局) 局部注册:在new Vue(options) 中,使用 配置项 components。 全局注册:直接 Vue.component('组件名', 组件)。
  3. 使用组件(组件标签) 页面上编写组件标签

注意点: 1.组件命名格式:如果是单个词,字母大写小写开头都可以,如果是多个词,建议使用 大驼峰命名方式,但这种只有在脚手架里面能用,html中就只有写成 "aaa-bbb-ccc": 组件 形式。 2.使用组件后(页面上写了标签),Vue会自动生成 VueComponent 实例对象——组件实例对象。 组件实例对象和Vue实例对象几乎一样,该有的都有。 3.VueComponent.prototype.__proto__ === Vue.prototype 组件实例对象的原型对象的原型对象与vm原型对象是一致的。Vue做的特殊处理,这么做的目的是只要是在 vm原型上增加的属性,所有其子组件的对象都能访问到。

# 21 ref

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

<!-- `vm.$refs.p` will be the DOM node -->  
<p ref="p">hello</p>  
  
<!-- `vm.$refs.child` will be the child component instance -->  
<child-component ref="child"></child-component>
1
2
3
4
5

当 v-for 用于元素或组件的时候,引用信息将是包含 DOM 节点或组件实例的数组。

关于 ref 注册时间的重要说明:因为 ref 本身是作为渲染结果被创建的,在初始渲染的时候你不能访问它们 - 它们还不存在!$refs 也不是响应式的,因此你不应该试图用它在模板中做数据绑定。

# 22 props

类似 react 中的 props , 不过在Vue中是通过配置项获取。

export default{
  props: {},
}
1
2
3

props 可以是数组或对象,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。

// 简单语法  
Vue.component('props-demo-simple', {  
props: ['size', 'myMessage']  
})  
  
// 对象语法,提供验证  
Vue.component('props-demo-advanced', {  
	props: {  
		// 检测类型  
		height: Number,  
		// 检测类型 + 其他验证  
		age: {  
			type: Number,  // 类型检测,可以简单写如上
			default: 0,  // 为该 prop 指定一个默认值。如果该 prop 没有被传入,则换做用这个值。
			required: true,  // 定义该 prop 是否是必填项。
			validator: function (value) {  
				return value >= 0  
			} // 自定义验证函数会将该 prop 的值作为唯一的参数代入。在非生产环境下,如果该函数返回一个 falsy 的值 (也就是验证失败),一个控制台警告将会被抛出。
		}  
	}  
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 组件传值

组件传值,默认是字符串,可以使用 v-bind 绑定数据传,需要注意的是:如果要传数字、布尔值、数组、对象,必须使用 v-bind

<!-- 即便 `42` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->  
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->  
<blog-post v-bind:likes="42"></blog-post>

<!-- 即便 `false` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue --> <blog-post v-bind:is-published="false"></blog-post>

<!-- 即便数组是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->  
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>

<!-- 即便对象是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->  
<blog-post  
	v-bind:author="{  
		name: 'Veronica',  
		company: 'Veridian Dynamics'  
	}"  
></blog-post>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 传入一个对象的所有 property

如果你想要将一个对象的所有 property 都作为 prop 传入,你可以使用不带参数的 v-bind (取代 v-bind:prop-name)。

下面的模板:

<blog-post v-bind="post"></blog-post>
1

等价于:

<blog-post  
  v-bind:id="post.id"  
  v-bind:title="post.title"  
></blog-post>
1
2
3
4

# 23 混入 mixin

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

参考混入 — Vue.js (opens new window) 注意点: 1.同名data属性以使用者为准进行合并; 2.同名钩子函数会合并成一个数组,都会被调用,混入对象的钩子函数先执行。 3.值为对象的选项,例如 methodscomponents 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件混入对象的键值对。

# 24 Vue中的插件

参考 插件 — Vue.js (opens new window)

# 插件的作用:

  1. 添加全局方法或者 property
  2. 添加全局资源,如 指令、过滤器等。
  3. 通过全局混入来添加一些组件选项,如 vue-router
  4. 添加 Vue 实例方法,通过添加到 Vue.propotype上实现。

# 使用插件

main.js 中用 Vue.use() 使用插件。

// 调用 `MyPlugin.install(Vue)`  
Vue.use(MyPlugin)  
  
new Vue({  
// ...组件选项  
})
1
2
3
4
5
6

也可以传入一个可选的选项对象:

Vue.use(MyPlugin, { someOption: true })
1

Vue.use 会自动阻止多次注册相同插件,届时即使多次调用也只会注册一次该插件。

Vue.js 官方提供的一些插件 (例如 vue-router) 在检测到 Vue 是可访问的全局变量时会自动调用 Vue.use()。然而在像 CommonJS 这样的模块环境中,你应该始终显式地调用 Vue.use()

// 用 Browserify 或 webpack 提供的 CommonJS 模块环境时  
var Vue = require('vue')  
var VueRouter = require('vue-router')  
  
// 不要忘了调用此方法  
Vue.use(VueRouter)
1
2
3
4
5
6

# 开发插件

Vue的插件必须暴露一个 install 方法,此方法接收两个参数,一个是 Vue 构造器,一个是可选的选项对象。

export default {
   install(Vue, options) {
     Vue.directive("my-directive", {
       bind(element, binding){
        // 初次解析时执行
        },
        inserted(element, binding){
          // 渲染到页面时执行
        },
        update(element, binding){
          // 指令所在模板再次被解析时执行
        }
     });

     Vue.filter('myFilter', function(value){
	   // 处理逻辑,并返回处理后的值
	 })
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 25 scoped样式

防止样式冲突,在 style 标签中添加属性 scoped

<style scoped>
</style>
1
2

pasted_image1746780823520.png

# 26 组件通信

# 父子之间通信

# props

父传子: props 子传父:父先传一个函数给子,子想传数据时通过调用传过来的函数给父传值。

# 自定义事件

通过自定义事件可以用于子->父传值。 1.父组件定义自定义事件给子组件 myEvent,并定义好接收数据的函数 handleMyEvent

<ChildComponent v-on:myEvent="handleMyEvent" />
1

2.子组件在合适时机调用组件传过来的事件

<button @click="handleClick">给父组件传值</button>

<script>
  export default {
    name: "ChildComponent",
    methods: {
      handleClick(){
        this.$emit("myEvent", "hello my ParentComponent")
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12

# 兄弟之间、跨层级之间通信

# 1.全局事件总线

1.注册全局事件总线

new Vue({
  render: h => h(App),
  beforeCreated: {
    Vue.propotype.$bus = this;
  }
}).$mount('#app')
1
2
3
4
5
6

2.使用

// 组件接受数据
export default {
  // ...
  menthods: {
    reciveCallback(value,...params){
      //...
    }
  },
  mounted() {
	this.$bus.$on("event-name", reciveCallback);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 2.消息发布与订阅

# 26 $nextTick

下一轮渲染时进行操作。

# 27 Vue中的动画与过渡

  1. css 定义 动画
@keyframes test {
  0%: {}
  100%: {}
}
// 或者
@keyframes test {
  from: {
    transfrom: translateX(100%)
  }
  to: {
    transfrom: translateX(0%)
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  1. 要动画效果的标签用 <transition></transition> 标签包裹。
<transition>
  <h1 v-show="isShow">动画区域</h1>
</transition>
1
2
3

这样做了后,Vue 会给 transition包裹的 h1 标签添加 几个类:

  • v-enter-active 进入时的动画

  • v-enter 进入的起点(很快就消失)

  • v-enter-to 进入的终点

  • v-leave-active 离开时的动画

  • v-leave 离开时的起点 (很快就消失)

  • v-leave-to 离开时的终点

如果一个组件里面有多个动画或者过渡,则在 transition 标签属性上添加 name 属性,添加后 Vue 给标签添加的类则不是 v- 开头的类,而是以 name 值开头的。 想要动画一上来就运行,则在 transition 上添加 appear 属性即可。

  1. 使用
<transition name="test" appear >
  <h1 v-show="isShow">动画区域</h1>
</transition>

<style>
@keyframes test {
  from: {
    transfrom: translateX(100%)
  }
  to: {
    transfrom: translateX(0%)
  }
}
/* 注意这里不再是 v-enter-from 而是 transition 的 name开头 */
.test-enter-active {
  animation: test 1s;
}
.test-leave-active {
  animation: test 1s reverse;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

或者不用定义动画,使用过渡效果

<transition name="test" appear >
  <h1 v-show="isShow">动画区域</h1>
</transition>

<style>

/* 进入时的起点、离开时的终点 */
.test-enter, .test-leave-to {
  transition: translateX(-100%);
}
/* 进入时的终点、离开时的起点 */
.test-leave, .test-enter-to {
  transition: translateX(0%);
}
/* 给附上动画,或者不写下面这个样式,改为 给 h1 标签添加样式也许 */
.test-enter-active, .test-leave-active {
  transition: 1s linear;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  1. 注意点
    1. transition 只能给一个标签元素使用,要给多个元素使用,需要用 transition-group 进行包裹;
    1. transition-group 包裹的元素必须要有 key 值。

# 插槽 slot

插槽的作用:让父组件可以向子组件指定位置插入html结构,也是父子组件通信方式之一。 (挖个坑,等使用者填充。组件的children内容)

# 默认插槽

组件A中直接用 slot 标签创建插槽。

<template>
  <div>
    <slot>当没有传递内容时,我显示出来</slot>
  </div>
</template>
1
2
3
4
5

<slot></slot> 标签内的内容官方称之为: 后备内容 (opens new window)

使用组件A的组件B:

<template>
  <A>
    <!-- 以下内容填充到 A组件的插槽里面 -->
    <h1>我是组件B给你的插槽内容</h1>
  </A>
</template>
1
2
3
4
5
6

# 具名插槽

插槽有名字,可以放置多个插槽。

<template>
  <div>
    <slot name="first">当没有传递内容时,我显示出来</slot>
    <slot name="second">当没有传递内容时,我显示出来</slot>
  </div>
</template>
1
2
3
4
5
6

使用组件的组件:

<template>
  <A>
    <!-- 以下内容填充到 A组件的 first插槽 里面 -->
    <h1 slot="first">我是组件B给你的first插槽内容</h1>
    <!-- 以下内容填充到 A组件的 second插槽 里面 -->
    <div slot="first">
      <span>我是组件B给你的second插槽内容</span>
    </div>
  </A>
</template>
1
2
3
4
5
6
7
8
9
10

官方文档现在推荐使用 v-slot (opens new window) 。可以简写成 # 仅限用于:template 包裹的内容,所以官方推荐使用插槽时使用 template

<template>
  <A>
    <!-- 以下内容填充到 A组件的 first插槽 里面 -->
    <template v-slot:first>
      <h1 slot="first">我是组件B给你的first插槽内容</h1>
    </template>
    
    <!-- 以下内容填充到 A组件的 second插槽 里面
     并且可以接收 prop 的具名插槽, slotProps是vm上的数据
	 -->
    <template #:second="slotProps">
      <div class="xxx">
        <span>我是组件B给你的second插槽内容</span>
      </div>      
    </template>
  </A>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 作用域插槽

数据不在使用者这边,而在插槽创建者那边,插入的结构还是由使用者决定。 组件A创建默认插槽,定义了数据 adata 给插槽:

<template>
  <div>
    <slot :adata="adata">当没有传递内容时,我显示出来</slot>
  </div>
</template>

<script>
  export default {
    name: "A",
    data() {
      return {
        adata: ["1","2","3","4"],
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

组件B使用组件A,并且传入插槽内容:

<template>
  <A slot-scope="slotData">
    <ul>
      <li v-for="(item, index) in slotData.adata" :key="index" >{{item}}</li>
    </ul>
  </A>
</template>
1
2
3
4
5
6
7

B组件使用A组件时,获取到A组件插槽传递过来的插槽数据,slotData 包含的是: {adata:["1","2","3","4"]},很明显可以有多个数据。

官方说明:在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除

Last Updated: 7/8/2025, 12:54:02 AM