vue第八单元(组件通信 子父,父子组件通信 自定义事件 事件修饰符 v-model props验证 )

时间:2021-04-23 18:47:54

第八单元(组件通信 子父,父子组件通信 自定义事件 事件修饰符 v-model props验证 )

#课程目标

  1. 掌握使用props让父组件给子组件传参(重点)

  2. 掌握props属性的使用以及prop验证的常用规则

  3. 掌握使用自定义事件让子组件给父组件传参(重点)

  4. 了解v-model在组件中的绑定原理,掌握组件的v-model的绑定

  5. 熟悉常用的表单修饰符、事件修饰符、键盘修饰符

#知识点

#1.组件间的通信方式

#1.1父组件给子组件传递数据--使用props属性

​ 在父组件中动态绑定自定义的props属性来传递的数据,Parent.vue如下:

<template>
<div>
Parent
<br />
<Children :pmsg='msg'></Children>
</div>
</template>
<script>
import Children from './Children'
export default {
name: 'Parent',
data () {
return {
msg:'我是父组件的数据'
}
},
components:{
Children
}
}
</script>


​ 代码所示中的:pmsg(:是vue指令v-bind的缩写)则是绑定的自定义props属性名称,msg则是父组件想要给子组件传递的数据

​ 在子组件中使用 props 选项去接收来自父组件传递过来的数据 ,Children.vue示例代码如下:

<template>
<div>
Children
<br />
{{pmsg}}
</div>
</template> <script>
export default {
name: 'Children',
//通过props来去接收父组件传递的值
props:['pmsg'],
data () {
return { }
}
}
</script>
 

​ 代码中要使用父亲传过来的参数,首先要在props中先定义父亲传过来的props属性名称,然后就可以在页面中使用父亲传过来的数据了,在此案例中,pmsg就是父组件的传到子组件中的数据了。

​ 注意,由于HTML特性是不区分大小写的,所以传递属性值时,如果想传递驼峰参数,pMsg应该转换成 kebab-case (短横线隔开式):p-msg='msg'。如:

//父组件传值时  想要传pMsg  应该这样写
<Children :p-msg='msg'></Children>
//子组件接收的是驼峰
props:['pMsg']
 

关于props

  • 可以使用v­-bind动态绑定父组件来的内容
  • 在组件中使用props来从父组件接收参数,注意,在props中定义的属性,都可以在子组件中直接使用
  • props来自父级,而组件中data return的数据就是组件自己的数据,两种情况作用域就是组件本身,可以在template,computed,methods中直接使用
  • props的值有两种,一种是字符串数组,一种是对象
  • 对于数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态(尽可能将父子组件解耦,避免子组件无意中修改了父组件的状态)
#1.2 Prop验证

​ 我们可以给组件的props属性添加验证,当传入的数据不符合要求时,Vue会发出警告。

    props: {
// 基础类型检测 (`null` 意思是任何类型都可以)
propA: Number,
// 多种类型
propB: [String, Number],
// 必传且是字符串
propC: {
type: String,
required: true
},
// 数字,有默认值
propD: {
type: Number,
default: 100
},
// 数组/对象的默认值应当由一个工厂函数返回
propE: {
type: Object,
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
return value > 10
}
}
}
 

type 可以是下面原生构造器:

  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
  • Symbol

​ type 也可以是一个自定义构造器函数,使用 instanceof 检测。

<template>
<div>
<div>名字: {{ person-prop.name }}, 年龄: {{ person-prop.age }} </div>
</div>
</template>
<script>
// 自定义Person构造器 这个可以定义在外边引进来,这里只是方便教材描写演示
function Person(name, age) {
this.name = name
this.age = age
}
export default {
name: 'Children',
//通过props来去接收父组件传递的值
//如果传过来的不是Person类型会报错,比如:1,'str',等等的其他类型...
props: {
person-prop: {
type: Person // 指定类型
}
},
data () {
return { }
}
}
</script>
 
#1.3 子组件给父组件传递数据--使用自定义事件

​ 父组件使用props传递数据给子组件,子组件怎么跟父组件通信呢?这时,Vue的自定义事件就派上用场了。接下来我们将学习Vue自定义事件。

​ 每个 Vue 实例都实现了事件接口 (Events interface),即:使用 $on(eventName) 监听事件、 使用 $emit(eventName) 触发事件。

父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。

也就是说:子组件用 $emit() 来触发事件 ,父组件用 v-on来 监听子组件的事件 。

注意:不能用 $on 侦听子组件抛出的事件,而必须在模板里直接用 v-on 绑定。

第一步:在子组件中触发$emit自定义事件。(第一个参数是事件名,后边的参数是要传递的数据 )

//smsg 是自定义事件的名称
//和原生的click,change,keyup等等类似
//上面几个分别是 点击事件的名称、数据变动事件的名称、键盘抬起事件的名称
//data是想要传递的数据
this.$emit('smsg',data)
 

第二步:在父组件中监听自定义事件中来接收子组件的参数

//监听原生的click事件  是@click
//那么监听自定义事件 也是如此 @smsg
//getMsg是函数
//这个函数中如果有值的传递,必须传递$event参数 $event就是子组件中传递过来的data
//所以可以有两种方式写
<Children @smsg="getMsg"></Children>
//或者
<Children @smsg="getMsg($event)"></Children>
 

子组件Children.vue具体代码:

