我正在尝试在组件内使用 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>
如果您想在组件的根元素上侦听原生事件,则必须对 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
我认为 $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
@click="$emit('click')"
。
.native
修饰符相比,这绝对是更明确的解决方案,并且使父组件更少依赖子组件的实现细节,这几乎总是一个加分项。
它是 @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>
正如 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: `
使用 $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: `
使用 Vue 3
使用 v-bind="$attrs":
Vue 3 将在很多方面让我们的生活变得更加轻松。一个例子是,它可以帮助我们创建一个更简单的透明包装器,只需使用 v-bind="$attrs"
即可减少配置。通过在子组件上使用它,我们的监听器不仅可以直接从父组件工作,而且任何其他属性也可以像使用普通 <div>
一样工作。
所以,关于这个问题,我们不需要在 Vue 3 中更新任何东西,你的代码仍然可以正常工作,因为 <div>
是这里的根元素,它会自动监听所有子事件。
演示#1:
常量 { createApp } = Vue; const 测试 = { 模板:`
但是,对于具有嵌套元素的复杂组件,我们需要将属性和事件应用到 <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;}
有点冗长,但这就是我的做法:
@click="$emit('click', $event)"
更新:@sparkyspider 添加的示例
<div-container @click="doSomething"></div-container>
在 div-container
组件中...
<template>
<div @click="$emit('click', $event);">The inner div</div>
</template>
组件的原生事件不能直接从父元素访问。相反,您应该尝试 v-on:click.native="testFunction"
,或者您也可以从 Test
组件发出事件。像v-on:click="$emit('click')"
。
使用 @click.native
的一个用例是当您创建自定义组件并希望在自定义组件上监听点击事件时。例如:
#CustomComponent.vue
<div>
<span>This is a custom component</span>
</div>
#App.vue
<custom-component @click.native="onClick"></custom-component>
@click.native
始终适用于这种情况。
应用程序.vue
<div id="app">
<test @itemClicked="testFunction($event)"/>
</div>
测试.vue
<div @click="$emit('itemClicked', data)">
click here
</div>
由于 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
}
不定期副业成功案例分享
@click.native="testFunction"