目录
一、组件的三大组成部分
二、组件的样式冲突scoped
三、scoped原理
编辑 四、data是一个函数
五、组件通信
六、props详解
七、非父子通信
1.eventbus事件总线(可以一传多)--->作用是在非父子组件之间,进行简易的消息传递(复杂场景--->vuex)
2.provide和inject
八、.sync修饰符
九、ref和refs
十、vue异步更新和$nextTick
十一、自定义指令
一、组件的三大组成部分
结构<template>---vue2只能有一个根元素
样式<style>---默认是全局样式,影响所有组件;局部样式:scoped下的样式,只作用于当前组件
逻辑<script>---el是根实例所独有的,data是一个函数,其他配置项不变
二、组件的样式冲突scoped
默认情况:写在组件中样式会全局生效---因此很容易造成多个组件之间的样式冲突问题
全局样式:默认组件中的样式会作用到全局
局部样式:可以给组件加上scoped属性可以让样式只作用于当前组件
三、scoped原理
给当前组件模板的所有元素,都会添加上一个自定义属性data-v-hash值,可以利用hash值区分开不同的组件,CSS选择器后面被自动处理,添加了属性选择器div[data-v-hash值](必须是当前组件的元素,才会有这个自定义属性,才会被这个样式作用到---当前组件内的标签都会被添加data-v-hash值的属性)
<style lang="less" scoped>
.footer-container {
background-color: white;
height: 50px;
border-top: 1px solid #f8f8f8;
display: flex;
justify-content: flex-end;
align-items: center;
padding: 0 10px;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
z-index: 999;
}
</style>
四、data是一个函数
一个组件的data选项,必须是一个函数---保证每个组件实例维护独立的一份数据对象
data(){
return{
数据对象
}
五、组件通信
1.概念:是指组件与组件之间的数据传递,组件的数据是独立的,无法直接访问其他组件的数据,想用其他组件的数据就要用到组件通信。
2.组件关系分类:
父子关系---props和$emit
非父子关系---provide&inject和eventbus
3.父子通信流程图
父组件通过props将数据传递给子组件
子组件利用$emi通知父组件修改更新
- 父传子
- --->给子组件以添加属性的方式传值---->动态属性传值--->:属性名 = "表达式"
- --->子组件内部通过props接收--->数组接收多个传值---->props: ['属性名']
- --->模板中直接使用--->模板字符串{{}}渲染--->{{ 属性名 }}
- 子传父
- --->$emit触发事件,给父组件发送消息通知--->子组件监听事件--->this.$emit('事件名','内容')
- 父组件监听事件--->@事件名 = '父级监听事件'
- 提供处理函数,形参中获取参数--->this.属性名 = 形参
六、props详解
定义:子组件上注册的一些自定义属性
作用: 向子组件传递数据
特点: 可以传递任意数据,任意类型的prop
props校验: 为组件中的prop指定严正要求,不符合要求,控制台会有错误提示
props: {
校验的属性名: {
type:类型,--->Number,String,Object,Array,Function,Boolean,
required:true, //是否必填
default:默认值, //默认值和是否必填选择其一即可
vaildator(value){
// 自定义校验逻辑
return 是否通过校验
}
}
}
单向数据流
父组件的prop更新,会单向的向下流动影响到子组件从而影响到视图
prop和data单向数据流的特点:
- 共同点:都可以给组件提供数据
- 区别:data的数据是自己的,可以随意更改;prop的数据是外部的,不能直接更改,要遵循单向数据流的原则(谁的数据谁负责)
七、非父子通信
1.eventbus事件总线(可以一传多)--->作用是在非父子组件之间,进行简易的消息传递(复杂场景--->vuex)
步骤:
- 创建一个都能访问到的事件总线(空vue实例)---作为媒介
- 接收方的组件监听bus实例事件---$on('事件名')
- 发送方的组件触发bus实例事件---$emit('事件名')
2.provide和inject
作用:跨层级共享数据
步骤:
- 父组件provide提供数据---->provide () { return {数据} }
- 子孙组件inject取值使用---->inject: []
- 简单类型传递的非响应式,复杂类型传递的响应式数据
八、v-model原理
原理:v-model本质上是一个语法糖, 例如利用在输入框上就是value属性和input事件的合写(应用与不同的表单元素,设置的dom属性和绑定的事件稍有不同)
作用:提供数据的双向绑定
1.v-model:
- 数据变,视图跟着变---> :value
- 视图变,数据跟着变--->@input (监听事件,监听输入框的输入)
注意$emit用在模板中的时候,获取事件的形参,input和click事件的形参是e事件对象
在行内中想要拿到当前事件的形参(事件对象)---->$event.target
2.表单类组件封装和v-model简化代码
2.1表单类组件封装
- 父传子:数据应该是父组件props传递过来的,v-model拆解绑定数据
- 子传父:监听输入,子传父传值给父组件修改
e.target触发事件的事件源,$emit获取事件的形参,下拉菜单的绑定事件是change,因为数据不是子组件的,所以不能使用v-model直接修改,否则会报错
2.2父组件v-model简化代码,实现子组件和父组件数据的双向绑定
- 子组件中props通过value接收,事件触发$emit(value和input事件两者缺一不可)
- 父组件中:v-model给组件直接绑定数据
八、.sync修饰符
作用:可以实现子组件与父组件数据的双向绑定,简化代码
特点:prop属性名可以自定义,非固定为value
本质是 :属性名和@事件:属性名合写
:属性.sync === :属性+@事件:属性名
九、ref和refs
作用:利用ref和refs可以获取dom元素或者组件实例
特点:查找范围--->当前组件内(更加精确稳定)
querySelector的查找范围是整个页面(容易出现找错的情况)
例如:获取dom
步骤:
- 目标标签----添加ref属性
- 恰当时机mounted内部(操作dom的生命周期函数)通过this.ref.ref属性值来获取目标标签
<div ref="chartRef">我是渲染图表的容器</div>
mounted () { console.log(this.$refs.chartRef)}
十、vue异步更新和$nextTick
vue是异步更新dom以便于提升性能
$nextTick是等dom更新后,才会触发执行此方法里面的函数体
<template>
<div class="app">
<div v-if="isShowEdit">
<input type="text" v-model="editValue" ref="inp" />
<button>确认</button>
</div>
<div v-else>
<span>{{ title }}</span>
<button @click="editFn">编辑</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
title: '大标题',
isShowEdit: false,
editValue: '',
}
},
methods: {
editFn() {
// 显示输入框
this.isShowEdit = true
// 获取焦点
this.$refs.inp.focus()
} },
}
十一、自定义指令
内置指令:v-html,v-model,v-for...等
每个指令都有自己各自独立的功能,自定义指令可以封装一些dom操作,扩张额外的功能,比如说v-focus自动聚焦,v-loading控制加载,v-lazy图片懒加载...
1.自定义指令-注册的语法
全局注册的语法:
vue.directive('指令名',{
inserted(el){
//可以对el标签扩展额外的功能
el.focus
}
})
局部注册的语法:
directives: {
指令名: {
inserted(el) {
// 可以对el标签扩展额外的功能
el.focus
}
}
}
使用:v-指令名
2.自定义指令-指令的值
语法:在绑定指令时,可以通过"等号"的形式为指令绑定具体的参数值-----v-指令名 = "指令值"
通过binding、value可以拿到指令值,指令值修改会触发update函数
update指令的值修改时触发---提供的值变化后,dom更新的逻辑
十二、插槽
作用:让组件内部的一些结构支持自定义
1.默认插槽(组件内定制一处结构)
插槽的基本语法:
- 组件内需要定制的结构部分,改用<slot></slot>占位
- 使用组件时,<MyDialog>在这里传入结构替换slot</MyDialog>
<div class="box">
<slot> 也可以在这里输入默认的内容(也称为后备内容) </slot>
</div>
<MyDialog>
'输入内容,在这里输入可以替换slot整体;如果不输入内容则默认使用后备内容'
</MyDialog>
2.具名插槽(可以定义多处结构)
slot有了name属性之后就是具名插槽,通过template将其包裹成一个整体----分发结构
语法:
- 多个slot使用name属性区分名字----<slot name= "名字"> </slot>
- template配合v-slot:名字来分发对应标签(可以简写为#名字)
//第一种写法 <MyDialog> <template v-slot:名字></template> </MyDialog> //简写语法 <MyDialog> <template #名字></template> </MyDialog>
3.作用域插槽(插槽传参的语法)
定义:在定义slot插槽的同时,是可以传值的,给插槽上可以绑定数据,将来使用组件时可以用
语法:
- 给slot标签以添加属性的方式传值
- 所有被添加的属性都会被收集到一个对象之中
- 在template中通过 `#插槽名=obj`接收,默认插槽名为default,具名插槽则为`#具名插槽=obj`--obj是变量名可以自定义,也可以对obj进行结构