深入自定义事件和原生DOM事件
自定义事件
-
在组件上标签上添加的事件就是自定义事件,不管系统是否带这些事件
-
比如添加
<自定义组件 @自定义事件 = "回调函数"></自定义组件>
那么@自定义事件
在自定义组件上就是自定义事件 -
<自定义组件 @click = "回调函数"></自定义组件>
,那么@click
就是自定义事件 -
添加的事件如果没有传入参数,那么输出就是undefined
- 如图,传入了参数,单击button,输出为10,如果没有传递参数10,则输出undefined
- 自定义组件上绑定原生DOM事件使用native和不使用的区别,如下图
- 如图
自定义事件示例
App.vue
<template>
<div id="app">
<!-- 给自定义组件绑定自定义事件为click事件,并将事件的回调函数绑定在事件check上 -->
<MyComponent @click="check"></MyComponent>
</div>
</template>
<script>
import MyComponent from '@/components/MyComponent'
export default {
name: 'App',
components: {
MyComponent,
},
methods:{
//给自定义组件绑定的自定义事件
check(event){
console.log("event",event);
}
}
}
</script>
自定义组件MyComponent
<template>
<div class="my">
这是我的组件
<!-- 用于触发给其绑定的自定义事件 -->
<button @click="chufa">触发自定义事件</button>
</div>
</template>
<script>
export default {
name: 'MyComponent',
methods:{
//触发自定义事件click,并传入一个参数100
chufa(){
this.$emit("click",1000);
}
}
}
</script>
<style scoped>
.my{
border: 1px solid red;
}
</style>
效果
原生DOM事件
-
在HTML标签上添加就是原生DOM事件,比如说
@click
@mousemove
这些系统自带的原生事件 -
添加的事件如果没有传入参数,那么系统会默认传入event参数
<button @click="test1">我是按钮1</button> //等同于 <button @click="test1($event)">我是按钮2</button>
vue自定义的事件在html标签和组件标签上的区别
-
在html标签上添加自定义事件无意义,所以自定义事件是给组件标签添加的
-
事件名可以任意,也可以和原生DOM事件名相同,但是是自定义的
-
如果自定义事件上想绑定原生的事件,那么就需要在事件对象名称后面添加 .native 并且绑定的事件添加在添加到组件根元素上,通过委派的形式使得子元素可以被触发
-
如图
深入理解v-model
-
首先我们需要知道v-model在HTML标签上的原理
-
v-model原来写法
// 标准v-model写法 普通写法 <input type="text" v-model="msg" />
-
v-model拆解写法(等同于上方直接写v-model)
- 先使用v-bind绑定一个值给输入框,再添加事件@input,当触发就将当前触发对象的值传递给v-bind绑定的那个值,就这样子完成了数据更新
// v-model拆解写法 <input type="text" :value="msg" @input="msg = $event.target.value"/>
那么v-model当中在自定义组件要怎么实现呢?
-
根据v-model在原生DOM上拆解的写法,我们应该这样子写( 以自定义组件CustomInput为例 )
-
需要知道的是: 在自定义组件当中,
$event
就是$emit
当中第二个参数传递过来的数据 -
父组件
<!--父亲给CustomInput传递 "msg2" 数据 --> <!--儿子要使用props接收( props:["value"] ),并且传递了自定义事件input --> <CustomInput :value="msg" @input="msg = $event"></CustomInput> <!--上面这一行代码可以简写为下面这一行但是子组件不能简写--> <!--必须要写下面这些内容!!!!!!!!!!!!!! --> <CustomInput v-model="msg"></CustomInput>
-
子组件 CustomInput.vue
<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的区别
[需求]
父亲向儿子传递一个值叫money),儿子每次都花100块钱,要求儿子花了多少钱,爸爸那边可以同步
第一次(无效果) (直接传递数据给儿子, 儿子每次单击都花100块钱)
-
父亲 (直接传递数据给儿子)
<!-- 会弹出警告说数据不同步 --> <Child :money="moneyFather"></Child>
弹出警告
-
儿子
<template> <span>小明每次花100元</span> <!-- 每次单击爸爸的钱就减少100 --> <button @click="money = money - 100">单击我花钱</button> <!-- 显示爸爸剩余多少钱 --> 爸爸还剩 {{ money }} 元 </template> <script> export default { name:"Child", //接收父亲传递过来的信息,告诉了我现在父亲有多少钱 props:["money"] } </script>
-
结果
- 儿子花钱按钮被单击,儿子当中的父亲的钱数量被改变,但是父亲兜兜里面的钱没有变化
第二次(有效果) 数据传递给儿子,但是儿子每次单击花钱的时候就告诉父亲我花钱了
-
父亲 (
$event
在自定义组件当中是$emit
传递的参数 父亲收到儿子传递过来的金钱数,就更新自己的金钱数)<!-- $event在自定义组件当中是$emit传递的参数 --> <!-- @update:xxx为固定格式,不可以更改,xxx为绑定的数据属性也就是v-bind:xxx="值"(当中的xxx) 对应简写属性 :xxx="值" 当中的xxx --> <Child :money="moneyFather" @update:money="moneyFather = $event"></Child>
-
儿子每次单击爸爸的钱就减少100 并且告诉爸爸 (通过
$emit
),并且传递 金钱-100的 值 给父亲<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修饰符)
<Child :money.sync="moneyFather"></Child>
-
儿子 (和第二次一样) 每次单击爸爸的钱就减少100 并且告诉爸爸 (通过
$emit
),并且传递 金钱-100的 值 给父亲<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
传递过来的数据)
<Child :value="moneyFather" @input="moneyFather = $event"></Child>
- 自定义组件
-
儿子
<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进行包装
<template> <a title="这个是提示框"> <el-button></el-button> </a> </template>
-
包装后的使用
<template> <div> <h2>自定义带Hover提示的按钮</h2> <!-- 使用二次封装后的 --> <MyButton></MyButton> </div> </template> <script> <!-- 引入二次封装后的el-button组件 --> import MyButton from "./myButton.vue" export default { name:"AttrsListenersTest", <!-- 注册使用自定义组件 --> componets:{ MyButton } } </script>
-
效果图
使用$attrs和$listeners进行复杂包装(可自定义参数效果)
-
前面要知道的
- 同等效果
- 传递数据给组件,可以使用
:key="value"
或者 直接省略:
,直接写 key= “value” 也是可以的,不过有冒号的:key="value"
value为js代码,没有冒号的 key=“value” value值为字符串!!
- 传递数据给组件,可以使用
<MyButton aa="10"></MyButton> <!-- 上一行和下一行是同等效果 --> <MyButton aa="10"></MyButton>
-
不同等效果
<!-- 传递字符串 "b" --> <MyButton aa="b"></MyButton> <!-- 传递变量b的值,即为10 --> <MyButton aa="b"></MyButton> <script> <!-- 引入二次封装后的el-button组件 --> import MyButton from "./myButton.vue" export default { name:"AttrsListenersTest", data(){ return { b:10 } }, <!-- 注册使用自定义组件 --> componets:{ MyButton } } </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文件的代码
const mixins = {
data(){
return {
sex:"男",
age:"18",
}
},
methods:{
sayHello(){
console.log("你好,世界");
}
}
};
export default mixins;
App.vue
使用mixin/test.js的混入
<template>
<div>
<div>姓名:{{name}}</div>
<div>年龄:{{sex}}</div>
<div>性别:{{age}}</div>
<button @click="sayHello">单击我 - 说hello</button>
<button @click="sayThankyou">单击我 - 说谢谢</button>
</div>
</template>
<script>
// 引入混入
import myMixin from "@/mixin/test";
export default {
name: "",
//使用混入
mixins:[myMixin],
data() {
return {
name:"李白",
}
},
methods:{
sayThankyou(){
console.log("谢谢你");
}
}
};
</script>
功能测试是否正常,可以看到,可以正常显示和调用函数
- 当然了,还有很多情况,比如说混入的时候,当
mixin/test.js
里面的数据或者方法和App.vue
当中的数据或者方法冲突的时候要怎么解决之类的,具体看官网吧~ @官网
之前做的一个混入的图