组件三大组成部分

结构<template>

  • 只能有一个根元素

样式<style>

  • 全局样式(默认):影响所有组件
  • 局部样式:scoped 下样式,只作用于 当前组件

逻辑<script>

  • el 根实例独有, data 是一个函数, 其他配置项一致

组件样式冲突 scoped

默认情况:写在组件中的样式会 全局生效 ,因此很容易造成多个组件之间的样式冲突问题。

  1. 全局样式: 默认组件中的样式会作用到全局,任何一个组件中都会受到此样式的影响
  2. 局部样式: 可以给组件加上scoped 属性,可以让样式只作用于当前组件
1
2
<style scoped>
</style>

scoped原理

  1. 当前组件内标签都被添加data-v-hash值 的属性
  2. css选择器都被添加 [data-v-hash值] 的属性选择器

最终效果: 必须是当前组件的元素, 才会有这个自定义属性, 才会被这个样式作用到

image.png

data 是一个函数

一个组件的 data 选项必须是一个函数。目的是为了:保证每个组件实例,维护独立的一份数据对象。

每次创建新的组件实例,都会新执行一次data 函数,得到一个新对象。

组件通信

组件通信,就是指组件与组件之间的数据传递

  • 组件的数据是独立的,无法直接访问其他组件的数据。
  • 想使用其他组件的数据,就需要组件通信

通信解决方案

  • 父子关系:props & $emit
  • 非父子关系:provide & inject 、 eventbus
  • 通用解决方案:Vuex(适用于复杂业务场景)

父子通信

父 → 子

父组件通过 props 将数据传递给子组件

  1. 父组件给子组件以添加熟悉的方式传值
  2. 子组件内部通过 props 接收数据

1682318711785.png

子 → 父

子组件利用 $emit 通知父组件修改更新

  1. 子组件通过 $emit 触发事件,传递参数给父组件
  2. 父组件通过事件监听子组件,获取参数

1682318965635.png

prop 概念

Prop 定义:组件上 注册的一些 自定义属性

Prop 作用:向子组件传递数据

prop 特点

  • 可以传递 任意数量 的prop
  • 可以传递 任意类型 的prop

1682320156914.png

prop 校验

作用:为组件的 prop 指定验证要求,不符合要求,控制台就会有错误提示 → 帮助开发者,快速发现错误

语法

  • 类型校验
  • 非空校验
  • 默认值
  • 自定义校验

image.png

prop & data 、单向数据流

prop & data 共同点:都可以给组件提供数据

区别

  • data 的数据是自己的,可以随便改
  • prop 的数据是外部的,不能直接改,要遵循 单向数据流

单向数据流:父级props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的

子改父数据的步骤

  1. 在子组件添加触发事件,并用this.$emit()将数据传回给父组件
  2. 父组件需要在子组件添加事件监听,获取新数据并且赋值

非父子通信

event bus 事件总线

作用:非父子组件之间,进行简易的消息传递

步骤

  1. 创建一个都能够访问的事件总线 EventBus.js(空 Vue 实例)
1
2
3
import Vue from 'vue'
const Bus = new Vue()
export default Bus
  1. A组件(接受方),监听Bus.$on事件
1
2
3
4
5
created () {
Bus.$on('sendMsg', (msg) => {
this.msg = msg
})
}
  1. B组件(发送方),触发Bus.$emit事件
1
Bus.$emit('sendMsg', '这是一个消息')

provide & inject

作用:跨层级共享数据

父组件 provide 提供数据

1
2
3
4
5
6
7
8
9
10
export default {
provide () {
return {
// 普通类型非响应式
color: this.color,
// 复杂类型响应式(推荐)
userInfo: this.userInfo,
}
}
}

子/孙组件 inject 获取数据

1
2
3
4
5
6
export default {
inject: ['color','userInfo'],
created () {
console.log(this.color, this.userInfo)
}
}
  • provide提供的简单类型的数据不是响应式的,复杂类型数据是响应式。(推荐提供复杂类型数据)
  • 子/孙组件通过inject获取的数据,不能在自身组件内修改

进阶用法

v-model 原理

原理

v-model本质上是一个语法糖。例如应用在输入框上,就是 value属性 和 input事件 的合写

1
2
3
4
5
6
<template>
  <div id="app" >
    <input v-model="msg" type="text">
    <input :value="msg" @input="msg = $event.target.value" type="text">
  </div>
</template>

作用

提供数据的双向绑定

  • 数据变,视图跟着变 :value
  • 视图变,数据跟着变 @input

注意$event 用于在模板中,获取事件的形参

表单类组件封装

表单类组件封装:实现子组件和父组件的双向绑定

  1. 父传子:数据应该是父组件 props 传递过来,拆解 v-model 绑定数据
  2. 子传父:监听输入,子传父传值给父组件修改

image.png

v-model 简化代码

v-model其实就是:value@input事件的简写

  • 子组件:props通过value接收数据,事件触发 input
  • 父组件:v-model直接绑定数据 (:value + @input

image.png

.sync 修饰符

作用:可以实现子组件与父组件数据的双向绑定,简化代码

特点:prop属性名,可以自定义,非固定的value

本质:就是 :属性名@update:属性名 合写

image.png

ref 和 $refs

作用: 利用 ref 和 $refs 可以用于获取DOM元素组件实例

特点:查找范围是当前组件内,更精确稳定

获取DOM

  1. 目标标签 - 添加 ref 属性
1
<div ref="logoRef">logo</div>
  1. 通过this.$refs.xxx,获取目标标签
1
2
3
4
mounted() {
// 需要在目标标签被渲染出来之后,才可以获取
console.log(this.$refs.logoRef)
}

获取组件

  1. 目标组件 - 添加 ref 属性
1
<BaseForm ref="baseForm"></BaseForm>
  1. 通过this.$refs.xxx,获取目标组件,里面可以调用对象里面的方法
1
this.$refs.baseForm.组件方法()

Vue 异步更新、$nextTick

当我们需要渲染组件后立刻操作内容的话,可能会无法实现

原因:Vue 是异步更新 DOM,目的是提高性能

$nextTick:等DOM更新完成后,才会触发执行此行方法里的函数体

1
2
3
this.$nextTick(() => {
this.$refs.inp.focus() // 用于实现现实输入框后聚焦输入框
})