ChatGPT解决这个技术问题 Extra ChatGPT

Vue v-on:click 对组件不起作用

我正在尝试在组件内使用 on click 指令,但它似乎不起作用。当我单击组件时,当我应该在控制台中获得“单击测试”时,什么都不会发生。我在控制台中没有看到任何错误,所以我不知道我做错了什么。

索引.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>

应用程序.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>

t
tony19

如果您想在组件的根元素上侦听原生事件,则必须对 v-on 使用 .native 修饰符,如下所示:

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

或者简而言之,正如评论中所建议的,您也可以这样做:

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

Reference to read more about native event


或简写 @click.native="testFunction"
什么是原生事件或它与其他正常事件有何不同?为什么这种根元素的特殊情况???
不建议在 vue 中使用 native 修饰符。只有在绝对必要时才使用它。请参阅@jim-mcneely 了解实现此目的的正确方法,即从子元素发出事件,然后在父元素中恢复它。
这是 native events 的正确链接
A
Adam

我认为 $emit 功能更适合我认为您所要求的。它使您的组件与 Vue 实例分离,以便在许多情况下可重用。

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

在 HTML 中使用它

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

我相信这是正确的答案。在组件内处理事件的链接。不关心要调用的单击事件的“版本”的父组件。我实际上在组件 @click="$emit('click')" 中将它实现为下面的答案,这样父组件只需使用常规 @click
我有点困惑。 $emit 部分是否应该在测试组件模板中?
@NelsonRodriguez 说了什么。使用 @click="$emit('click')"
.native 修饰符相比,这绝对是更明确的解决方案,并且使父组件更少依赖子组件的实现细节,这几乎总是一个加分项。
t
tony19

它是 @Neps' answer,但有详细信息。

注意:如果您不想修改组件或无权访问它,@Saurabh's answer 更合适。

为什么@click 不能正常工作?

组件很复杂。一个组件可以是一个小的花哨的按钮包装器,另一个可以是一个包含一堆逻辑的整个表格。 Vue 不知道您在绑定 v-model 或使用 v-on 时的确切期望,因此所有这些都应由组件的创建者处理。

如何处理点击事件

根据 Vue docs$emit 将事件传递给父级。来自文档的示例:

主文件

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

零件

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

@v-on shorthand

组件处理原生 click 事件并发出父级的 @enlarge-text="..."

enlarge-text 可以替换为 click 以使其看起来像是在处理原生点击事件:

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

但这还不是全部。 $emit 允许通过事件传递特定值。在原生 click 的情况下,值为 MouseEvent(与 Vue 无关的 JS 事件)。

Vue 将该事件存储在 $event 变量中。因此,最好使用事件发出 $event 以创建原生事件使用的印象:

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

很好的答案。使用自定义组件上的 $emit('click') ,它会按预期工作:)
t
tony19

正如 Chris Fritz (Vue.js Core Team Emeriti) 在 VueCONF US 2019 中提到的

如果我们让 Kia 输入 .native,然后基本输入的根元素突然从一个输入变为一个标签,这个组件就会被破坏并且这并不明显,事实上,除非你有一个非常好的测试。相反,通过避免使用我目前认为是反模式并将在 Vue 3 中删除的 .native 修饰符,您将能够明确定义父级可能关心哪些元素侦听器被添加到...

使用 Vue 2

使用 $listener:

因此,如果您使用的是 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: `

点击这里
` }) new Vue({ el: "#myApp", data: {},方法:{ testFunction: function(event) { console.log('test clicked') } } }) div.child{border:5px dotted orange; padding:20px;}
<测试@click="testFunction">

使用 $emit 方法:

为此,我们还可以使用 $emit 方法,它可以帮助我们在父组件中侦听子组件的事件。为此,我们首先需要从子组件发出 custom event,例如:

Test.vue(子组件)

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

重要提示:始终使用 kebab-case 作为事件名称。有关这一点的更多信息和演示,请查看此答案:VueJS passing computed value from component to parent

