Passando Funções de Callback para Componentes no Vue.js
Funções de callback permitem a comunicação entre componentes pai e filho no Vue.js. Elas são passadas como props e podem ser chamadas pelo componente filho.
Considere o seguinte exemplo:
<!DOCTYPE html>
<html>
  <head>
    <title>Componentes Vue.js</title>
    <meta charset="utf-8" />
    <script src="https://unpkg.com/vue"></script>
  </head>
  <body>
    <div id="app">
      <h3>Value {{ count }}</h3>
      <counter :changefn="increase"></counter>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return { count: 0 };
        },
        methods: {
          increase() {
            this.count++;
          },
        },
      });
      app.component("counter", {
        props: ["changefn"],
        template: `<div><button v-on:click="changefn()">+</button></div>`,
      });
      app.mount("#app");
    </script>
  </body>
</html>Neste exemplo, o objeto Vue define um contador armazenado na variável count e um método increase() para incrementá-lo. Esse método não é chamado diretamente no componente pai, mas sim no componente filho counter.
A referência ao método increase é passada para o componente counter por meio da prop chamada changefn:
<counter :changefn="increase"></counter>Dentro do componente counter, esse método é chamado ao clicar no botão:
<button v-on:click="changefn()">+</button>Sempre que o botão for pressionado, o método do componente pai será acionado, aumentando o valor da variável count exibida na tela.

Passando Paramentros para Funções de Callback
Agora, veja um exemplo onde há uma lista de usuários, com a possibilidade de adicionar e remover itens:
<!DOCTYPE html>
<html>
  <head>
    <title>Componentes Vue.js</title>
    <meta charset="utf-8" />
    <script src="https://unpkg.com/vue"></script>
  </head>
  <body>
    <div id="app">
      <h2>Lista de Usuários</h2>
      <userform :addfn="add"></userform>
      <div>
        <useritem v-for="(user, index) in users" :user="user" :key="index" :index="index" :removefn="remove"> </useritem>
      </div>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            users: [
              { name: "Tom", age: 23 },
              { name: "Bob", age: 26 },
            ],
          };
        },
        methods: {
          remove(index) {
            this.users.splice(index, 1);
          },
          add(user) {
            this.users.push(user);
          },
        },
      });
      app.component("userform", {
        props: ["addfn"],
        data() {
          return {
            user: { name: "", age: 18 },
          };
        },
        template: `<div>
                        <input type="text" v-model="user.name" />
                        <input type="number" v-model="user.age" />
                        <button v-on:click="addfn({name: user.name, age: user.age})">Adicionar</button>
                    </div>`,
      });
      app.component("useritem", {
        props: ["user", "index", "removefn"],
        template: `<div>
                        <p>Nome: {{ user.name }} <br> Idade: {{ user.age }}</p>
                        <button v-on:click="removefn(index)">Remover</button>
                    </div>`,
      });
      app.mount("#app");
    </script>
  </body>
</html>O objeto Vue exibe uma lista de usuários na tela e define dois métodos: add para adicionar um novo usuário e remove para remover um item da lista.
O componente userform representa um formulário de entrada. O método add é passado como prop chamada addfn:
<userform :addfn="add"></userform>Dentro do userform, a função addfn recebe os valores inseridos e aciona o método add do componente pai.
O componente useritem representa um item da lista. Ele recebe o método remove como prop chamada removefn. Ao clicar no botão de remoção, essa função é chamada, acionando o método remove do componente pai.
Esse padrão permite que os componentes filhos apenas chamem as funções definidas no componente pai, sem modificar diretamente os dados. Dessa forma, a lógica de manipulação da lista fica centralizada no componente pai, enquanto os filhos apenas disparam os eventos necessários.

Documentação: