1. 程式人生 > 實用技巧 >Vue基礎——將原生事件繫結到元件

Vue基礎——將原生事件繫結到元件

今天再次看了看vue文件,又找到了知識盲區。

對於將原生事件繫結到元件 ,文件有講,別人也有寫部落格。

但我還是想根據自己的理解把這一內容講清楚

總的來說,有三種方法

  • 使用native修飾符
  • 使用$emit分發事件
  • 使用$listeners

正文:

首先,show code

html中程式碼
<
div id="app"> <my-button @click='handleClick'></my-button> </div>
js中程式碼
Vue.component('my-button',{ template:`<button>點選</button>` }) const vm
= new Vue({ el:'#app', methods:{ handleClick(){ console.log('click') } } })

在這裡,我們定義了my-button子元件,在父元件中引用了,然後我們想在上面繫結click事件,觸發handleClick回撥。

那麼,可以猜猜有沒有觸發?

——結果很容易猜到,沒有觸發,click沒有列印輸出。

為什麼?

——因為vue有自己事件執行機制,my-button不是原生DOM元素,我們是無法直接給其繫結原生事件並觸發的

所以就有解決辦法一:使用native修飾符

我們僅需要在click後加上.native就可,如下

<div id="app">
    <my-button @click.native='handleClick'></my-button>
</div>

相當於我們會把事件放在原生button標籤上,此時事件便觸發,click就列印了。

雖然這個方法使用起來非常簡單,但是其存在侷限性:它只會把事件放在子元件的根標籤上。

上面子元件的根標籤就是button,自然就觸發了。

但是某些情況下,將某些事件繫結在根標籤而非目標標籤時,是無法觸發事件的。如下情況:

<div id="app2">
    <my-input @focus.native='handleFocus'></my-input>
</div>
Vue.component('my-input',{
    template:`
    <label for="">
       label:
       <input type="text">
   </label>
    `
})
const vm2 = new Vue({
    el:'#app2',
    methods:{
        handleFocus(){
            console.log('focus...')
        }
    }
})

儘管我們使用了native修飾符,但是focus事件放在子元件根標籤——label標籤上,無法觸發該事件。

所以就有解決辦法二:使用$emit分發事件

Vue.component('my-input',{
    template:`
    <label for="">
       label:
       <input type="text" @focus='$emit("focus","子元件的value")'>
   </label>
    `
})
const vm2 = new Vue({
    el:'#app2',
    methods:{
        handleFocus(value){
            console.log('focus...',value)   //focus... 子元件的value
        }
    }
})

在子元件input標籤中繫結focus事件,其回撥中使用$emit分發事件,使父元件事件觸發。

$emit()有兩個引數:

第一個引數為分發的事件名,在這裡為focus,也可改別的,只需要與父元件中給子元件標籤上繫結的事件名一致即可

第二個引數為給父元件該事件傳的引數,我們在父元件中的該事件回撥中就可接受到。所以我們一般想將子元件的資料傳給父元件,完成父子元件間的通訊,就可使用$emit。

除了這個解決方法外,還有第三種:使用$listeners

$listeners 它是一個物件,裡面包含了作用在這個元件上的所有監聽器。

Vue.component('my-input',{
    template:`
    <label for="">
       label:
       <input type="text" v-on='$listeners'>    
   </label>
    `
})

(其餘程式碼同上一個方法,故省略)

在input上使用 v-on="$listeners" ,就是將所有的事件監聽器指向這個input元素。

故也同樣能打印出,且value值為event物件。

相比起方法二,這個$listener的使用更加全面——

  若是方法二,再在子元件標籤上繫結多個事件,那就要在子元件進行相應的寫事件名進行$emit分發

  而這個方法,就已經將所有事件監聽綁在input元素上了,就不用再次設定

而且,你也可以再次設定,$listeners的使用是很靈活的

你可以自定義監聽器,或者覆蓋一些監聽器的行為。

在下面的程式碼中,重寫了focus事件監聽器

Vue.component('my-input',{
    template:`
    <label for="">
       label:
       <input type="text" v-on='inputListeners'>    
   </label>
    `,
    computed:{
        inputListeners(){
            return Object.assign({},this.$listeners,{
                focus:(event)=>{
                    this.$emit('focus',event.target.value)
                }
            })
        }
    }
})

首先,我們得明白 v-on:xxx=fn等價於v-on={xxx:fn}

其次,inputListeners是一個計算屬性,返回的是一個物件,是將$listeners 和 你重寫的事件的物件 合併的物件

還有,在這裡重寫監聽器,還是用到了$emit,每個監聽器都得到event物件,我們可以取出event.target.value傳給父元件

最後,父元件就能在focus時觸發事件,並得到子元件傳來的值了

總結:

三種方法都能使原生事件繫結到元件上,就寫法上當然是第一種最簡單,第三種更麻煩。但是隻要理解了就都挺好寫的了。

但是在使用時,還是根據需求來,若是就是想繫結到元件的根標籤上,直接使用第一種即可。否則,便使用二或三。