[javascript] Vue v-on : 클릭이 구성 요소에서 작동하지 않습니다

구성 요소 내에서 on click 지시문을 사용하려고하는데 작동하지 않는 것 같습니다. 구성 요소를 클릭해도 콘솔에서 ‘테스트 클릭’이 표시되면 아무 일도 일어나지 않습니다. 콘솔에 오류가 표시되지 않아서 내가 뭘 잘못하고 있는지 모르겠습니다.

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 (구성 요소)

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

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



답변

구성 요소의 루트 요소에서 기본 이벤트를 수신하려면 다음과 같이에 .native 한정자 를 사용해야합니다 v-on.

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

또는 간단히 말해서, 의견에서 제안한대로 다음을 수행 할 수 있습니다.

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


답변

나는 $emit당신이 요구하는 것보다 기능이 더 잘 작동한다고 생각합니다. 여러 컨텍스트에서 재사용 할 수 있도록 구성 요소를 Vue 인스턴스와 분리하여 유지합니다.

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

HTML로 사용

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


답변

그것은이다 @Neps ‘대답 하지만 세부 사항.


참고 : @Saurabh의 답변 은 구성 요소를 수정하지 않거나 액세스 할 수없는 경우 더 적합합니다.


@click이 작동하지 않는 이유는 무엇입니까?

구성 요소가 복잡합니다. 하나의 구성 요소는 작은 멋진 버튼 래퍼가 될 수 있고 다른 구성 요소는 내부에 많은 논리가있는 전체 테이블이 될 수 있습니다. Vue는 바인드 v-model또는 사용할 때 정확히 무엇을 기대하는지 알지 못 v-on하므로 구성 요소 작성자가 모든 것을 처리해야합니다.

클릭 이벤트를 처리하는 방법

에 따르면 뷰의 문서 , $emit부모에 이벤트를 전달합니다. 문서의 예 :

메인 파일

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

구성 요소

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

( @는 IS v-on 속기 )

구성 요소는 기본 click이벤트를 처리 하고 상위 이벤트를 생성합니다.@enlarge-text="..."

enlarge-textclick기본 클릭 이벤트를 처리하는 것처럼 보이도록 대체 할 수 있습니다 .

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

그러나 이것이 전부는 아닙니다. $emit이벤트와 함께 특정 값을 전달할 수 있습니다. native의 경우 click값은 MouseEvent (Vue와 관련이없는 JS 이벤트)입니다.

Vue는 해당 이벤트를 $event변수 에 저장 합니다. 따라서 $event기본 이벤트 사용에 대한 인상을주기 위해 이벤트와 함께 내보내는 것이 가장 좋습니다 .

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


답변

조금 장황하지만 이것이 내가하는 방법입니다.

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


답변

컴포넌트의 기본 이벤트는 상위 요소에서 직접 액세스 할 수 없습니다. 대신을 시도 v-on:click.native="testFunction"하거나 Test구성 요소 에서 이벤트를 생성 할 수 있습니다. 처럼 v-on:click="$emit('click')".


답변

VueCONF 2019 에서 Chris Fritz (Vue.js 핵심 팀 Emeriti )가 언급 한대로

우리가 Kia를 입력 .native한 다음 기본 입력의 루트 요소가 입력에서 레이블로 갑자기 변경되면이 구성 요소가 깨져서 분명하지 않으며 실제로 테스트를 잘하지 않으면 바로 잡을 수 없습니다. 대신 Vue 3에서 안티 패턴이 제거 될 것으로 생각되는.native 수정자를 사용하지 않으면 부모가 추가 할 요소 리스너에 대해 부모가 신경 쓸 수 있음을 명시 적으로 정의 할 수 있습니다 …

Vue 2와 함께

사용 $listeners:

따라서 Vue 2를 사용하는 경우이 문제를 해결하는 더 좋은 옵션은 완전히 투명한 래퍼 논리 를 사용하는 것 입니다. 이를 위해 Vue는 $listeners컴포넌트에서 사용되는 리스너 객체를 포함하는 속성을 제공합니다 . 예를 들면 다음과 같습니다.

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

그런 다음 구성 요소에 다음과 같이 추가하면 v-on="$listeners"됩니다 test.

Test.vue (자식 구성 요소)

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

이제 <test>구성 요소는 완전히 투명한 래퍼입니다 . 즉, 일반 <div>요소 와 똑같이 사용할 수 있습니다 .native. 수정 자 없이 모든 리스너가 작동합니다 .

데모:

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>

$emit방법을 사용하여 :

우리는 $emit이 목적을 위해 메소드를 사용할 수 있으며 , 이는 상위 컴포넌트에서 하위 컴포넌트 이벤트를 청취하는 데 도움이됩니다. 이를 위해 먼저 다음과 같은 하위 컴포넌트에서 사용자 정의 이벤트 를 생성 해야합니다 .

Test.vue (자식 구성 요소)

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

중요 : 이벤트 이름으로 항상 케밥 케이스를 사용하십시오. 이 포인트에 대한 자세한 정보와 데모를 보려면 VueJS가 계산 된 값을 component에서 parent로 전달하십시오 .

이제 다음과 같이 부모 구성 요소에서 생성 된이 사용자 지정 이벤트를 수신하면됩니다.

App.vue

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

그래서, 기본적으로 대신 v-on:click하거나 속기는 @click우리는 단순히 사용 v-on:my-event하거나 @my-event.

데모:

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와 함께

사용 v-bind="$attrs":

Vue 3는 다양한 방식으로 우리의 삶을 훨씬 쉽게 만들어 줄 것입니다. 이에 대한 예제 중 하나는을 사용하여 구성이 훨씬 적은 더 간단한 투명 래퍼 를 만드는 데 도움이된다는 것입니다 v-bind="$attrs". 자식 컴포넌트에서 이것을 사용함으로써 우리의 리스너는 부모로부터 직접 작동 할뿐만 아니라 다른 어떤 속성도 정상적인 것처럼 작동 <div>합니다.

따라서이 질문과 관련하여 Vue 3에서 아무것도 업데이트 할 필요가 없으며 <div>여기의 루트 요소와 마찬가지로 코드가 여전히 잘 작동 하며 모든 자식 이벤트를 자동으로 듣습니다.

데모 # 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>

그러나 <input />부모 레이블 대신 기본에 속성과 이벤트를 적용해야하는 중첩 요소가있는 복잡한 구성 요소의 경우 간단히 사용할 수 있습니다.v-bind="$attrs"

데모 # 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>


답변

로부터 문서 :

JavaScript의 제한으로 인해 Vue는 다음과 같은 배열 변경을 감지 할 수 없습니다.

  1. 색인을 사용하여 항목을 직접 설정하는 경우 (예 : vm.items [indexOfItem] = newValue
  2. 어레이의 길이를 수정할 때 (예 : vm.items.length = newLength)

제 경우에는 Angular에서 VUE로 마이그레이션 할 때이 문제가 발생했습니다. 수정은 매우 쉽지만 찾기가 매우 어렵습니다.

setValue(index) {
    Vue.set(this.arr, index, !this.arr[index]);
    this.$forceUpdate(); // Needed to force view rerendering
}