admin管理员组文章数量:1129631
Let's say I have a main Vue instance that has child components. Is there a way of calling a method belonging to one of these components from outside the Vue instance entirely?
Here is an example:
var vm = new Vue({
el: '#app',
components: {
'my-component': {
template: '#my-template',
data: function() {
return {
count: 1,
};
},
methods: {
increaseCount: function() {
this.count++;
}
}
},
}
});
$('#external-button').click(function()
{
vm['my-component'].increaseCount(); // This doesn't work
});
<script src=".js"></script>
<script src=".1.1/jquery.min.js"></script>
<div id="app">
<my-component></my-component>
<br>
<button id="external-button">External Button</button>
</div>
<template id="my-template">
<div style="border: 1px solid; padding: 5px;">
<p>A counter: {{ count }}</p>
<button @click="increaseCount">Internal Button</button>
</div>
</template>
Let's say I have a main Vue instance that has child components. Is there a way of calling a method belonging to one of these components from outside the Vue instance entirely?
Here is an example:
var vm = new Vue({
el: '#app',
components: {
'my-component': {
template: '#my-template',
data: function() {
return {
count: 1,
};
},
methods: {
increaseCount: function() {
this.count++;
}
}
},
}
});
$('#external-button').click(function()
{
vm['my-component'].increaseCount(); // This doesn't work
});
<script src="http://vuejs.org/js/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="app">
<my-component></my-component>
<br>
<button id="external-button">External Button</button>
</div>
<template id="my-template">
<div style="border: 1px solid; padding: 5px;">
<p>A counter: {{ count }}</p>
<button @click="increaseCount">Internal Button</button>
</div>
</template>
So when I click the internal button, the increaseCount()
method is bound to its click event so it gets called. There is no way to bind the event to the external button, whose click event I am listening for with jQuery, so I'll need some other way to call increaseCount
.
EDIT
It seems this works:
vm.$children[0].increaseCount();
However, this is not a good solution because I am referencing the component by its index in the children array, and with many components this is unlikely to stay constant and the code is less readable.
Share Improve this question edited Feb 11, 2019 at 10:46 Pierce O'Neill 38310 silver badges24 bronze badges asked Nov 12, 2015 at 22:29 harrygharryg 24.1k46 gold badges134 silver badges208 bronze badges 3- 1 I added an answer using mxins if you want to give it a try. In my opinion I prefer to setup the app this way. – Omar Tanti Commented Mar 28, 2018 at 1:31
- Why do you need to do that? I mean why do you need to call that method? Maybe better to use something like v-model? – Igor Popov Commented Feb 19, 2022 at 1:48
- In my case it would be something like this: I build some vue app that I include in some existing static hugo webpage. The vue app can be seen as some plugin/addon and is otherwise completely separate. But I would like to connect the existing search button and language switcher to the vue app that also supports this. – E. Körner Commented May 22, 2023 at 7:14
17 Answers
Reset to default 357In the end I opted for using Vue's ref
directive. This allows a component to be referenced from the parent for direct access.
E.g.
Have a component registered on my parent instance:
const vm = new Vue({
el: '#app',
components: { 'my-component': myComponent }
});
Render the component in template/html with a reference:
<my-component ref="foo"></my-component>
Now, elsewhere I can access the component externally
<script>
vm.$refs.foo.doSomething(); //assuming my component has a doSomething() method
</script>
See this fiddle for an example: https://jsfiddle.net/0zefx8o6/
(old example using Vue 1: https://jsfiddle.net/6v7y6msr/)
Edit for Vue3 - Composition API
The child-component has to return
the function in setup
you want to use in the parent-component otherwise the function is not available to the parent.
Note:
<script setup>
doc is not affacted, because it provides all the functions and variables to the template by default.
You can set ref for child components then in parent can call via $refs:
Add ref to child component:
<my-component ref="childref"></my-component>
Add click event to parent:
<button id="external-button" @click="$refs.childref.increaseCount()">External Button</button>
var vm = new Vue({
el: '#app',
components: {
'my-component': {
template: '#my-template',
data: function() {
return {
count: 1,
};
},
methods: {
increaseCount: function() {
this.count++;
}
}
},
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<my-component ref="childref"></my-component>
<button id="external-button" @click="$refs.childref.increaseCount()">External Button</button>
</div>
<template id="my-template">
<div style="border: 1px solid; padding: 2px;" ref="childref">
<p>A counter: {{ count }}</p>
<button @click="increaseCount">Internal Button</button>
</div>
</template>
For Vue2 this applies:
var bus = new Vue()
// in component A's method
bus.$emit('id-selected', 1)
// in component B's created hook
bus.$on('id-selected', function (id) {
// ...
})
See here for the Vue docs. And here is more detail on how to set up this event bus exactly.
If you'd like more info on when to use properties, events and/ or centralized state management see this article.
See below comment of Thomas regarding Vue 3.
You can use Vue event system
vm.$broadcast('event-name', args)
and
vm.$on('event-name', function())
Here is the fiddle: http://jsfiddle.net/hfalucas/wc1gg5v4/59/
A slightly different (simpler) version of the accepted answer:
Have a component registered on the parent instance:
export default {
components: { 'my-component': myComponent }
}
Render the component in template/html with a reference:
<my-component ref="foo"></my-component>
Access the component method:
<script>
this.$refs.foo.doSomething();
</script>
Say you have a child_method()
in the child component:
export default {
methods: {
child_method () {
console.log('I got clicked')
}
}
}
Now you want to execute the child_method
from parent component:
<template>
<div>
<button @click="exec">Execute child component</button>
<child-cmp ref="child"></child_cmp> <!-- note the ref="child" here -->
</div>
</template>
export default {
methods: {
exec () { //accessing the child component instance through $refs
this.$refs.child.child_method() //execute the method belongs to the child component
}
}
}
If you want to execute a parent component method from child component:
this.$parent.name_of_method()
NOTE: It is not recommended to access the child and parent component like this.
Instead as best practice use Props & Events for parent-child communication.
If you want communication between components surely use vuex or event bus
Please read this very helpful article
If you're using Vue 3 with <script setup>
sugar, note that internal bindings of a component are closed (not visible from outside the component) and you must use defineExpose
(see docs) to make them visible from outside. Something like this:
<script setup lang="ts">
const method1 = () => { ... };
const method2 = () => { ... };
defineExpose({
method1,
method2,
});
</script>
Since
Components using
<script setup>
are closed by default
This is a simple way to access a component's methods from other component
// This is external shared (reusable) component, so you can call its methods from other components
export default {
name: 'SharedBase',
methods: {
fetchLocalData: function(module, page){
// .....fetches some data
return { jsonData }
}
}
}
// This is your component where you can call SharedBased component's method(s)
import SharedBase from '[your path to component]';
var sections = [];
export default {
name: 'History',
created: function(){
this.sections = SharedBase.methods['fetchLocalData']('intro', 'history');
}
}
Using Vue 3:
const app = createApp({})
// register an options object
app.component('my-component', {
/* ... */
})
....
// retrieve a registered component
const MyComponent = app.component('my-component')
MyComponent.methods.greet();
https://v3.vuejs.org/api/application-api.html#component
Here is a simple one
this.$children[indexOfComponent].childsMethodName();
I am not sure is it the right way but this one works for me.
First import the component which contains the method you want to call in your component
import myComponent from './MyComponent'
and then call any method of MyCompenent
myComponent.methods.doSomething()
To access the data of a child component in Vue 3 or execute (call) a method, using <script setup>
syntax, as mentioned above, it is necessary to use the defineExpose
(see docs) method to make variables or methods visible from outside. Look at the following code.
Child component:
<script setup>
impor { ref } from "vue";
const varA = ref("Hola");
const myMethod = () => { ... };
defineExpose({
varA,
myMethod,
});
</script>
Parent component:
<child-component ref="myChildComponent" />
<script setup>
import { ref } from "vue";
const myChildComponent = ref(null)
const changeData = () => {
myChildComponent.value.myMethod();
// or
myChildComponent.value.varA = "Hi";
}
</script>
As mentioned above:
Components using script setup are closed by default
If you're searching for vue 3 solution with setup functions, here it is:
Component:
<template>
template...
</template>
<script setup>
import { defineExpose } from "vue";
function do_something(){
alert('called!');
}
// here is the trick
defineExpose({do_something});
</script>
Parent:
<template>
<my-component ref="myComponent" />
</template>
<script setup>
import {ref} from "vue";
const myComponent = ref(null);
// calling method on child component
myComponent.value.do_something();
</script>
In vue 3 composition api you should expose the method you want to access from outside by using defineExpose
.
Sometimes you want to keep these things contained within your component. Depending on DOM state (the elements you're listening on must exist in DOM when your Vue component is instantiated), you can listen to events on elements outside of your component from within your Vue component. Let's say there is an element outside of your component, and when the user clicks it, you want your component to respond.
In html you have:
<a href="#" id="outsideLink">Launch the component</a>
...
<my-component></my-component>
In your Vue component:
methods() {
doSomething() {
// do something
}
},
created() {
document.getElementById('outsideLink').addEventListener('click', evt =>
{
this.doSomething();
});
}
Declare your function in a component like this:
export default {
mounted () {
this.$root.$on('component1', () => {
// do your logic here :D
});
}
};
and call it from any page like this:
this.$root.$emit("component1");
Example of Message component.
100% work on Vue3.
No hacks! Clean console!
It is almost impossible to find a ready-made working solution but here it is.
Official documentation: https://v3.ru.vuejs.org/api/sfc-script-setup.htmlhttps://v3.ru.vuejs.org/api/sfc-script-setup.html
File src/views/FormN.vue
<script setup>
import Messages from '../components/Messages.vue';
</script>
<template>
<Messages ref="messagesRef" />
<form>
<button v-on:click="submitForm" type="button">Send</button>
</form>
</template>
<script>
export default {
methods: {
submitForm() {
this.$refs.messagesRef.addMessage('New item was added.');
// this.$refs.messagesRef.addMessage('New item was not added!', 'warning');
// this.$refs.messagesRef.addMessage('New item was not added!!!', 'error');
// this.$refs.messagesRef.deleteMessagesByType('ok');
// this.$refs.messagesRef.deleteMessagesByType('warning');
// this.$refs.messagesRef.deleteMessagesByType('error');
// this.$refs.messagesRef.deleteMessagesAll();
}
}
}
</script>
File src/components/Messages.vue
<script setup>
import { ref } from 'vue';
const messages = ref({
'ok' : [],
'warning': [],
'error' : []
});
const addMessage = (message, type = 'ok') => {
messages.value[type].push(message);
};
const deleteMessage = (num, type = 'ok') => {
messages.value[type] = messages.value[type].filter((value, i) => i !== num);
};
const deleteMessagesByType = (type = 'ok') => {
messages.value[type] = [];
};
const deleteMessagesAll = () => {
deleteMessagesByType('ok');
deleteMessagesByType('warning');
deleteMessagesByType('error');
};
defineExpose({
addMessage : addMessage,
deleteMessage : deleteMessage,
deleteMessagesByType: deleteMessagesByType,
deleteMessagesAll : deleteMessagesAll
})
</script>
<template>
<x-messages data-type="ok" v-if="messages.ok.length !== 0">
<ul>
<li v-for="(message, num) in messages.ok" :key="num">
{{ message }} [<a href="#" data-type="delete" v-on:click="deleteMessage(num, 'ok')">x</a>]
</li>
</ul>
</x-messages>
<x-messages data-type="warning" v-if="messages.warning.length !== 0">
<ul>
<li v-for="(message, num) in messages.warning" :key="num">
{{ message }} [<a href="#" data-type="delete" v-on:click="deleteMessage(num, 'warning')">x</a>]
</li>
</ul>
</x-messages>
<x-messages data-type="error" v-if="messages.error.length !== 0">
<ul>
<li v-for="(message, num) in messages.error" :key="num">
{{ message }} [<a href="#" data-type="delete" v-on:click="deleteMessage(num, 'error')">x</a>]
</li>
</ul>
</x-messages>
</template>
Bonus: custom tags.
File vite.config.js
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => [
'x-field',
'x-other-custom-tag'
].includes(tag),
}
}
})
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
p.s. This contribution was made by the author and developer of CMS Effcore.
I have used a very simple solution. I have included a HTML element, that calls the method, in my Vue Component that I select, using Vanilla JS, and I trigger click!
In the Vue Component, I have included something like the following:
<span data-id="btnReload" @click="fetchTaskList()"><i class="fa fa-refresh"></i></span>
That I use using Vanilla JS:
const btnReload = document.querySelector('[data-id="btnReload"]');
btnReload.click();
本文标签: javascriptCall a Vuejs component method from outside the componentStack Overflow
版权声明:本文标题:javascript - Call a Vue.js component method from outside the component - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736699366a1948347.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论