嗨!让我抓住礼拜天的尾巴,继续研究Vue.js吧XD,之后就要分心处理React了,那废话不多说,分隔线下进入正文!
对父级做事件处理
首先提一下关于组件的事件处理,昨天有在文章中提到官方的一个例子:
HTML
<div id="demoCounter"> <button-counter></button-counter></div>
JavaScript
Vue.component('button-counter',{ data:()=>{ return { count:0, } }, template:`<div> <button @click="count++">Click me</button> <span>目前点了{{count}}下</span> </div>`})let demoCounter = new Vue({ el:'#demoCounter',})
上方在设定组件时我们把事件写再button
的@click
里面,让他被点击时可以把count
加1,但是这仅仅于组件控制组件的资料而已,试着想想当把count
的值放到demoCounter
的data
中时,组件内的事件该怎么控制count
加1呢?如果遇到这种情况可以使用Vue.js中的内建方法$emit
传入事件名字,让他对父层组件demoCounter
触发用v-on
绑定的事件名称:
HTML
<div id="demoCounter"> <!--再使用组件时设定组件内部监听的$emit事件名称来触发父组件的事件--> <button-counter @add-count="addCount"></button-counter> <!--把count从内部组件移到外面--> <span>目前点了{{count}}下</span></div>
JavaScript
Vue.component('button-counter',{ template:`<div> <!--在组件内部使用v-on绑定$emit方法,传入事件名称--> <button @click="$emit('add-count')">Click me</button> </div>`,})let counterData = { count:0,}let counterMethods = { //被触发的事件在这边 addCount:()=>{ counterData.count+=1; }} let demoCounter = new Vue({ el:'#demoCounter', data:counterData, methods:counterMethods,})
如上方使用$emit
建立让外层组件监听的事件,就可以触发并更改父组件的方法及资料。
然后这里在使用事件的时候也有需要注意的地方,那就是$emit
传入的方法名称会全部变成小写,而且和之前在设定组件名称时不同,就算在这里使用驼峰命名法
,他在外面v-on
的时候也不会帮你转换成短横线命名法
,也就是说驼峰式命名法
在这里完全无用武之地,以下是例子:
HTML
<!--使用驼峰式命名法让父组件监听事件名称--><button @click="$emit('addCount')">Click me</button><!--如果像上方$emit设定,以下两种写法都不会被触发--><button-counter @add-count="addCount"></button-counter><button-counter @add-count="add-count"></button-counter><!--他会被转成小写的版本,所以只有以下写法会被触发--><button-counter @add-count="addcount"></button-counter>------------------分隔线------------------<!--如果一开始是短横线命名法--><button @click="$emit('add-count')">Click me</button><!--不需另外转换写法也会被触发--><button-counter @add-count="add-count"></button-counter>
所以说,官方在这里注明了,不如就使用$emit
时只以短横线命名法
处理,当然如果平时就是用短横线命名法
就不需要在意这个了。
另一点是,有时候父组件上监听的事件会需要一个或以上的参数传入处理,所以$emit
他第一个参数如上面所说是呼叫父组件的事件名称,这边也要感谢fysh711426大大留言补充关于参数的部分,如果是由$emit
指定事件,并额外传入参数给父组件的话,$emit
会把第二个以后的全部参数都放到arguments
这个物件中,也就是说父组件如果要获取子组件藉由$emit
传的参数,必须使用arguments[0]
代表第一个参数、arguments[1]
代表第二个参数..等等,我们看下方例子:
HTML
<div id="demoCounter"> <!--在父组件上用arguments来接收子组件传的参数--> <button-counter @add-count="addCount(arguments)"></button-counter> <span>目前点了{{count}}下</span></div>
JavaScript
Vue.component('button-counter',{ template:`<div> <!--在组件内部使用v-on绑定$emit方法,传入事件名称外多传了两个参数--> <button @click="$emit('add-count','传入一个参数','传入第二个参数')">Click me</button> </div>`,})let counterData = { count:0,}let counterMethods = { addCount:(arrArg)=>{ //在事件内分别印出arrArg物件,和第一个值还有第二个值 console.log(arrArg) console.log(arrArg[0]) console.log(arrArg[1]) counterData.count+=1; }} let demoCounter = new Vue({ el:'#demoCounter', data:counterData, methods:counterMethods,})
结果会如下:
接着来提好久不见的v-model
吧!
在组件上使用v-model
之前的文章中有说过,v-model
其实是个语法糖,也就是让各位大大用起来觉得甜甜的(咦?),先複习一下吧!v-model
到底帮我们做了哪些事:
<input v-model="message" />
会等于:
<input :value="message" @input="message = $event.target.value" />
上面的观念之前的文章中有提过(还不熟的可以看这里),所以应该不会有太大的问题,但在组件上直接使用v-model
是不会有任何作用的,所以当我们知道v-model
的原理以后,也可以用相同的方式放到让v-model
在组件上实现。
但是一口气说完,第一个想法可能是「天啊!这是什么鬼?」,所以这个部分让我们大部分解一下过程:
在组件上设定Props
属性,并用指定value
来绑定input
的value
值,有没有初始值都没关係,但是为了做到v-model
的v-bind:value="value"
必须这么做。JavaScript
Vue.component('inputName',{ //用props属性来为组件内的DOM绑定资料 props:['value'], template:`<div> <!--这边的观念是:value="message"的部分--> <input :value='value' > </div>`,})
接着要处理v-model
帮我们做的第二件事情@input="message = $event.target.value"
,但是我们v-model
绑定的资料在父组件的data
中,所以用上面学到的$emit
来控制和触发父组件的事件,而上面也有说过$emit
的第一个参数为触发父组件的事件名称,那我们的事件名称是什么?先回头看一下HTML
的部分:HTML
<div id="demoInput"> <!--在组件里用v-model绑定父组件data中的nameVal--> <input-name v-model="nameVal"></input-name> <span>我的名字是:{{nameVal}}</span></div>
单就<input-name v-model="nameVal"></input-name>
这一行,大家应该可以知道他做了哪些事情吧?他会等于:
HTML
<input-name :value="nameVal" @input="nameVal=$event.target.value"></input-name>
欸嘿嘿!聪明的你发现父组件的事件了吗?没错!就是input
,所以$emit
要绑定的事件名称就是input
,但是光是呼叫到input
还是不够的,因为父组件的input
会用$event.target.value
的值去指定给nameVal
,所以在事件后方要再多加一个参数,让父组件的input
接收,所以设定第二个参数为input
的值:$event.target.value
。
JavaScript
Vue.component('inputName',{ props:['value'], template:`<div> <!--加上了@input="message = $event.target.value"的观念,并用$emit来触发父组件的input事件--> <input :value='value' @input="$emit('input', $event.target.value)"> </div>`,})//这里是父组件,绑定的资料在data中let demoInput = new Vue({ el:'#demoInput', data:{ nameVal:'', },})
最后的程式码,把所有注解拿掉会如下方这样子,也完成了在组件中实做v-model
,虽然看起来没有几行,但是却用到了之前提到的不少观念,所以如果有不懂得可以看一下前面的几篇文章,或是自己练习看看,都会加深一点印象!
HTML
<div id="demoInput"> <input-name v-model="nameVal"></input-name> <span>我的名字是:{{nameVal}}</span></div>
JavaScript
Vue.component('inputName',{ props:['value'], template:`<div> <input :value='value' @input="$emit('input', $event.target.value)"> </div>`,})let demoInput = new Vue({ el:'#demoInput', data:{ nameVal:'', },})
得到的结果就和我们一般使用的<input v-model="nameVal" />
一样对吧!但没想到加入组件后会变的那么难懂,不过还是老话一句,熟能生巧,虽然感觉我发文很频繁,不过每次在写範例的时候还是会一直偷看之前自己发的文XD。
最后感谢大大们的观看!如果文章中有任何解释不清楚或理解错误的地方,还请各位大大留言告诉我,另外有任何想法也都欢迎留言和我讨论,不管是什么我都会认真看过的!谢谢大家