Poznajemy Vue, krok po kroku. Tym razem poznajemy, czym są methods i jak ich używać. Do dzieła.

Ok, nasza apka:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://unpkg.com/vue@3.4.9/dist/vue.global.js" defer></script> 
    <script src="app3.js" defer></script>
</head>
<body>
    
    <div id="app">
        <p>Random number: {{Math.random()}}</p>
    </div>
</body>
</html>

Używamy tutaj funkcji wewnątrz nawiasów wąsatych jak widać. Oczywiście, potrzebna jeszcze część JavaScriptowa, inaczej to po prostu tekst:

const app = Vue.createApp({
    data() {
      return {
        counter: 0
      };
    },

  });
  
app.mount('#app');

Ok, fajnie. Ale mamy też takie coś, jak methods. Dodajmy metodę increment:

const app = Vue.createApp({
    data() {
      return {
        counter: 0
      };
    },
    methods: {
        increment(){
            this.counter++;
        }
    },

  });
  
app.mount('#app');

This wskazuje na obiekt data, na zmienne w tym obiekcie. Ok, teraz markup:

<div id="app">
        <p>Random number: {{Math.random()}}</p>
        <p>Counter: {{counter}}</p>
        <button @click="increment">+ 1</button>
</div>

Counter działa bez zarzutu, ale możemy zaobserwować, że za każdym jego użyciem Math.random też się wykonuje. Specjalnie takie przykłady tworzę, abyśmy oswoili się z tym, jak działają frameworki frontendowe, jakie mają ograniczenia.

Jest tak – każdy re-render sprawia, że metody są odpalane. Możemy to sprawdzić, dodajmy ten kod:

const app = Vue.createApp({
    data() {
      return {
        counter: 0,
        name: "John"
      };
    },
    methods: {
        increment(){
            this.counter++;
        },
        fullname(){
            console.log("I run");
            return this.name + " Doe";
        }
    },

  });
  
app.mount('#app');

Ok, pobawmy się guzikiem do inkrementacji. Żadnego i run nie będzie, tylko random będzie się wywoływać. Teraz jednak zmieńmy markup:

<div id="app">
        <p>Random number: {{Math.random()}}</p>
        <p>Counter: {{counter}}</p>
        <p>Fullname: {{fullname()}}</p>
        <button @click="increment">+ 1</button>
    </div>

Teraz, za każdym kliknięciem zmieniającym counter (którego nowa wersja jest zapisywana w data) zobaczymy, że fullname również jest odpalane, choć wcale nie musi być, jego zależności (czyli name) się nie zmieniły.

Mimo wszystko – re-render (wymuszony przez zmianę countera, który jest wyświetlany) sprawia, że Vue musi obliczyć sobie wartość fullname od nowa.

To są zupełnie nowe koncepty, w backendzie tego nie mieliśmy. Cóż, przyzwyczajajmy się. Jest sposób, aby tego uniknąć, tzw. computed properties, ale o tym za chwilę.

Na razie sposób na setTimeout, który zmienia coś z data:

 methods: {
        increment(){
            this.counter++;
        },
        fullname(){
            console.log("I run");
            return this.name + " Doe";
        },
        incrementDelayed(){
            let that = this;
            
            setTimeout(() => {
                that.counter++;
            }, 3000);
        }
    },

Stara sztuczka JavaScriptowców, nie ma nic z Vue wspólnego, jeżeli tego nie znamy, to wstyd. Użyjmy w markupie:

<button @click="increment">+ 1</button>
<button v-on:click="incrementDelayed">+ 1 delayed</button>

Dyrektywa v-on to po prostu wydłużona wersja @click. Nie ma znaczenia, czego używamy:

<button v-on:click="increment">+ 1</button>
<button @click="incrementDelayed">+ 1 delayed</button>

Oczywiście po tych 3 sekundach nastąpi zmiana countera (+1), która wymusza re-render, który wymusza ponowne wylosowanie liczby oraz ponowne obliczenie fullname.

Więcej Vue już wkrótce.