<template>
<div class="cc">
Children
<br />
<button @click="clickMe">点击我</button>
</div>
</template>
<script>
export default {
name: 'Children',
data () {
return {
msg:'我是子组件的数据'
}
},
methods:{
clickMe(){
//子组件中先触发这个emit事件
this.$emit('smsg',this.msg);
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.cc{
height: 100px;
background-color: red;
}
</style>
 

父组件Parent.vue具体代码:

<template>
<div class="pp">
Parent--{{msg}}
<br />
<Children @smsg="getMsg"></Children>
<!--也可以这样写-->
<!--<Children @smsg="getMsg($event)"></Children>-->
</div>
</template>
<script>
import Children from './Children'
export default {
name: 'Parent',
data () {
return {
msg:'我是没有改变之前的数据'
}
},
methods:{
//this.$emit('smsg',this.msg);
//data这个参数 指的就是子组件中 this.msg
getMsg(data){
//console.log(msg)
this.msg = data;
}
},
components:{
Children
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.pp{
height: 500px;
background-color: pink;
}
</style>
 
#1.4 在组件中使用 v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。

我们可以使用v-model来去绑定组件,试试怎么实现组件间的传值。

首先我们得知道v-model的绑定原理:

//正常表单绑定v-model
//data中的msg会随着input中的值变化而变化 也就是双向绑定
<input type="text" v-model="msg" /> //不使用v-model完成数据的双向绑定
<input type="text" @input="msg=$event.target.value" :value="msg" />
 

​ 通过上述的代码,我们已经明白了v-model的绑定原理,那么如果我们想给一个子组件上的input与父组件的某个数据做一个双向数据绑定,我们该怎么做呢?(Children组件,假定这个组件有一个input元素)

//如果这样绑定这个v-model指令
<Children v-model="msg"></Children> //根据之前的原理剖析,上面这个代码可以转换成:
<Children @input="msg=$event.target.value" :value="msg"></Children>
 

思考:这么写对不对呢?

我们再看子组件Children.vue中的部分代码:

<template>
<div>
//如果想要作为双向绑定,那么子组件中的值就应该往父组件中传,这里就要用到$emit去自定义事件
//因为父组件是使用input来监听,那么我们就应该使用自定义'input'的事件触发 这里是和原生input同名而已
//并把当前value值传给父组件
<input type="text" @input="$emit('input',$event.target.value)" :value="value" />
</div>
</template> //既然父组件传了prop名为value的的值,那么props中应该定义一个value
props:['value']
 

写到这里我们打开浏览器会发现,我们并没有实现双向绑定,为什么呢?

我们再回顾一下,在讲父组件监听自定义事件的时候,说过参数$event就是子组件传回来的参数。

那么,在父组件中,我们应该改为:

<Children @input="msg=$event" :value="msg"></Children>
 

到此为止,我们就实现了父组件与子组件中表单元素的双向绑定

#2.修饰符

#2.1表单修饰符

(1).lazy

在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步。你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步。

如下,示例:

<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" />
 

(2).number

如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符。

如下,示例:

<input v-model.number="age" />
 

(3).trim

如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符。

如下,示例:

<input v-model.trim="msg" />
 
#2.2事件修饰符

在Vue中,事件修饰符处理了许多DOM事件的细节,让我们不再需要花大量的时间去处理这些烦恼的事情,而能有更多的精力专注于程序的逻辑处理。在Vue中事件修饰符主要有:

  • .stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡
  • .prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播)
  • .capture:与事件冒泡的方向相反,事件捕获由外到内
  • .self:只会触发自己范围内的事件,不包含子元素
  • .once:只会触发一次

.stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡

<div id="app">
  <div class="outeer" @click.stop="outer">
    <div class="middle" @click.stop="middle">
      <button @click.stop="inner">点击我</button>
    </div>
  </div>
</div>
 

.prevent取消默认事件

.prevent等同于JavaScript的event.preventDefault(),用于取消默认事件。

<!--不会跳转到另外一个页面-->
<a href="https://www.baidu.com" @click.prevent="clickMe"></a>
 

.capture 捕获事件

捕获事件:嵌套两三层父子关系,然后所有都有点击事件,点击子节点,就会触发从外至内 父节点 ==>子节点的点击事件

<div class="outeer" @click.capture="outer">
<div class="middle" @click.capture="middle">
<button @click.capture="inner">点击我</button>
</div>
</div>
 

.self

修饰符.self只会触发自己范围内的事件,不会包含子元素。

<div class="outeer" @click.self="outer">
<div class="middle" @click.self="middle">
<button @click.stop="inner">点击我</button>
</div>
</div>
 

.once 只执行一次点击

如果我们在@click事件上添加.once修饰符,只要点击按钮只会执行一次。

#2.3键盘修饰符

在JavaScript事件中除了前面所说的事件,还有键盘事件,也经常需要监测常见的键值。在Vue中允许v-on在监听键盘事件时添加关键修饰符。记住所有的keyCode比较困难,所以Vue为最常用的键盘事件提供了别名:

  • .enter:回车键
  • .tab:制表键
  • .delete:含deletebackspace
  • .esc:返回键
  • .space: 空格键
  • .up:向上键
  • .down:向下键
  • .left:向左键
  • .right:向右键

#授课思路

vue第八单元(组件通信 子父,父子组件通信 自定义事件 事件修饰符 v-model props验证 )

#案例和作业

使用组件方式实现弹窗

vue第八单元(组件通信 子父,父子组件通信 自定义事件 事件修饰符 v-model props验证 )