现在,我们只需要在父组件中监听这个发出的自定义事件,比如:

应用程序.vue

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

所以基本上,我们将简单地使用 v-on:my-event 或仅使用 @my-event,而不是 v-on:click 或简写 @click

演示:

Vue.component('test', { template: `

点击这里
` }) new Vue({ el: " #myApp", data: {}, methods: { testFunction: function(event) { console.log('test clicked') } } }) div.child{border:5px dotted orange; padding:20px;}
<测试@my-event="testFunction">

使用 Vue 3

使用 v-bind="$attrs":

Vue 3 将在很多方面让我们的生活变得更加轻松。一个例子是,它可以帮助我们创建一个更简单的透明包装器,只需使用 v-bind="$attrs" 即可减少配置。通过在子组件上使用它,我们的监听器不仅可以直接从父组件工作,而且任何其他属性也可以像使用普通 <div> 一样工作。

所以,关于这个问题,我们不需要在 Vue 3 中更新任何东西,你的代码仍然可以正常工作,因为 <div> 是这里的根元素,它会自动监听所有子事件。

演示#1:

常量 { createApp } = Vue; const 测试 = { 模板:`

点击这里
` }; const App = { components: { Test }, setup() { const testFunction = event => { console.log("test clicked"); };返回 { testFunction }; } }; createApp(App).mount("#myApp"); div.child{border:5px 点缀橙色; padding:20px;}
< /div>

但是,对于具有嵌套元素的复杂组件,我们需要将属性和事件应用到 <input /> 而不是父标签,我们可以简单地使用 v-bind="$attrs"

演示#2:

常量 { createApp } = Vue; const BaseInput = { props: ['label', 'value'], template: ` ` }; const App = { components: { BaseInput }, setup() { const search = event => { console.clear(); console.log("正在搜索...", event.target.value); };返回{搜索}; } }; createApp(App).mount("#myApp"); input{padding:8px;}



J
JJJSchmidt

有点冗长,但这就是我的做法:

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

更新:@sparkyspider 添加的示例

<div-container @click="doSomething"></div-container>

div-container 组件中...

<template>
  <div @click="$emit('click', $event);">The inner div</div>
</template>

这是哪里?你为什么把它放在那里?请为查看此答案的人添加更多详细信息,好吗?
在这个例子中,这将被放置在 Test.vue 组件中的 div 标签上。然后在 App.vue 中使用组件测试时可以使用 v-on:click="testFunction" 或 @click="testFunction"
我将其更改为 $emit 但没有任何反应。除了$emit,我还需要做些什么吗? jsfiddle.net/xwvhy6a3
@RichardBarraclough 您的组件现在会发出您的自定义事件“clickTreeItem”。接下来是在使用该组件时处理该事件的处理方式: v-on:myEvent="myMethod"
佚名

组件的原生事件不能直接从父元素访问。相反,您应该尝试 v-on:click.native="testFunction",或者您也可以从 Test 组件发出事件。像v-on:click="$emit('click')"


P
Penny Liu

使用 @click.native 的一个用例是当您创建自定义组件并希望在自定义组件上监听点击事件时。例如:

#CustomComponent.vue
<div>
  <span>This is a custom component</span>
</div>

#App.vue
<custom-component @click.native="onClick"></custom-component>

@click.native 始终适用于这种情况。


F
Farzad.Kamali

应用程序.vue

<div id="app">
    <test @itemClicked="testFunction($event)"/>
</div>

测试.vue

<div @click="$emit('itemClicked', data)">
     click here
</div>

t
tony19

documentation

由于 JavaScript 的限制,Vue 无法检测到数组的以下更改:

当你直接设置一个带有索引的项目时,例如 vm.items[indexOfItem] = newValue 当你修改数组的长度时,例如 vm.items.length = newLength

就我而言,我在从 Angular 迁移到 VUE 时偶然发现了这个问题。修复很容易,但很难找到:

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