深入自定义事件和原生DOM事件($attr等)
深入自定义事件和原生DOM事件
自定义事件
在组件上标签上添加的事件就是自定义事件,不管系统是否带这些事件
比如添加
<自定义组件 @自定义事件 = "回调函数"></自定义组件>
那么@自定义事件
在自定义组件上就是自定义事件<自定义组件 @click = "回调函数"></自定义组件>
,那么@click
就是自定义事件添加的事件如果没有传入参数,那么输出就是undefined
- 如图,传入了参数,单击button,输出为10,如果没有传递参数10,则输出undefined
- 自定义组件上绑定原生DOM事件使用native和不使用的区别,如下图
- 如图
自定义事件示例
App.vue
1 | <template> |
自定义组件MyComponent
1 | <template> |
效果
原生DOM事件
在HTML标签上添加就是原生DOM事件,比如说
@click
@mousemove
这些系统自带的原生事件添加的事件如果没有传入参数,那么系统会默认传入event参数
1
2
3<button @click="test1">我是按钮1</button>
//等同于
<button @click="test1($event)">我是按钮2</button>
vue自定义的事件在html标签和组件标签上的区别
在html标签上添加自定义事件无意义,所以自定义事件是给组件标签添加的
事件名可以任意,也可以和原生DOM事件名相同,但是是自定义的
如果自定义事件上想绑定原生的事件,那么就需要在事件对象名称后面添加 .native 并且绑定的事件添加在添加到组件根元素上,通过委派的形式使得子元素可以被触发
如图
深入理解v-model
首先我们需要知道v-model在HTML标签上的原理
v-model原来写法
1
2// 标准v-model写法 普通写法
<input type="text" v-model="msg" />v-model拆解写法(等同于上方直接写v-model)
- 先使用v-bind绑定一个值给输入框,再添加事件@input,当触发就将当前触发对象的值传递给v-bind绑定的那个值,就这样子完成了数据更新
1
2// v-model拆解写法
<input type="text" :value="msg" @input="msg = $event.target.value"/>
那么v-model当中在自定义组件要怎么实现呢?
根据v-model在原生DOM上拆解的写法,我们应该这样子写( 以自定义组件CustomInput为例 )
需要知道的是: 在自定义组件当中,
$event
就是$emit
当中第二个参数传递过来的数据父组件
1
2
3
4
5
6<!--父亲给CustomInput传递 "msg2" 数据 -->
<!--儿子要使用props接收( props:["value"] ),并且传递了自定义事件input -->
<CustomInput :value="msg" @input="msg = $event"></CustomInput>
<!--上面这一行代码可以简写为下面这一行但是子组件不能简写-->
<!--必须要写下面这些内容!!!!!!!!!!!!!! -->
<CustomInput v-model="msg"></CustomInput>子组件 CustomInput.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<template>
<div>
<input type="text"
// 绑定从父亲传递过来的参数
:value = "value"
// 绑定原生DOM事件@input,输入框内容发生改变,就将改变的值作为$emit的第二个参数
// 并通过$emit触发父亲给子组件的自定义事件input
@input="$emit('input',$event.target.value)"/>
</div>
</template>
<script>
export default {
name: "CustomInput",
// 接收从父亲传递过来的:value="msg"的值
// 如果是简写形式(<CustomInput v-model="msg"></CustomInput>)也是从value接收
props:["value"]
}
</script>
.sync修饰符实现父子数据同步和.sync和v-model的区别
1 | [需求] |
第一次(无效果) (直接传递数据给儿子, 儿子每次单击都花100块钱)
父亲 (直接传递数据给儿子)
1
2<!-- 会弹出警告说数据不同步 -->
<Child :money="moneyFather"></Child>弹出警告
儿子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<template>
<span>小明每次花100元</span>
<!-- 每次单击爸爸的钱就减少100 -->
<button @click="money = money - 100">单击我花钱</button>
<!-- 显示爸爸剩余多少钱 -->
爸爸还剩 {{ money }} 元
</template>
<script>
export default {
name:"Child",
//接收父亲传递过来的信息,告诉了我现在父亲有多少钱
props:["money"]
}
</script>
结果
- 儿子花钱按钮被单击,儿子当中的父亲的钱数量被改变,但是父亲兜兜里面的钱没有变化
第二次(有效果) 数据传递给儿子,但是儿子每次单击花钱的时候就告诉父亲我花钱了
父亲 (
$event
在自定义组件当中是$emit
传递的参数 父亲收到儿子传递过来的金钱数,就更新自己的金钱数)1
2
3
4
5<!-- $event在自定义组件当中是$emit传递的参数 -->
<!-- @update:xxx为固定格式,不可以更改,xxx为绑定的数据属性也就是v-bind:xxx="值"(当中的xxx)
对应简写属性 :xxx="值" 当中的xxx
-->
<Child :money="moneyFather" @update:money="moneyFather = $event"></Child>儿子每次单击爸爸的钱就减少100 并且告诉爸爸 (通过
$emit
),并且传递 金钱-100的 值 给父亲1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<template>
<div style="background: #ccc; height: 50px">
<span>小明每次花100元</span>
<!-- 每次单击爸爸的钱少100 并且告诉爸爸 $emit,并且传递 金钱-100的值 给父亲-->
<!-- update:money 为自定义事件名称 -->
<button @click="$emit('update:money', money - 100)">花钱</button>
<!-- 显示爸爸剩余多少钱 -->
爸爸还剩 {{ money }} 元
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: "Child",
// 接收父亲传递过来的信息,告诉了我现在父亲有多少钱
props: ["money"],
};
</script>
第三次(有效果)等同于第二次简写
父亲 (使用sync修饰符)
1
2
3
<Child :money.sync="moneyFather"></Child>儿子 (和第二次一样) 每次单击爸爸的钱就减少100 并且告诉爸爸 (通过
$emit
),并且传递 金钱-100的 值 给父亲1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<template>
<div style="background: #ccc; height: 50px">
<span>小明每次花100元</span>
<!-- 每次单击爸爸的钱少100 并且告诉爸爸 $emit,并且传递 金钱-100的值 给父亲-->
<!-- update:money 为自定义事件名称 -->
<button @click="$emit('update:money', money - 100)">花钱</button>
<!-- 显示爸爸剩余多少钱 -->
爸爸还剩 {{ money }} 元
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: "Child",
// 接收父亲传递过来的信息,告诉了我现在父亲有多少钱
props: ["money"],
};
</script>
v-model的使用在数据同步的使用
父亲依旧是通过
:value
向子传递$event
依旧是子通过$emit
传递过来的数据- 自定义组件
$event
返回的都是$emit
传递过来的数据)
1
<Child :value="moneyFather" @input="moneyFather = $event"></Child>
- 自定义组件
儿子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<template>
<div style="background: #ccc; height: 50px">
<span>小明每次花100元</span>
<!-- 每次单击爸爸的钱少100 并且告诉爸爸 $emit,并且传递 金钱-100的值 给父亲-->
<button @click="$emit('input', value - 100)">花钱</button>
<!-- 显示爸爸剩余多少钱 -->
爸爸还剩 {{ value }} 元
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: "Child",
// 接收父亲传递过来的信息,告诉了我现在父亲有多少钱
props: ["value"],
};
</script>
.sync和v-model在数据同步使用区别
- v-model和.sync都可以实现父子组件数据同步,下面是约定成俗的规定
v-model
是当子组件当中有表单类元素的时候使用.sync
是当子组件当中不是表单类元素的时候使用
自定义带hover提示的el-button和$attrs和$listeners的使用
- 前置知识
- el-button
- 如果想带图标,那么添加icon属性可以,注意: icon属性里面的值都是以el-icon-xxx形式出现的
- element-ui的icon库
- el-button
- 原来的el-button组件并没有鼠标悬停上去就出现提示的功能,我们可以通过对el-button进行再次包装
简易的包装(但是不能达到自己去传入配置设置的要求)
如图 MyButton.vue对el-button进行包装
1
2
3
4
5<template>
<a title="这个是提示框">
<el-button></el-button>
</a>
</template>包装后的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<template>
<div>
<h2>自定义带Hover提示的按钮</h2>
<!-- 使用二次封装后的 -->
<MyButton></MyButton>
</div>
</template>
<script>
</script>效果图
使用$attrs和$listeners进行复杂包装(可自定义参数效果)
前面要知道的
- 同等效果
- 传递数据给组件,可以使用
:key="value"
或者 直接省略:
,直接写 key= “value” 也是可以的,不过有冒号的:key="value"
value为js代码,没有冒号的 key=”value” value值为字符串!!
- 传递数据给组件,可以使用
1
2
3<MyButton aa="10"></MyButton>
<!-- 上一行和下一行是同等效果 -->
<MyButton aa="10"></MyButton>不同等效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<!-- 传递字符串 "b" -->
<MyButton aa="b"></MyButton>
<!-- 传递变量b的值,即为10 -->
<MyButton aa="b"></MyButton>
<script>
</script>
- 同等效果
$attrs
获取传递给组件的所有属性,它会排除 props已经声明接收的属性 以及class,style这二个样式• 如图
排除props接收到了的
- 如图
$listeners
获取父组件传递给子组件的所有自定义事件监听组成的对象- 如图
$attrs
和$listeners
一键绑定在组件上- 可以通过
v-bind
一次性把父组件传递过来的属性添加给子组件(v-bind
不可以简写为:
) - 可以通过
v-on
一次性把父组件传递过来的事件监听添加给子组件(v-on
不可以简写@
) - 如图
- 可以通过
$children和$parent和$refs的使用
this.$refs
放在HTML和组件标签身上的区别this.$refs.名称
放在html标签身上拿到的就是这个DOM元素this.$refs
放在组件标签身上拿到的就是组件对象本身
this.$refs妙用
可以直接通过this.$refs.名称来获取组件,并且在组件当中去操作这个获取到的组件里面的数据
如图所示(父亲) 父亲直接通过this.$refs.son.money就操控了儿子和女儿的钱
$children 和 $parent的妙用
$parent
前提:
- 必须只有一个父亲才可以使用!如果这个组件有多个父亲,那么就不可以用!(为什么有多个父亲,因为存在组件复用的情况!)
如图,儿子通过
this.$parent.money
来获取父亲的钱并且修改
$children
获取当前组件的所有的子组件,返回子组件的数组,(无顺序,不能说[0]一定就是儿子,[1]就一定是女儿)
如图
本案例当中,均在配置对象当中书写了data数据
mixin混入的基本使用
@官方API:混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
说通俗点就是混入就是将别人的东东变为自己的东东,这里的混入只说一些基本的使用
先来看示例吧
mixin/test.js文件的代码
1 | const mixins = { |
App.vue
使用mixin/test.js的混入
1 | <template> |
功能测试是否正常,可以看到,可以正常显示和调用函数
- 当然了,还有很多情况,比如说混入的时候,当
mixin/test.js
里面的数据或者方法和App.vue
当中的数据或者方法冲突的时候要怎么解决之类的,具体看官网吧~ @官网
之前做的一个混入的图