组件组成部分
scoped
组件的 style 样式,默认会作用于全局,加上 scoped
属性的 style 样式,只会作用于当前组件
scoped 原理:
- 给当前组件内所有标签添加
data-v-hash值
的自定义属性- 当前组件的 style 样式的 css 选择器会自动添加属性选择器
data
一个组件的 data 选项必须是一个函数,保证每个组件实例维护独立的一份数据对象,每次创建新的组件实例,都会新执行一次 data 函数,得到一个新对象,示例代码如下:
<template>
<div class="base-count">
<button @click="count--">-</button>
<span>{{ count }}</span>
<button @click="count++">+</button>
</div>
</template>
<script>
export default {
data: function () {
return {
count: 100,
}
},
// 简写
// data() {
// console.log('函数执行了')
// return {
// count: 100,
// }
// },
}
</script>
组件通信
父子关系
- 父组件通过
props
将数据传递给子组件 - 子组件通过
$emit
通知父组件修改更新
父传子
父组件代码:
<template>
<div class="app" style="border: 3px solid #000; margin: 10px">
我是APP组件
<!-- 1.给组件标签添加自定义属性 -->
<Son :title="myTitle"></Son>
</div>
</template>
<script>
import Son from './components/Son.vue'
export default {
name: 'App',
data() {
return {
myTitle: '程序员校花',
}
},
components: {
Son,
},
}
</script>
子组件代码:
<template>
<div class="son" style="border:3px solid #000;margin:10px">
<!-- 3.直接使用 props 的值 -->
我是Son组件 {{title}}
</div>
</template>
<script>
export default {
name: 'Son-Child',
// 2.通过 props 来接受
props:[' title ']
}
</script>
子传父
父组件代码:
<template>
<div class="app" style="border: 3px solid #000; margin: 10px">
我是APP组件
<!-- 2.父组件对子组件的消息进行监听 -->
<Son :title="myTitle" @changTitle="handleChange"></Son>
</div>
</template>
<script>
import Son from './components/Son.vue'
export default {
name: 'App',
data() {
return {
myTitle: '程序员校花',
}
},
components: {
Son,
},
methods: {
// 3.提供处理函数,提供逻辑
handleChange(newTitle) {
console.log(newTitle) // 校花好美
this.myTitle = newTitle
},
},
}
</script>
子组件代码:
<template>
<div class="son" style="border: 3px solid #000; margin: 10px">
我是Son组件 {{ title }}
<button @click="changeFn">修改title</button>
</div>
</template>
<script>
export default {
name: 'Son-Child',
props: ['title'],
methods: {
changeFn() {
// 1. 通过 this.$emit() 向父组件发送通知
this.$emit('changTitle','校花好美')
},
},
}
</script>
props
- 定义:组件上注册的一些自定义属性(自定义属性指的是 vue 组件标签,而不是 HTML 标签)
- 作用:向子组件传递数据
- 特点:可以传递任意数量、任意类型的 props
校验
可以为组件的 props 指定验证要求,不符合要求,控制台就会有错误提示,可以进行:
- 类型校验
- 非空校验
- 默认值
- 自定义校验
示例代码如下:
props: {
校验的属性名: {
type: 类型, // Number String Boolean ...
required: true, // 是否必填
default: 默认值, // 默认值
validator(value) {
// 自定义校验逻辑
return 是否通过校验
}
}
},
VS method
- 共同点:都可以给组件提供数据
- 区别:
- data 的数据是自己的,随便改
- props 的数据是外部的,不能直接改
非父子关系(了解)
event bus 事件总线
作用:非父子组件之间,进行简易消息传递

使用步骤如下:
-
创建一个都能访问到的事件总线(空 Vue 实例 )
import Vue from 'vue' const Bus = new Vue() export default Bus
-
A 组件(接收方),监听 Bus 实例的事件
created () { Bus.$on('sendMsg', (msg) => { this.msg = msg }) }
-
B 组件(发送方),触发 Bus 实例的事件
Bus.$emit('sendMsg', '这是一个消息')
provide & inject
作用:跨层级共享数据

