Vue v-on: tıklama bileşen üzerinde çalışmıyor


187

Bir bileşenin içindeki tıklama yönergesini kullanmaya çalışıyorum ama işe yaramıyor gibi görünüyor. Bileşeni tıklattığımda, konsolda bir 'test tıklatıldı' almam gerektiğinde hiçbir şey olmaz. Konsolda herhangi bir hata görmüyorum, bu yüzden neyi yanlış yaptığımı bilmiyorum.

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>vuetest</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

App.vue

<template>
  <div id="app">
    <test v-on:click="testFunction"></test>
  </div>
</template>

<script>
import Test from './components/Test'

export default {
  name: 'app',
  methods: {
    testFunction: function (event) {
      console.log('test clicked')
    }
  },
  components: {
    Test
  }
}
</script>

Test.vue (bileşen)

<template>
  <div>
    click here
  </div>
</template>

<script>
export default {
  name: 'test',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

Yanıtlar:


334

Bir bileşenin kök öğesindeki yerel bir olayı dinlemek istiyorsanız , aşağıdakiler için .native değiştiricisini kullanmanız gerekir v-on:

<template>
  <div id="app">
    <test v-on:click.native="testFunction"></test>
  </div>
</template>

veya kısaca, yorumda önerildiği gibi şunları da yapabilirsiniz:

<template>
  <div id="app">
    <test @click.native="testFunction"></test>
  </div>
</template>

3
Veya stenografi@click.native="testFunction"
Pier

75
ne olduğu doğal olay ya da nasıl diğerinden farklıdır , normal olaylar? Neden kök elemanlar için bu özel durum ???
MrClan


9
doğal değiştiricinin vue içinde kullanılması tavsiye edilir. Sadece kesinlikle gerekliyse kullanın. Bunu gerçekleştirmenin doğru yolu için @ jim-mcneely'ye bakınız, yani alt öğeden olayları yayan ve daha sonra üst öğede yeniden canlandıran.
Deiknymi


32

Bence $emitfonksiyon istediğini düşündüğüm şey için daha iyi çalışıyor. Bileşeninizi Vue örneğinden ayrı tutar, böylece birçok bağlamda yeniden kullanılabilir.

// Child component
<template>
  <div id="app">
    <test @click="$emit('test-click')"></test>
  </div>
</template>

HTML'de kullanın

// Parent component
<test @test-click="testFunction">

5
Bunun doğru cevap olduğuna inanıyorum. Bileşen içinde olayların bağlantılarını ele alın. Tıklama etkinliğinin hangi "sürümünün" aranacağının üst bileşeniyle ilgilenmeyin. Aslında bunu bileşende aşağıdaki cevap olarak uyguluyorum @click="$emit('click')"ve bu şekilde ana bileşen düzenli kullanıyor@click
Nelson Rodriguez

2
Biraz kafam karıştı. $ Emit parçasının test bileşeni şablonunda olması gerekiyor mu?
Stefan Fabian

1
@ NelsonRodriguez ne dedi. Kullanın @click="$emit('click')".
Nifel

20

Bu @Neps'in cevabı ama detayları ile.


Not : Bileşeninizi değiştirmek istemiyorsanız veya ona erişiminiz yoksa @ Saurabh'ın cevabı daha uygundur.


@Click neden sadece çalışmıyor?

Bileşenler karmaşıktır. Bir bileşen küçük bir süslü düğme sarıcı olabilir ve diğeri içinde bir grup mantık bulunan tüm bir tablo olabilir. Vue, bağlandığında v-modelveya kullandığınızda tam olarak ne beklediğinizi bilmiyor v-on, bu nedenle bunların tümü bileşenin yaratıcısı tarafından işlenmelidir.

Tıklama etkinliği nasıl yönetilir?

Vue belgelerine göre , $emitolayları ebeveyne aktarır. Dokümanlardan örnek:

Ana dosya

<blog-post
  @enlarge-text="onEnlargeText"
/>

Bileşen

<button @click="$emit('enlarge-text')">
  Enlarge text
</button>

( @Bir v-on kısaltmadır )

Bileşen yerel clicketkinliği işler ve ebeveynin@enlarge-text="..."

enlarge-textclickyerel bir tıklama etkinliğini ele alıyor gibi görünmesini sağlamak için bununla değiştirilebilir :

<blog-post
  @click="onEnlargeText"
></blog-post>
<button @click="$emit('click')">
  Enlarge text
</button>

Ama hepsi bu değil. $emitbir olayla belirli bir değerin iletilmesine izin verir. Native durumunda click, değer MouseEvent'dir (Vue ile ilgisi olmayan JS olayı).

Vue bu olayı bir $eventdeğişkende saklar . Bu nedenle, $eventyerel etkinlik kullanımı izlenimi oluşturmak için bir etkinlikle yaymak en iyisidir :

<button v-on:click="$emit('click', $event)">
  Enlarge text
</button>

8

Biraz ayrıntılı ama bunu nasıl yaparım:

@click="$emit('click', $event)"


8
bu nereye gidiyor? Neden oraya koydun? Bu yanıtı görüntüleyenler için biraz daha ayrıntı ekleyin, lütfen?
mix3d

Bu örnekte bu, Test.vue bileşenindeki div etiketine yerleştirilir. Daha sonra v-on kullanabilirsiniz: App.vue
Tim Wickstrom

Bunu ben değiştirdim $emitama hiçbir şey olmuyor. Ayrıca bir şey yapmam gerekir $emitmi? jsfiddle.net/xwvhy6a3
Richard Barraclough

@RichardBarraclough bileşeniniz artık "clickTreeItem" özel etkinliğinizi yayınlıyor. Ardından, bu bileşenin kullanımında o olayla ne yapılacağı ele alınacaktır: v-on: myEvent = "myMethod"
Neps

5

Bileşenlerin yerel olaylarına üst öğelerden doğrudan erişilemez. Bunun yerine v-on:click.native="testFunction", Testbileşenden de bir olay gönderebilirsiniz . Gibi v-on:click="$emit('click')".


4

VueCONF US 2019'da Chris Fritz (Vue.js Core Team Emeriti ) tarafından belirtildiği gibi

Kia girmiş olsaydık .nativeve daha sonra baz girişin kök elemanı bir girişten bir etikete değişti ve bu bileşen kırıldı ve açık değil ve aslında, gerçekten iyi bir testiniz olmadıkça hemen yakalayamayabilirsiniz. Bunun yerine, şu anda Vue 3'te bir anti-desen kaldırılacağını düşündüğüm.native değiştiricinin kullanımından kaçınarak, ebeveynin hangi öğe dinleyicilerinin eklendiğini önemsediğini açıkça tanımlayabileceksiniz ...

Vue 2 ile

Kullanma $listeners:

Yani, Vue 2 kullanıyorsanız, bu sorunu çözmek için daha iyi bir seçenek tamamen şeffaf bir sarma mantığı kullanmak olacaktır . Bu Vue $listeners, bileşen üzerinde kullanılan dinleyicilerin bir nesnesini içeren bir özellik sağlar . Örneğin:

{
  focus: function (event) { /* ... */ }
  input: function (value) { /* ... */ },
}

ve sonra biz sadece eklemem gerekiyor v-on="$listeners"için testbenzeri bileşeni:

Test.vue (alt bileşen)

<template>
  <div v-on="$listeners">
    click here
  </div>
</template>

Şimdi <test>bileşen tamamen şeffaf bir sargıdır , yani normal bir <div>eleman gibi kullanılabilir : tüm dinleyiciler .nativedeğiştirici olmadan çalışacaktır .

Demo:

Vue.component('test', {
  template: `
    <div class="child" v-on="$listeners">
      Click here
    </div>`
})

new Vue({
  el: "#myApp",
  data: {},
  methods: {
    testFunction: function(event) {
      console.log('test clicked')
    }
  }
})
div.child{border:5px dotted orange; padding:20px;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="myApp">
  <test @click="testFunction"></test>
</div>

$emitYöntemi kullanarak :

$emitAna bileşendeki alt bileşenler olaylarını dinlememize yardımcı olan bu amaç için de yöntemi kullanabiliriz . Bunun için önce aşağıdaki gibi alt öğeden özel bir etkinlik yayınlamamız gerekir :

Test.vue (alt bileşen)

<test @click="$emit('my-event')"></test>

Önemli: Olay adları için her zaman kebap durumu kullanın. Daha fazla bilgi ve bu noktadan demo demosu için lütfen şu cevaba göz atın : VueJS hesaplanan değeri bileşenden üst öğeye geçirir .

Şimdi, bu yayılan özel etkinliği aşağıdaki gibi ana bileşenlerde dinlememiz gerekiyor:

App.vue

<test @my-event="testFunction"></test>

Yani, temelde v-on:clickya da steno yerine @clicksadece v-on:my-eventya da sadece kullanacağız @my-event.

Demo:

Vue.component('test', {
  template: `
    <div class="child" @click="$emit('my-event')">
      Click here
    </div>`
})

new Vue({
  el: "#myApp",
  data: {},
  methods: {
    testFunction: function(event) {
      console.log('test clicked')
    }
  }
})
div.child{border:5px dotted orange; padding:20px;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="myApp">
  <test @my-event="testFunction"></test>
</div>


Vue 3 ile

Kullanma v-bind="$attrs":

Vue 3 hayatımızı birçok yönden kolaylaştıracak. Bunun örneklerinden biri, sadece kullanarak daha az yapılandırmayla daha basit bir şeffaf sargı oluşturmamıza yardımcı olacağıdır v-bind="$attrs". Bunu alt bileşenlerde kullanarak, yalnızca dinleyicimiz doğrudan ebeveynten değil, aynı zamanda diğer normal özellikler de normal bir şekilde çalışır <div>.

Bu nedenle, bu soru ile ilgili olarak, Vue 3'teki hiçbir şeyi güncellememiz gerekmeyecek ve kodunuz <div>burada kök öğe gibi iyi çalışacak ve otomatik olarak tüm alt olayları dinleyecektir.

Demo # 1:

const { createApp } = Vue;

const Test = {
  template: `
    <div class="child">
      Click here
    </div>`
};

const App = {
  components: { Test },
  setup() {
    const testFunction = event => {
      console.log("test clicked");
    };
    return { testFunction };
  }
};

createApp(App).mount("#myApp");
div.child{border:5px dotted orange; padding:20px;}
<script src="//unpkg.com/vue@next"></script>
<div id="myApp">
  <test v-on:click="testFunction"></test>
</div>

Ancak <input />, ana etiket yerine ana öğeye öznitelikler ve olaylar uygulamamız gereken yuvalanmış öğelere sahip karmaşık bileşenler içinv-bind="$attrs"

Demo # 2:

const { createApp } = Vue;

const BaseInput = {
  props: ['label', 'value'],
  template: `
    <label>
      {{ label }}
      <input v-bind="$attrs">
    </label>`
};

const App = {
  components: { BaseInput },
  setup() {
    const search = event => {
      console.clear();
      console.log("Searching...", event.target.value);
    };
    return { search };
  }
};

createApp(App).mount("#myApp");
input{padding:8px;}
<script src="//unpkg.com/vue@next"></script>
<div id="myApp">
  <base-input 
    label="Search: "
    placeholder="Search"
    @keyup="search">
  </base-input><br/>
</div>


1
Bu kabul edilen cevap olmalı. Teşekkürler!
alijunior

0

Gönderen belgeler :

JavaScript'teki sınırlamalar nedeniyle Vue, bir dizide aşağıdaki değişiklikleri algılayamaz:

  1. Dizinle doğrudan bir öğe ayarladığınızda, örneğin vm.items [indexOfItem] = newValue
  2. Dizinin uzunluğunu değiştirdiğinizde, örneğin vm.items.length = newLength

Benim durumumda Angular'dan VUE'ye geçerken bu sorunla karşılaştım. Düzeltme oldukça kolaydı, ancak bulmak gerçekten zor:

setValue(index) {
    Vue.set(this.arr, index, !this.arr[index]);
    this.$forceUpdate(); // Needed to force view rerendering
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.