使用步骤如下:
-
父组件
provide
提供数据export default { provide () { return { // 普通类型【非响应式】 color: this.color, // 复杂类型【响应式】 userInfo: this.userInfo, } } }
-
其他组件使用
inject
取值使用export default { inject: ['color','userInfo'], created () { console.log(this.color, this.userInfo) } }
进阶语法
v-model
原理
- 原理:
v-model
本质上是一个语法糖。例如应用在输入框上,就是 value 属性和 input 事件的合写 - 作用:提供数据的双向绑定
- 数据变,视图跟着变
:value
- 视图变,数据跟着变
@input
- 数据变,视图跟着变
- 在模板中,
$event
用于获取事件的形参
示例代码如下:
<template>
<div class="app">
<input v-model="msg1" type="text"/>
<br />
<!-- v-model的底层其实就是:value和 @input的简写 -->
<input :value="msg2" @input="msg2 = $event.target.value" type="text"/>
</div>
</template>
<script>
export default {
data() {
return {
msg1: '',
msg2: '',
}
},
}
</script>
封装表单组件

封装表单类组件,实现子组件和父组件数据的双向绑定:
- 父传子:数据由父组件的
props
传递过来的,拆解 v-model 绑定数据 - 子传父:监听输入,子传父传值给父组件修改
表单子组件代码如下:
<template>
<div>
<select :value="cityId" @change="selectCity">
<option value="101">北京</option>
<option value="102">上海</option>
<option value="103">武汉</option>
<option value="104">广州</option>
<option value="105">深圳</option>
</select>
</div>
</template>
<script>
export default {
props: {
cityId: String,
},
methods: {
selectCity(e) {
this.$emit('changeId', e.target.value)
},
},
}
</script>
父组件代码如下:
<template>
<div class="app">
<BaseSelect
:cityId="selectId"
@changeId="selectId = $event"
></BaseSelect>
</div>
</template>
<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
data() {
return {
selectId: '103',
}
},
components: {
BaseSelect,
}
}
</script>
v-model 简化
- 上面封装表单组件中不能直接使用
v-modal
,因为数据是父组件的不能直接修改 - 但是可以在父组件中简化代码,步骤如下:
- 子组件中:
props
通过value
接收,事件触发input
- 父组件中:
v-model
给组件直接绑数据
- 子组件中:
因为 v-model
就等于 :value
+ @input
HTML 中
change
和input
事件的区别:
change
事件:在用户对表单元素进行修改并失去焦点后触发input
事件:用户对表单元素的输入进行修改时即时触发
表单子组件代码如下:
<template>
<div>
<select :value="value" @change="selectCity">
<option value="101">北京</option>
<option value="102">上海</option>
<option value="103">武汉</option>
<option value="104">广州</option>
<option value="105">深圳</option>
</select>
</div>
</template>
<script>
export default {
props: {
value: String,
},
methods: {
selectCity(e) {
this.$emit('input', e.target.value)
},
},
}
</script>
父组件代码如下:
<template>
<div class="app">
<BaseSelect
v-model="selectId"
></BaseSelect>
</div>
</template>
<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
data() {
return {
selectId: '102',
}
},
components: {
BaseSelect,
},
}
</script>
sync 修饰符
- 作用:可以实现子组件与父组件数据 的 双向绑定,简化代码
- 特点:
props
属性名可以自定义,不用写死为value
- 场景:封装弹框类的基础组件,
visible
属性 true 显示 false 隐藏 - 本质:
:属性名
和@update:属性名
的合写 @update
为 vue 的自定义事件,用于父子组件之间的通信

父组件代码如下:
<template>
<div class="app">
<button @click="openDialog">退出按钮</button>
<!-- :visible.sync === :visible="isShow" + @update:visible="isShow=$event" -->
<BaseDialog :visible.sync="isShow"></BaseDialog>
</div>
</template>
<script>
import BaseDialog from './components/BaseDialog.vue'
export default {
data() {
return {
isShow: false,
}
},
methods: {
openDialog() {
this.isShow = true
},
},
components: {
BaseDialog,
},
}
</script>
子组件代码如下:
<template>
<div class="base-dialog-wrap" v-show="visible">
<div class="base-dialog">
<div class="title">
<h3>温馨提示:</h3>
<button class="close" @click="closeDialog">x</button>
</div>
<div class="content">
<p>你确认要退出本系统么?</p>
</div>
<div class="footer">
<button @click="closeDialog">确认</button>
<button @click="closeDialog">取消</button>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
visible: Boolean,
},
methods: {
closeDialog() {
this.$emit('update:visible', false)
}
}
}
</script>
ref 和 $refs
-
作用:使用
ref
和$refs
可以用于获取 dom 元素或组件实例 -
特点:查找范围是当前组件内,更精确稳定
-
语法如下:
-
获取 dom:
-
给目标标签添加
ref
属性<div ref="chartRef">我是渲染图表的容器</div>
-
在 dom 渲染后,通过
this.$refs.xxx
,获取目标标签mounted () { console.log(this.$refs.chartRef) },
-
-
获取组件:
-
给目标组件添加
ref
属性<BaseForm ref="baseForm"></BaseForm>
-
使用
this.$refs.xxx
,获取目标组件,就可以调用组件对象里面的方法this.$refs.baseForm.组件方法()
-
-
$nextTick
异步更新
需求:编辑标题,编辑框自动聚焦:
- 点击编辑,显示编辑框
- 让编辑框立刻获取焦点
this.isShowEdit = true // 显示输入框
this.$refs.inp.focus() // 获取焦点
- 问题:第一行代码执行后,DOM 还未更新完,此时获取焦点是不能成功的
- 原因:Vue 是异步更新 DOM ,目的是提升性能
$nextTick 解决异步更新
$nextTick
:等 DOM 更新后,才会触发执行此方法里的函数体,语法如下:
this.$nextTick(() => {
this.$refs.inp.focus()
})