11 Temmuz 2020 Cumartesi

VueJs Öğrenmeye Devam

Merhaba ,

Daha önce Vue .js üzerinde çalışma yapmıştım. Bu sefer başka bir kurs üzerinden tekrar sıfırdan başlayarak bilgimizi ilerletmeye devam ediyoruz. Önce ortamı hazırlayalım. Bu bölüm için bir klasör tanımlayalım ve içinde ilk adında bir klasör ekleyerek başlayalım. Bu klasöre denemelerimizi yapmak için index.html adında bir yeni dosya ekleyelim. Favori editörümüzde index.html dosyasını düzenlemek için açalım. Benim favori editörüm Sublime, size de tavsiye ederim. Önce basit temel HTML sayfa yapısını bir tanımlayalım.

ilk/index.html
<!DOCTYPE html>
<html>
    <head>
        <title>VueJs Öğreniyorum</title>
    </head>
    <body>

    </body>
</html>

Ben kodlarımda Türkçe kelimeler kullanmayı seviyorum. Ancak tarayıcılarda sorun yaşamak istemiyorsanız bütün kod yazdığınız dosyaları UTF-8 encoding ile kaydetmelisiniz. Özellikler Windows kullananlarda "yeni dosya" diyerek üretilen dosyalar Türkçe için Wimdows hazretlerinin Türkçe'ye uygun gördüğü encoding formatlarından birinde üretiliyor ve tarayıcılar bu kodlamayı tanımıyor ya da tanıması için kodumuza ekstra ilavelerle tarayıcıya anlatmamız gerekiyor.


UTF-8 kaydetmek için ne yapılır? Sublime kullanıyorsanız File > Save with Encoding > UTF-8 with BOM menü seçeneği Notepad++ kullanırsanız Kodlama > UTF-8 BOM'a Dönüştür menü seçeneği bu işi yapar.

Önce bir yerlerden VueJs dosyası bulalım ve klasörümüze indirelim. Her yerlere koymuşlar kütüphane dosyalarını. Birini vereyim https://unpkg.com/vue/dist/vue.js sizi en son versiyona götürür. Burada sayfaya sağ tıklayıp "farklı kaydet" seçerek Vue.js dosyasını index.html dosyamızın yanına kaydedelim. Sıra geldi kütüphane dosyamızı web sayfamıza eklemeye.

ilk/index.html
...
    <head>
        <title>VueJs Öğreniyorum</title>
        <script src="vue.js"></script>
    </head>
...

Artık kullanmaya bağlayabiliriz. VueJs sayfada görsel içinde etki edeceği bir alana sahip olmalıdır. Genel teamül olarak bu bölge için sayfada id değeri app olan bir div elemanı kullanılır. Sayfamızın body kısmına bu div elemanını ekleyelim.

ilk/index.html
...
    <body>
        <div id="app"></div>    
    </body>
...

Şimdi JavaScript kodlarımızı yazmak için main.js adında bir dosya oluşturalım ve bunu da index.html dosyamıza dahil edelim.

...
    <body>
        <div id="app"></div>

        <script src="main.js"></script>    
    </body>
...

Bir örnekle başlayalım. Vue kütüphanesini sayfamızda kullanmak için JavaScript kodumuzda Vue sınıfının bir oluşumunu ekleriz. Bu oluşumu tanımlarken en önemli özellik olarak html dosyamızdaki hangi elemana bu kodun etki edeceğini belirlemek olur.

ilk/main.js
new Vue({
  el: "#app"
});

el özelliği Vue kodlarının hangi html elemanına etki edeceğini belirler. Değer string olarak bir CSS seçici kelimesi olarak verilir.

Hep merhaba dünya denip başlanır ya, biz de sayfamıza bir mesaj çıkartalım. Vue kullanarak bir değişkenin değerini şöyle yazdırırız,

ilk/index.html
...
        <div id="app">
            <h3>{{ mesaj }}</h3>
        </div>
...

{{ mesaj }} yapısı parantezler içindeki şeyin bir kod olarak işleneceğini belirtiyor. Şimdi JavaScript kodumuzda Vue oluşum nesnesinde mesaj değişkenine bir değer verelim.

ilk/main.js
new Vue({
  el: "#app",
  data: {
    mesaj: "Merhaba Vue"
  }
});

Değişken tanımlamaları için data özelliğinde bir nesne içinde verilmesi gerekir. Şimdi sayfayı tarayıcıda açıp sonucu görelim.


Gördüğümüz gibi {{ mesaj }} yerine mesaj değişkenine JavaScript kodumuzda verdiğimiz değer geldi. Deneme olsun diye aynı div elemanını kopyalayıp başka bir id değeri verelim.

ilk/index.html
...
        <div id="app">
            <h3>{{ mesaj }}</h3>
        </div>
        <div id="app2">
            <h3>{{ mesaj }}</h3>
        </div>
...



Sadece doğru id değerine sahip bölümde kod çalıştı geri kalan ise normal bir yazı olarak işlendi. Yazdığımız kodlar sadece el özelliğinde seçili olan eleman içerisinde geçerli olacaktır. Sayfada başka başka bölümler için de ayrı Vue sınıfı oluşumları tanımlayarak onlarda da başka kodların çalışmasını sağlayabiliriz.




Uygulamamızı geliştirelim

Diyelim sayfamıza bir input elemanı ekleyerek bu mesaj değişkenine kullanıcının buradan değer girmesini sağlayalım.

ilk/index.html
...
        <div id="app">
            <input type="text" v-on:input="mesajDeğiştir($event)">
            <h3>{{ mesaj }}</h3>
        </div>
...

v-on deyimi VueJs'in bu elemanla ilgili bir olayı takip edeceğini belirtiyor. İki nokta üstüste işareti sonrasında gelen input ise takip edilecek olay. Yani input elemanından bir değer girildiğinde olay oluşacak. Özelliğe değer olarak girilen mesajDeğiştir olay gerçekleşince çalıştırılacak olan metodun adı. JavaScript kodumuza metodu ekleyelim.

new Vue({
  el: "#app",
  data: {
    mesaj: "Merhaba Vue"
  },
  methods: {
    mesajDeğiştir: function(olay){
      this.mesaj = olay.target.value;
    }
  }
});

$event ile olayın bilgisini metoda gönderiyoruz. Mesajı değiştirmek için değişkeni this.mesaj diye çağırıyoruz. Vue nesnemiz içinde data ve methods bölümlerinde verilen tüm isimlere fonksiyonların içinden başlarına this koyarak erişebiliriz. olay.target yani olayın hedefi bizim input elemanımız. Onun değerini mesaj değişkenine yazıyor olay görev metodumuz.







DOM Etkileşimleri


Başlangıç kodumuza geri dönelim

ilk/index.html
<!DOCTYPE html>
<html>
    <head>
        <title>VueJs Öğreniyorum</title>
        <script src="vue.js"></script>
    </head>
    <body>
        <div id="app">
            <h3>{{ mesaj }}</h3>
        </div>

        <script src="main.js"></script>    
    </body>
</html>

va JavaScript kodumuz,

ilk/main.js
new Vue({
  el: "#app",
  data: {
    mesaj: "Merhaba Vue"
  }
});

Sayfada Merhaba Vue yazısına sağ tıklayıp öğeyi denetle (ya da inspect element) seçersek geliştirici araçları penceresinde bize elemanı gösterecektir.


Burada yazdığımız kod görünmez. İşlenmiş son hali görünür. Ama sayfaya sağ tıklayıp "sayfa kaynağı" seçtiğimizde orjinal işlenmemiş kod halini görürüz. Bu geliştirici araçları penceresinde kodumuzun sonucu elde edilen DOM elemanlarını görüp inceleyebiliriz.

Diyelim Vue metodu olarak tanımladığımız bir metodu görselimizde çalıştırmak istiyoruz. Aynı görsel yapısını kullanarak metodu da çağırabiliriz.

ilk/main.js
new Vue({
  el: "#app",
  data: {
    mesaj: "Merhaba Vue"
  },
  methods: {
    merhabaDe: function(){
      return "Merhaba, Naber?";
    }
  }
});

ilk/index.html
...
        <div id="app">
            <h3>{{ merhabaDe() }}</h3>
        </div>
...

Metod çağırırken ismin sonuna eklenen parantezleri unutmayalım. Sayfayı yenileyince metod çalıştırılır ve sonucunda geri dönen değer görsele yazılır.


Bu şekilde string değeri olan bir değişken ya da string değer dönen bir fonksiyon DOM elemanına etki etmiş olur.

Foınksiyon içinden data bölümündeki değişkenlere erişmek için başına this ekliyorduk. Mesajımızı fonksiyon yoluyla yayınlamayı düşünürsek.

ilk/main.js
...
    merhabaDe: function(){
      return this.mesaj;
    }
...

Tekrar Merhaba Vue mesajımıza geri döndük. Sayfamıza bir de link ekleyelim ama referans adresi Vue değişkeninden gelsin,

ilk/index.html
...
        <div id="app">
            <h3>{{ merhabaDe() }} - <a href="{{ link }}">Google</a></h3>
        </div>
...

ve data bölümüne link adında değişkeni ekleyelim,

ilk/main.js
...
  data: {
    mesaj: "Merhaba Vue",
    link: "http://google.com/"
  },
...

Bu kod eski versiyonlarda çalışır ama son versiyonda çalışmaz ve konsolda bir hata mesajı görürüz.


Diyor ki tag özellikleri içinde etkileşim iptal edilmiştir. v-bind deyimi ya da eşdeğeri olan : kullanarak yapın. Mesela <div id="{{ val }}"> yerine <div :id="val"> kullanın. Hadi yapalım.

ilk/index.html
...
        <div id="app">
            <h3>{{ merhabaDe() }} - <a :href="link">Google</a></h3>
        </div>
...

Artık linkimiz çalışıyor. :href deyiminin uzun şekli v-bind:href Bir şeyi değişken değerine bağlamaya bind deniyor. Burada da href özelliğini link değişkenine bağlamış oluyoruz. VueJs v-bind gibi birçok yönlendirmelere sahip, zaman içinde teker teker göreceğiz inşallah.


Bir kerelik bağlamalar

Şimdiye kadar gördüğümüz şekliyle VueJs etkileşimleri her zaman aktif kalırlar. Yani değişkene kod içinde başka bir değer daha verirsek bu sefer yeni değer görseli değiştirecektir. Örnek olarak mesaj değerini h1 elemanı içinde gösterelim ve merhabaDe metodu içinde mesaj değişkenine yeni değer verdikten sonra aşağıda gösterelim.

ilk/index.html
...
        <div id="app">
            <h1>{{ mesaj }}</h1>
            <h3>{{ merhabaDe() }} - <a :href="link">Google</a></h3>
        </div>
...

ilk/main.js
...
    merhabaDe: function(){
      this.mesaj = "Sadece Merhaba"
      return this.mesaj;
    }
...


Haydaa!.. Önce üst satır işlenir h1 içine Merhaba Vue yazılır , sonra metod çalışır mesaj değişkeni değişir aşağıya da Sadece Merhaba yazar diye beklemiştim Ama Vue değişken değerlerini takip eder ve bir değer değişmesi olursa gider kullanılan yerlere o değeri tekrar işler.

v-once deyimi VueJs'e elemanın içindeki değerlerin bir kez işleneceğini sonra işlenmeyeceğini bildirir. Örnekte sadece bir kez işlenmesini istediğimiz eleman h1 elemanı. Kodu şöyle değiştiririz.

        <div id="app">
            <h1 v-once>{{ mesaj }}</h1>
            <h3>{{ merhabaDe() }} - <a :href="link">Google</a></h3>
        </div>


Güzel. Aklımızın bir köşesinde tutalım, lazım olacak gibi.



HTML kodu yayınlamak


Diyelim yukarıda sadece href değerini bağladığımız link elemanını komple VueJs değişkeni yardımıyla görselde yayınlamak istiyoruz. Görsel ve JavaScript şöyle olacaktır.

        <div id="app">
            <h1 v-once>{{ mesaj }}</h1>
            <h3>{{ merhabaDe() }} - <a :href="link">Google</a></h3>
            <hr>
            <h3>{{ linkEleman }}</h3>
        </div>

  data: {
    mesaj: "Merhaba Vue",
    link: "http://google.com/",
    linkEleman: "<a href='http://google.com/'>Google</a>"
  },

ve sonuç,


😊 VueJs ileride karşılaşılabilecek güvenlik açıklarından bizi korumak için html kodlarını yayınlarken düz yazıya çevirir. Fakat biz önlemlerimizi aldık kardeşim bu html kodu sayfada işle demek istiyorsak. v-html yönlendiricisi kullanabiliriz. Şöyleki,

ilk/index.html
...
        <div id="app">
            <h1 v-once>{{ mesaj }}</h1>
            <h3>{{ merhabaDe() }} - <a :href="link">Google</a></h3>
            <hr>
            <h3 v-html="linkEleman"></h3>
        </div>
...


Tekrar belirteyim yayınlayacağımız içerik kullanıcı tarafından girilen verilere dayanmıyor dahili olarak üretiliyorsa ya da girilen verileri tamamen temizlediğimize eminsek v-html yönlendiricisi kullanabiliriz. Aksi halde web sitemiz cross site scripting adı verilen saldırılara maruz kalabilir.



Olayları İzlemek

Olaylar programları yönlendiren ana unsurdur. Genelde programlar bir olayın gerçekleşmesini bekler ve bu olaya göre bir tepki verir. Her zaman bir şeyler olunca bir şeyler çalışır. Örnek olarak bir butonun tıklanması, bir değerin girilmesi, belirli bir zamanın gelmesi, bir tuşa basılması vs kullanıcının yaptığı ya da sistem tarafından üretilen bir çok olay vardır. Olay işlemenin iki parçası vardır, ilki olayı izlemek ve gerçekleşmesini beklemek, ikincisi ise olay gerçekleştiğinde yapılacakları belirten bir fonksiyon tanımlamak. Bu fonksiyonların genel adı olay görev fonksiyonlarıdır.

VueJs kullanıcının yaptığı etkileşimlerden doğan olayları takip etmek için v-on yönlendiricisini kullanır. En başta hatırlarsak bir input elemanına değer girilmesini izleyen bir kod yazmıştık. Şimdi de bir buton tıklanmasını izleyen örnek verelim.

ilk/index.html
...
        <div id="app">
            <button v-on:click="arttır()">Tıkla</button>
            <h3>{{ sayaç }}</h3>
        </div>
...

ilk/main.js
new Vue({
  el: "#app",
  data: {
    sayaç: 0
  },
  methods: {
    arttır: function(){
      this.sayaç++;
    }
  }
});

Aslında burada VueJs Türkçe karakterle ilgili bir sorun yaşıyor. Ben bunu pansuman bir tedbir ile aştım. v-on:click="arttır()" yazarken parantezlere gerek yok aslında. Ama fonksiyon isminde Türkçe karakter olduğundan böyle yazmadan çalışmıyor. Bu yüzden bundan sonra fonksiyon isimlerinde Türkçe karakterler yerine en yakın İngilizce karakteri kullanacağım. Şöyle düzenlersek

<button v-on:click="arttir">Tıkla</button>

ve

    arttir: function(){

Sıkıntı olmadan çalışır.


Voila!.. Ama ben Opera kullanıyorum belki sizin kullandığınız tarayıcıda sıkıntı olmaz bilemem.



Olay nesnesinden olay bilgisini almak

Yukarıdaki koda ilave olarak mouse koordinatları bildirmek için bir görsel ilavesi yapalım.

ilk/index.html
...
        <div id="app">
            <button v-on:click="arttir">Tıkla</button>
            <h3>{{ sayaç }}</h3>
            <p>{{ x }} / {{ y }}</p>
        </div>
...

x ve y değişkenleri data bölümünde tanımlı olmalıdır.

ilk/main.js
...
  data: {
    sayaç: 0,
    x: 0,
    y: 0
  },
...

İzlememiz gereken olay mousemove olayı. Mouse hareket ettirildikçe bu olay çağrılacaktır. İzleme için görseli şöyle yaparız,

...
            <p v-on:mousemove="koordinatYenile">{{ x }} / {{ y }}</p>
...

Vue nesnesi metodunu ekleyelim,

...
   methods: {
    arttir: function(){
      this.sayaç++;
    },
    koordinatYenile: function(olay){
      this.x = olay.clientX;
      this.y = olay.clientY;
    }
  }
...

Paragraf üzerinde mouse gezdirdikçe koordinatlar değişecektir. Neden sadece paragraf üzerindeyken? Çünkü olay izlemesini paragraf elemanına tanımladık. Metod tanımında parametre olarak bir isim verirsek o isimdeki değişkende olayın bilgisi olacaktır. clientX ve clientY ise VueJs ile alakasız. Bunlar JavaScript MouseMove olayının standart bilgileri.

v-on: yerine kısaltması olan @ işaretini de kullanabiliriz,

<p @mousemove="koordinatYenile">{{ x }} / {{ y }}</p>




Kendi verimizi fonksiyona göndermek

Ya görev fonksiyonuna kendi istediğimiz bir parametreyi göndermek istersek ne yapacağız? Sayaç meselesine geri dönelim. Şu anda kodumuz butona her tıklandığında değeri bir arttırıyor. Değeri her seferinde arttırılacak miktarı da buton tıklamasında fonksiyonu çağırırken belirtmek istersek şöyle yaparız.

ilk/index.html
...
        <div id="app">
            <button v-on:click="arttir(2)">Tıkla</button>
            <h3>{{ sayaç }}</h3>
...

Metodumuzu da verilen parametreye göre arttırma yapacak şekilde değiştirelim.

ilk/main.js
...
    arttir: function(miktar){
      this.sayaç += miktar;
    },
...

Artık her buton tıklanınca sayı 2 artacaktır. Peki hem kendi verilerimizi hem de olay bilgisini nasıl alacağız?

...
        <div id="app">
            <button v-on:click="arttir(2, $event)">Tıkla</button>
            <h3>{{ sayaç }}</h3>
...

$event yazarak olay bilgisini parametre olarak verebiliriz. $event değişkeni ön tanımlıdır ve içinde gerçekleşmiş lan olay bilgisini barındıran bir nesnedir. Fonksiyon içinde de 2. parametre olarak standart parametre gibi kullanabiliriz. Mesela,

...
    arttir: function(miktar, olay){
      console.log(olay);
      this.sayaç += miktar;
    },
...





Olayı değiştirmek

Bazen tanımladığımız olayı modifiye etmemiz gerekebilir. Bunu görmek için de koordinatlar göstergemize örnek yapalım. Diyelin paragraf içinde bir bölgede mouse koordinatlarının takip edilmemesini istiyoruz. Görselimizi şöyle değiştirelim,

ilk/index.html
...
        <div id="app">
            <button v-on:click="arttir(2, $event)">Tıkla</button>
            <h3>{{ sayaç }}</h3>
            <p @mousemove="koordinatYenile">
                Koordinatlar : {{ x }} / {{ y }}
                - <span>ÖLÜ BÖLGE</span>
            </p>
        </div>
...

Eklediğimiz span elemanı hala bizim paragrafımız içinde olduğundan onun üzerinde mouse gezerken de koordinatlar yenilenir. Bunu durdurmak için span elemanına da mouse takip eden bir olay izlemesi yazıp onun fonksiyonu içinde paragraftaki izleyicinin harekete geçmesini engelleyebiliriz.

...
            <p @mousemove="koordinatYenile">
                Koordinatlar : {{ x }} / {{ y }}
                - <span @mousemove="durdur">ÖLÜ BÖLGE</span>
            </p>
...

Metod tanımı da şöyle,

ilk/main.js
...
    koordinatYenile: function(olay){
      this.x = olay.clientX;
      this.y = olay.clientY;
    },
    durdur: function(olay){
      olay.stopPropagation();
    }
...

stopPropagation fonksiyonu olayın burada bitirilmesi ve diğer izleyenlere bildirilmemesini sağlıyor.

Fakat VueJs'de bunu daha kolay bir şekilde yapabiliriz.

...
            <p @mousemove="koordinatYenile">
                Koordinatlar : {{ x }} / {{ y }}
                - <span @mousemove.stop="">ÖLÜ BÖLGE</span>
            </p>
...

.stop eki olayın yayınlanmasını durdurur. Bu sayede bir yeni fonksiyon tanımlamaya gerek kalmaz. durdur metodumuza artık gerek kalmadı silebiliriz. VueJs'de bu eklere olay modifiye edici denir (event modifier).



Keyboard olayları

Görsele bir input elemanı ekleyelim ve içinde herhangi bir tuşa basılıp bırakılınca bir alarm versin.

ilk/index.html
...
            <input type="text" @keyup="alarmVer">
...

Ve karşılık metodumuz,

ilk/main.js
...
    alarmVer: function(){
      alert("ALARM!");
    }
...

Hangi tuşa basarsak basalım bıraktığımızda bir alarm penceresi açılacaktır. Peki sadece enter tuşu basıp bırakılınca alarm vermek istersek ne yapacağız?. VueJs'de bunun için bir olay modifiye edici var ,

...
            <input type="text" @keyup.enter="alarmVer">
...

.enter ile keyup olayını modifiye edince sadece enter tuşuna cevap veriyor. Tuş ismini yazarak böyle filtrelemeler yapabiliriz. Mesela .z desek z tuşu basılınca çalışacaktı. Hem enter hem de boşluk çubuğu basılmasında çalışsın istersek.

...
            <input type="text" @keyup.enter.space="alarmVer">
...

Böyle sürüp gider.



Görsel içinde JavaScript yazmak

Butonumuz tıklanınca fonksiyon çağırmak yerine direk JavaScript kod da çalıştırabiliriz. Örnek olarak butonumuzun bir kopyasını alalım ve fonksiyon çağırmak yerine kod yazalım.

ilk/index.html
...
            <button v-on:click="arttir(2)">Tıkla</button>
            <button v-on:click="sayaç++;">Tıkla</button>
...

Aynı şekilde değeri görterirken de işlem yapabiliriz.

...
            <h3>{{ sayaç * 2 }}</h3>
...

Bu da tamamen geçerli bir yöntem olacaktır. İstersek daha büyütelim sayı 10'dan büyük mü kontrol edelim.

...
<h3>{{ sayaç * 2 > 10 ? "Sayı 10'dan büyük" : "Sayı 10'dan küçük" }}</h3>
...

Gördüğümüz gibi kodumuz karışık yada sade, uzun ya da kısa olsun çalışacaktır. Tabi bu şekilde görsel içine kod yazmak yapısal düzen bakımından bozucu bir şey. Lojik ile görseli birbirine karıştırıyoruz. Ancak gerekli olduğu durumlarda böyle bir imkan olduğunu da bilelim.



İki yönlü bağlama

Daha önce görsel eleman değeri ile bir verinin bağlanmasını bind işlemi olarak görmüştük. Kafa karıştıranları silelim , görselimizi ve JavaScript kodumuzu basit bir hale getirip bu konuya başlayalım.

ilk/index.html
...
        <div id="app">
            <input type="text">
            <h3>{{ isim }}</h3>
        </div>
...


ilk/main.js
new Vue({
  el: "#app",
  data: {
    isim: "Ümit"
  }
});

İki yönlü bir bağlama yapmak istiyoruz. Hem input içine girilen değer isim değişkenine konsun ve sayfadaki yazı değişsin. Hem de kodumuz içinde bir yerde isim değişkeni değişince bu da input içine yazılsın.

...
        <div id="app">
            <input type="text" v-model="isim">
            <h3>{{ isim }}</h3>
        </div>
...

v-model deyimi input eleman değeri ve isim değişken değerini direk birbirine çift yönlü bağlıyor. Daha önceki gibi yok değer girişine olay izleme yaz , yok fonksiyon içinde olay.target.value deyip değere ulaşmaya çalış gibi şeylerin hepsini bu deyim otomatik olarak bizim adımıza yapacaktır.

Kod içinde değer değişiminin etkisini görmek için de bir buton ekleyelim.

...
        <div id="app">
            <input type="text" v-model="isim">
            <button @click="isim = 'Hasan';">Değiştir</button>
            <h3>{{ isim }}</h3>
        </div>
...




Hesaplanmış özellikler ile değişimlere tepki vermek

Şöyle de bir kodumuz olsun

ilk/index.html
...
        <div id="app">
            <button @click="arttır()">Arttır</button>
            <h3>Sayaç: {{ sayaç }}</h3>
            <h3>Sonuç: {{ sonuç }}</h3>
        </div>
...


ilk/main.js
new Vue({
  el: "#app",
  data: {
    sayaç: 0,
    sonuç: ""
  },
  methods: {
    arttır: function(){
      this.sayaç++;
      this.sonuç = this.sayaç > 5 ? "5'ten büyük" : "5'ten küçük";
    }
  }
});

Butona her tıklandığında sayaç değeri bir artacak, değer 5'ten büyükse sonuç değeri 5'ten büyük değilse sonuç değeri 5'ten küçük olacak. Basit (aslında eşit ya da küçük olmalı ya, neyse amaç öğrenmek).

Küçük kod parçalarında bu kolay yönetilebilir ve anlaşılabilir bir yöntem. Ama ilk olarak şuna dikkat edelim sayfa ilk geldiğinde butona tıklanmadan önce sonuç değerini göremiyoruz. Ya da diyelim bir tane de Azalt butonu ekledik, buna da bir metod yazdık

...
            <button @click="arttır()">Arttır</button>
            <button @click="azalt()">Azalt</button>
...


...
  methods: {
    arttır: function(){
      this.sayaç++;
      this.sonuç = this.sayaç > 5 ? "5'ten büyük" : "5'ten küçük";
    },
    azalt: function(){
      this.sayaç--;
      this.sonuç = this.sayaç > 5 ? "5'ten büyük" : "5'ten küçük";
    }
  }
...

Biz ne yapacağız? Sayfa yüklenince karşılaştırma yap, değer artırılınca karşılaştırma yap, azaltılınca karşılaştırma yap. Diyelim değeri 10'ar arttıran kod yazdık orada da sonuç değerini bulmak için karşılaştırma yap. Sonra da Allah kahretsin küçük ya da eşit yazmalıydık de tüm karşılaştırmaları tek tek bul değiştir. Bunu kökten çözmek için hesaplanmış özellikler vardır.

ilk/main.js
new Vue({
  el: "#app",
  data: {
    sayaç: 0
  },
  computed: {
    sonuç: function(){
      return (this.sayaç > 5 ? "5'ten büyük" : "5'ten küçük");
    }
  }
});

Artık butonlardan metod çağırmak yerine direk sayaç değerini değiştirebiliriz.

ilk/index.html
...
        <div id="app">
            <button @click="sayaç++;">Arttır</button>
            <button @click="sayaç--;">Azalt</button>
            <h3>Sayaç: {{ sayaç }}</h3>
            <h3>Sonuç: {{ sonuç }}</h3>
        </div>
...

computed bölümünde tanımlanan işlemler bağlı oldukları değişken değerlerinde bir değişim oldumu otomatikman devreye girip hesap yaparlar. Bu örnekte sayaç değeri değiştikçe otomatik olarak sonuç değeri de değişir. Ancak computed bölümünde yer alan değerler aynı data bölümündekiler gibi görselimizde kullanılabilir. Aynen kullanılabilir derken bir küçük ayrıntı var, computed bölümündeki değerler default olarak sadece okunan değerlerdir. Sayfaya {{ }} içinde yazarken sorun yok, v-bind ile bir elemanın değerini bağlarken de sorun yok. Ama v-model kullanınca bildiğimiz gibi iki yönlü bağlama oluyor, yani dışarıdan da hesaplanmış değer üzerine yazılabilmeli. Bu amaçla tanımlama yapılırken get ve set fonksiyonları ayrı ayrı tanımlanır. Bunu da ileride görürüz inşalllah..



Bir alternatif olarak watch

watch bölümünde değer değişimini izlemek istediğimiz data bölümü değişkenlerine ait görev fonksiyonları tanımlayabiliriz. Bu aslında yukarıda anlatılan ve computed kullanılan yapıya bir alternatif olarak kullanılabilir. Yani sayaç değişkeni izlemeye alınır ve değişim olunca sonuç değişkeni değeri belirlenir.

ilk/main.js
new Vue({
  el: "#app",
  data: {
    sayaç: 0,
    sonuç: ""
  },
  watch: {
    sayaç: function(değer){
      this.sonuç = değer > 5 ? "5'ten büyük" : "5'ten küçük";
    }
  }
});

Bu da sayfa ilk yüklendiği an hariç aynı etkiyi yapacaktır. Ama örneği başka bir şeyle geliştirelim. Diyelim değer değiştirildikten 3 saniye sonra sayaç değerini sıfır yapalım.

...
  watch: {
    sayaç: function(değer){
      this.sonuç = değer > 5 ? "5'ten büyük" : "5'ten küçük";
      var vm = this;
      setTimeout(function(){
        vm.sayaç = 0;
      },3000);
    }
  }
...

setTimeout bloğu içinden sayaç değerine ulaşabilmek için bloğa girmeden evvel this değişkenini vm değişkenine kopyaladık. Değer değişimi ile buraya gelindiği için eklediğimiz timeout , ilk değer değişiminden 3000 mili saniye sonra sayaç değerini sıfırlar.




CSS sınıflarıyla dinamik stil değiştirme

Bu konuyu işlemek için bir CSS stil dosyasına ihtiyacımız olacak. Uygulama klasörümüzde styles.css adında yeni bir text dosya tanımlayalım ve bunu index.html dosyamızdan çağıralım.

ilk/index.html
...
    <head>
        <title>VueJs Öğreniyorum</title>
        <script src="vue.js"></script>
        <link rel="stylesheet" type="text/css" href="styles.css">
    </head>
...

Görselimizin ve JavaScript dosyamızın başlangıç hali de şunlar olsun.

ilk/index.html
...
        <div id="app">
            <div class="demo"></div>
            <div class="demo"></div>
            <div class="demo"></div>
        </div>
...

ilk/main.js
new Vue({
  el: "#app"
});

Bu div elemanlarını kare şeklinde göstermek için stil dosyamızda şunları yazalım.

ilk/styles.css
.demo {
 width: 100px;
 height: 100px;
 background-color: gray;
 display: inline-block;
 margin: 10px;
}

Sayfa şöyle görünecektir.


Diyelim bu kareleri başka başka renkler yapmak isiyoruz. Bunu class değerlerine başka değerler ekleyerek yapabiliriz. Stil dosyamıza şu stillleri ekleyelim.

ilk/styles.css
...
.red {
 background-color: red;
}

.green {
 background-color: green;
}

.blue {
 background-color: blue;
}

Şimdi birinci kareyi kırmızı yapmak için class değerine ekleme yaparız.

...
        <div id="app">
            <div class="demo red"></div>
            <div class="demo"></div>
            <div class="demo"></div>
        </div>
...


Peki karenin rengini üzerine her tıklandığında değiştirmek istersek?

VueJs ile bu işi yapmak için ilk önce bir değişkende kırmızı olup olmadığını saklamak sonra da her tıklandığında bu değişken değerini ters çevirmek gerekiyor.

ilk/main.js
new Vue({
  el: "#app",
  data: {
    kırmızıEkle: false
  }
});

ilk/index.html
...
        <div id="app">
            <div 
                class="demo" 
                @click="kırmızıEkle = !kırmızıEkle;">
            </div>
            <div class="demo"></div>
            <div class="demo"></div>
        </div>
...

Sonra da class değerine dinamik olarak ilave yapmak için v-bind yapısını kullanırız.

...
            <div 
                class="demo" 
                @click="kırmızıEkle = !kırmızıEkle;"
                :class="{ red: kırmızıEkle }">
            </div>
...

Önce de söylediğimiz gibi :class ve v-bind:class aynı şeyi ifade eder. Burada ilave class olarak kırmızıEkle değişken değerine bağlı olarak red değeri girilmesini bir JavaScript kod ile sağlıyoruz. Burada v-bind:class deyimine bir JavaScript nesne gönderince değer true ise key ismi class olarak eklenir. Örnekle anlatsak daha iyi,

:class="{ red: kırmızıEkle, blue: maviEkle }"

Bunun da farkı yok aynı anlamda.

:class="{ 'red': kırmızıEkle, blue: maviEkle }"

Burada maviEkle değeri true ise class değerine blue eklenecektir, her iki değer de true ise hem red hem blue eklenecektir. Ayrıca eklenecek değeri tırnak içinde yazmak sadece gmrsel olarak bir anlam katar, isterseniz öyle kullanın.

Bir kırmızı bir mavi olsun istersek

:class="{ red: kırmızıEkle, blue: !kırmızıEkle }"

Görsel içinden bu kodu uzaklaştırmak için hesaplanmış değer de kullanabiliriz. Şöyle ki,

ilk/index.html
            <div 
                class="demo" 
                @click="kırmızıEkle = !kırmızıEkle;"
                :class="divClasses">
            </div>

ilk/main.js
  computed: {
    divClasses: function(){
      return {
        red: this.kırmızıEkle,
        blue: !this.kırmızıEkle
      }
    }
  }







İsim kullanarak dinamik stil değişimi

Data kısmında tanımlı bir değişken ismini de direk olarak :class deyimine değer olarak verebiliriz. Bir input ekleyelim ve orada hangi class değeri yazıyorsa o 3. kareye eklensin.

ilk/index.html
...
        <div id="app">
            <div 
                class="demo" 
                @click="kırmızıEkle = !kırmızıEkle;"
                :class="divClasses">
            </div>
            <div class="demo"></div>
            <div class="demo" :class="renk"></div>
            <hr>
            <input type="text" v-model="renk">
        </div>
...

ilk/main.js
new Vue({
  el: "#app",
  data: {
    kırmızıEkle: false,
    renk: "green"
  },
...

Şimdi input'a ne yazarsak o değer 3. kareye class olarak eklenecektir.


class değeri için array içinde kombinasyon da yapabiliriz. Mesela

<div class="demo" :class="[renk, { red: kırmızıEkle }]"></div>

Tabi bunu yaptık da burada bir CSS çakışması olacak. Stil dosyamızda green ve blue seçicileri daha sonra geldiği için red class değeri eklesek bile kırmızı olmayacaktır. Önce input içindeki değeri silip sonra 1. kareye tıklarsak 3. karenin de onunla beraber kırmızı yada gri olduğunu görürüz.





class olmadan stili dinamik olarak değiştirmek

Başa dönelim ve class olmadan stile müdahale etmek için bu sefer :style kelimesini kullanalım.

ilk/index.html
...
        <div id="app">
            <div class="demo"></div>
            <div class="demo"></div>
            <div class="demo"></div>
            <hr>
            <input type="text" v-model="renk">
        </div>
...

ilk/main.js
new Vue({
  el: "#app",
  data: {
    renk: "green"
  }
});

:style kelimesi kullanarak direk olarak arkaplan rengine şöyle müdahale edebiliriz.

        <div id="app">
            <div class="demo" :style="{ 'background-color': renk }"></div>
            <div class="demo"></div>
            <div class="demo"></div>
            <hr>
            <input type="text" v-model="renk">
        </div>

background-color yazısını tırnak içine aldık çünkü arasında tire işareti olan bir isim JavaScript'te kabul edilmez. Ama tırnak olmadan yazmak için bir kolaylık olarak Camel Case denen teknikle şöyle yazarsak da VueJs anlayacaktır.

<div class="demo" :style="{ backgroundColor: renk }"></div>


input kutusuna yazdığımız renk kareye arkaplan rengi olarak gelecektir. #0ff gibi sayı ile de renk verebiliriz, kutuya yazıp deneyin.

Stilimizde çok fazla değer olacaksa hesaplanmış değer kullanarak stilleri JavaScript kodumuz içinde daha düzenli görünecek şekilde verebiliriz.

ilk/index.html
...
        <div id="app">
            <div class="demo" :style="{ backgroundColor: renk }"></div>
            <div class="demo" :style="stilim"></div>
            <div class="demo"></div>
            <hr>
            <input type="text" v-model="renk">
        </div>
...

ilk/main.js
new Vue({
  el: "#app",
  data: {
    renk: "green",
    width: 100
  },
  computed: {
    stilim: function(){
      return {
        backgroundColor: this.renk,
        width: this.width + "px"
      };
    }
  }
});

width değerini girmek için bir input daha ekleyelim görsele

            <input type="text" v-model="renk">
            <input type="text" v-model="width">






Array ile stil vermek

:style değerlerini de bir array içinde kombinasyon yapabiliriz. 3. kutuya da bunu yapalım.

<div class="demo" :style="[stilim, { height: width + 'px' }]"></div>


DOM etkileşimleri bölümü burada bitiyor. Çok şey gördük masallah. Görsellerin baya tozunu attık. Şimdi yeni bir bölüme geçiyoruz.







Koşullar ve Listeler


Bu bölümde görsellerin yayınlanmasında koşulları ve listeleri kullanarak yapabileceklerimizi göreceğiz.


v-if ile koşula göre yayınlama

Artık yeni bir klasöre önceki dosyaları kopyalayıp baştan bu bölüme başlayalım. Daha önce ilk adında bir klasörde yaptıklarımızı toplamıştık, bir kopyasını oluşturup bu klasöre de koşullar adını verelim de bir değişiklik gibi olsun. Hep aynı klasörde silip silip yazdıkça sanki bir şey yapmıyormuşuz gibi geliyor. Başlangıç olarak görselimize scriptimize şunları yazalım.

koşullar/index.html
...
        <div id="app">
            <h3>Beni görebilirsin!</h3>
            <h3>Beni de görebilir misin?</h3>
        </div>
...

koşullar/main.js
new Vue({
  el: "#app",
  data: {
    göster: true
  },
});

Sayfayı tarayıcı da açtığımızda iki satır yazı görünecektir. Bazen bir kısım görseli belli koşullara bağlı olarak göstermek ya da gizlemek isteyebiliriz. Örneğin bir hata mesajı, bir değeri değiştirmek için yanında input açmak, belli koşullara göre değişik işler yapan butonları göstermek ya da yok etmek gibi.

Örenk olarak burada ilk satırın göster değişkeni değerine göre görünmesini istiyorsak,

koşullar/index.html
...
        <div id="app">
            <h3 v-if="göster">Beni görebilirsin!</h3>
            <h3>Beni de görebilir misin?</h3>
            <button @click="göster = !göster">Değiştir</button>
        </div>
...

v-if VueJs kelimesine verilen göster değeri true ise ilk satır görünür. En alta da bir buton ekleyerek göster değişkeni değerini değiştirip test edebiliriz.


Örnek resim göster değişken değeri false iken olan sayfa görünümünü veriyor. Dikkatinizi çekmek istediğim bir nokta var. Geliştirici araçları penceresinde elemanları incelersek her iki satır da görünürken bir div ve içinde 2 tane h3 elemanı olacaktır. Ama butona tıkladığımızda elemanları şöyle görürüz.


<!----> şeklinde boş bir HTML yorum elemanı olarak görünen şey aslında VueJs'in bize burada birşeyler vardı ama ben onları bir sebepten dolayı uçurdum mesajıdır.

Önemli bir konu da v-if elemanı görünür veya görünmez yapmıyor. Komple sayfaya ekliyor ya da DOM listesinden elemanı yok ediyor. Hani bazen elemanı stilinde display: none yaparak görünmez yaparız ama hala orada duruyordur. Bu öyle değil tamamen eleman DOM'dan çıkarılıyor.

v-if olur da tamamlayıcısı v-else olmaz mı? Görsele bir satır daha ekleyelim.

koşullar/index.html
...
        <div id="app">
            <h3 v-if="göster">Beni görebilirsin!</h3>
            <h3 v-else>Şimdi de beni görebilirsin!</h3>
            <h3>Beni de görebilir misin?</h3>
            <button @click="göster = !göster">Değiştir</button>
        </div>
...

v-else kendinden önce yazılan en son v-if ile verilen koşul geçersiz ise çalışır.


Alternatif v-if satırı kullanmak

Yeri gelmişken bahsedelim. eğer HTML kod içinde template tag kullanırsak bu elemanlar listesinde görünmeyecektir. Örneğin,

        <div id="app">
            <h3 v-if="göster">Beni görebilirsin!</h3>
            <h3 v-else>Şimdi de beni görebilirsin!</h3>
            <template>
                <h3>Template içi yazı</h3>
            </template>
            <h3>Beni de görebilir misin?</h3>
            <button @click="göster = !göster">Değiştir</button>
        </div>


template kullanarak bir çok elemanı başka bir görsel eleman içine koymadan bir çok elemanı tek bir v-if ile görünmez yapabiliriz. Mesela

            <template v-if="göster">
                <h1>Başlık</h1>
                <h3>Template içi yazı</h3>
            </template>




v-show kullanarak gizlemek

v-show kullanarak v-if gibi elemanı tamamen DOM'dan çıkarmadan sadece stilini değiştirerek görünmez yapabiliriz. Ama eleman hala orada olacaktır.

        <div id="app">
            <h3 v-if="göster">Beni görebilirsin!</h3>
            <h3 v-else>Şimdi de beni görebilirsin!</h3>
            <h3 v-show="göster">Beni de görebilir misin?</h3>
            <button @click="göster = !göster">Değiştir</button>
        </div>


style="display: none;" ile eleman görünmez yapılmış. Ama hala DOM içinde duruyor. Programımızda bir yerlerde eleman görünmez olsa da hala DOM elemanı olarak etkileşimde bulunmamız gerekiyorsa v-if yerine v-show kullanmak gerekir.



v-for kullanarak listeleri göstermek

Sayfamızı boşaltarak başlayalım.

koşullar/index.html
...
        <div id="app">
            
        </div>
...

koşullar/main.js
new Vue({
  el: "#app",
  data: {
    yiyecekler: ["Et", "Meyve", "Kurabiye"],
    kişiler: [
     {isim: "Ümit", yaş: 54, renk: "red"},
     {isim: "Alp", yaş: "bilinmiyor", renk: "blue"}
    ]
  }
});

Bu sefer görselimiz boş ama bir sürü verimiz var. Bir yiyecekler listesi, bir kişiler listesi ki her bir elemanı bir obje oluyor. Niye böyle başladık? Çünkü listelerle görsel oluşturmayı göreceğiz.

v-for kullanarak yiyecekler listesini yayınlayalım,

        <div id="app">
            <ul>
                <li v-for="yiyecek in yiyecekler">{{ yiyecek }}</li>
            </ul>
        </div>

v-for yapısı bir array içindeki her eleman için birer kez çalışır. Burada yiyecek in yiyecekler şekli ile yiyecekler listesindeki her değer için bir li elemanı üretilir. Her turda o andaki değer yiyecek adında geçici bir değişkene yüklenir.


Liste değerleri yanında index değerlerini de alıp kullanabiliriz.

koşullar/index.html
...
        <div id="app">
            <ul>
                <li v-for="(yiyecek, index) in yiyecekler">
                    {{ yiyecek }} ({{ index }})
                </li>
            </ul>
        </div>
...


Tabi bu index değeri sadece böyle rakam olarak göstermek için alınmıyor. İleride daha gelişmiş kodlar yazarken bize çok faydalı olabilecek bir özellik. Parantez içinde ilk yazılan, elemanın değerinin konacağı değişken adı, ikinci ise index değerinin konacağı değişken adı olmalıdır.



Alternatif v-for deyimi

Daha önce v-if deyiminde gördüğümüz gibi burada da template elemanı kullanarak birden fazla elemandan oluşan bir grup yayınlaması yapabiliriz.

koşullar/index.html
...
                <template v-for="(yiyecek, index) in yiyecekler">
                    <h2>{{ yiyecek }}</h2>
                    <p>{{ index }}</p>
                </template>
...




Nesneler üzerinden döngü yapmak

Nesneler üzerinden de v-for döngüsü yapılabilir.

...
        <div id="app">
            <ul>
                <li v-for="kişi in kişiler">{{ kişi.isim }}</li>
            </ul>
        </div>
...


Bunda pek matah bir şey göremedik. Ama bildiğimiz gibi burada kişi değişkeni bir nesne ve v-for kullanarak onun da elemanları üzerinden döngü yapabiliriz.

koşullar/index.html
...
            <ul>
                <li v-for="kişi in kişiler">
                    <span v-for="değer in kişi">{{ değer }} </span>
                </li>
            </ul>
...


array içinde döngü yaparken index değerini aldığmız gibi nesne üzerinde döngü yaparken bu sefer key değerini alabiliriz.

...
<ul>
    <li v-for="kişi in kişiler">
        <div v-for="(değer, key) in kişi">{{ key }}: {{ değer }}</div>
    </li>
</ul>
...


Yetmedi nesne içinde de index değerini alabiliriz.

...
<ul>
    <li v-for="kişi in kişiler">
        <div v-for="(değer, key, index) in kişi">
            {{ key }}: {{ değer }} ({{ index }})
        </div>
    </li>
</ul>
...



Sayı dizisi üzerinde çevrim

Tamamen değişkenlerden bağımsız olarak sayılar üzerinden de çevrim yapabiliriz.

...
<span v-for="n in 10">{{ n }}</span>
...








Bir Oyun Yazalım


Bu bölüm için eğitmenin verdiği koda hiç bakmadan benim sadece çalışmasına bakarak kafadan yaptığım örneği şurada çalışırken görebilirsiniz. Tavsiyem siz de sadece uygulamanın çalışmasına bakarak kendi çözümünüzü oluşturun sonra hep beraber eğitmenin örneği ile karşılaştıralım.




Gelelim öğretmen nasıl yapmış. İlk önce bir yeni klasör yapmış uygulama için ve içine stiller için css adında bir alt klasör eklemiş. CSS dosyası olarak 2 dosya var bu klasörde biri kendi yazdığımız stilller için app.css dosyası, biri de yerleşimle uğraşmamak adına hazır kullanılan foundation.css kütüphanesi. Bu kütüphaneyi buradan benim drive dosyalarımdan indirebilirsiniz.

Uygulama klasörümüzde index.html dosyamıza şunları yazalım.

app/index.html
<!DOCTYPE html>
<html>
<head>
    <title>Yaratık Katili</title>
    <script src="https://npmcdn.com/vue/dist/vue.js"></script>
    <link rel="stylesheet" href="css/foundation.min.css">
    <link rel="stylesheet" href="css/app.css">
</head>
<body>
<div id="app">
    <section class="row">
        <div class="small-6 columns">
            <h1 class="yazı-ortada">SEN</h1>
            <div class="sağlıkbar">
                <div class="sağlıkbar yazı-ortada" style="background-color: green; margin: 0; color: white;">

                </div>
            </div>
        </div>
        <div class="small-6 columns">
            <h1 class="yazı-ortada">YARATIK</h1>
            <div class="sağlıkbar">
                <div class="sağlıkbar yazı-ortada" style="background-color: green; margin: 0; color: white;">

                </div>
            </div>
        </div>
    </section>
    <section class="row butonlar">
        <div class="small-12 columns">
            <button id="oyun-başlat">YENİ OYUN BAŞLAT</button>
        </div>
    </section>
    <section class="row butonlar">
        <div class="small-12 columns">
            <button id="saldır">SALDIR</button>
            <button id="özel-saldırı">ÖZEL SALDIRI</button>
            <button id="iyileş">İYİLEŞ</button>
            <button id="vazgeç">VAZGEÇ</button>
        </div>
    </section>
    <section class="row kayıtlar">
        <div class="small-12 columns">
            <ul>
                <li>

                </li>
            </ul>
        </div>
    </section>
</div>
</body>
</html>

css klasörü içindeki app.css dosyamıza da şu stillleri yazalım.

app/css/app.css
.yazı-ortada {
    text-align: center;
}

.sağlıkbar {
    width: 80%;
    height: 40px;
    background-color: #eee;
    margin: auto;
    transition: width 500ms;
}

.butonlar, .kayıtlar {
    margin-top: 30px;
    text-align: center;
    padding: 10px;
    border: 1px solid #ccc;
    box-shadow: 0px 3px 6px #ccc;
}

.turn {
    margin-top: 20px;
    margin-bottom: 20px;
    font-weight: bold;
    font-size: 22px;
}

.kayıtlar ul {
    list-style: none;
    font-weight: bold;
    text-transform: uppercase;
}

.kayıtlar ul li {
    margin: 5px;
}

.kayıtlar ul .player-turn {
    color: blue;
    background-color: #e4e8ff;
}

.kayıtlar ul .monster-turn {
    color: red;
    background-color: #ffc0c1;
}

button {
    font-size: 20px;
    background-color: #eee;
    padding: 12px;
    box-shadow: 0 1px 1px black;
    margin: 10px;
}

#oyun-başlat {
    background-color: #aaffb0;
}

#oyun-başlat:hover {
    background-color: #76ff7e;
}

#saldır {
    background-color: #ff7367;
}

#saldır:hover {
    background-color: #ff3f43;
}

#özel-saldırı {
    background-color: #ffaf4f;
}

#özel-saldırı:hover {
    background-color: #ff9a2b;
}

#iyileş {
    background-color: #aaffb0;
}

#iyileş:hover {
    background-color: #76ff7e;
}

#vazgeç {
    background-color: #ffffff;
}

#vazgeç:hover {
    background-color: #c7c7c7;
}




Bu şekilde uygulama görselinin bir iskeletini oluşturarak başlıyoruz. Script için app.js adında bir dosya ekleyelim klasörümüze. Sonra da bu dosyayı index.html dosyamızdan çağıralım.

...
<script src="app.js"></script>
</body>
</html>

Önce temel Vue oluşum nesnesi ile başlayalım.

app/app.js
new Vue({
 el: "#app"
});

Data bölümünde neler olacak? Bir bakışta gördüğümüz oyuncunun ve yaratığın sağlık seviyeleri.

new Vue({
    el: "#app",
    data: {
        oyuncuSağlık: 100,
        yaratıkSağlık: 100
    }
});

Hem butonların gösterimi hem de oyun kontrolü için oyunun çalışmakta olduğuna dair bir veri de olsa iyi olur.

    data: {
        oyuncuSağlık: 100,
        yaratıkSağlık: 100,
        çalışıyor: false
    }

Sağlık göstergelerinden başlayalım. Genişliğin orantılı olarak değişmesi ve üzerinde sağlık değerinin yazması için. HTML görseli şöyle yaparız.

    <section class="row">
        <div class="small-6 columns">
            <h1 class="yazı-ortada">SEN</h1>
            <div class="sağlıkbar">
                <div class="sağlıkbar yazı-ortada" 
                    style="background-color: green; margin: 0; color: white;"
                    :style="{ width: oyuncuSağlık + '%' }">
                    {{ oyuncuSağlık }}
                </div>
            </div>
        </div>
        <div class="small-6 columns">
            <h1 class="yazı-ortada">YARATIK</h1>
            <div class="sağlıkbar">
                <div class="sağlıkbar yazı-ortada" 
                    style="background-color: green; margin: 0; color: white;"
                    :style="{ width: yaratıkSağlık + '%' }">
                    {{ yaratıkSağlık }}
                </div>
            </div>
        </div>
    </section>

Artık sağlık değerleri değiştikçe yeşil barların üzerindeki yazı ve genişlikleri otomatik olarak değişecek.



Koşullara göre butonları göstermek

Buton gruplarımızı section tag'leri içine koyduk. Bunların hangisinin görüneceğini v-if yönlendiricisini kullanarak belirleriz. çalışıyor değeri false iken YENİ OYUN BAŞLAT butonunun olduğu section görünür olacak, çalışıyor değeri true iken diğer oyun oynamasına ait butonların bulunduğu section görünür olacak.

app/index.html
...
    <section class="row butonlar" v-if="!çalışıyor">
        <div class="small-12 columns">
            <button id="oyun-başlat">YENİ OYUN BAŞLAT</button>
        </div>
    </section>
    <section class="row butonlar" v-if="çalışıyor">
        <div class="small-12 columns">
            <button id="saldır">SALDIR</button>
            <button id="özel-saldırı">ÖZEL SALDIRI</button>
            <button id="iyileş">İYİLEŞ</button>
            <button id="vazgeç">VAZGEÇ</button>
        </div>
    </section>
...

İkinci v-if yerine v-else kullanarak kestirmeden gidebilirdik ama böyle daha açıklayıcı oldu bence. Artık sayfayı yenileyince sadece YENİ OYUN BAŞLAT butonu görünecektir.


Tabii ki buton henüz hiç bir iş yapmıyor.


Oyunu Başlat metodu

Önce buton tıklama olayına metodu bağlayarak başlayalım.

app/index.html
...
    <section class="row butonlar" v-if="!çalışıyor">
        <div class="small-12 columns">
            <button id="oyun-başlat" @click="oyunuBaşlat()">YENİ OYUN BAŞLAT</button>
        </div>
    </section>
...

oyunuBaşlat metodu içinde neler olacak? İlk akla gelen çalışıyor değeri true olacak ve oyun oynama butonları görünür olacak. Ayrıca yeni bir oyuna başlarken oyuncu ve yaratık sağlık değerlerini %100'den başlatmalıyız. Bu doğrultuda JavaScript kodumuza şunları ekleriz.

app/app.js
...
    },
    methods: {
        oyunuBaşlat: function(){
            this.çalışıyor = true;
            this.oyuncuSağlık = 100;
            this.yaratıkSağlık = 100;
        }
    }
});

Sayfayı yenileyip butona tıkladığımızda artık oyun oynama butonları görünecektir.


Oyun artık çalışmaya başladı. Şimdi bu butonlara bir kodlar yazarak tarafların birbirini dövmelerini sağlamalıyız.



saldır metodunun yazılması

Dört oyun butonu için tıklama olaylarına metod isimleri tanımlayarak başlayalım.

app/index.html
...
    <section class="row butonlar" v-if="çalışıyor">
        <div class="small-12 columns">
            <button id="saldır" @click="saldır()">SALDIR</button>
            <button id="özel-saldırı" @click="özelSaldırı()">ÖZEL SALDIRI</button>
            <button id="iyileş" @click="iyileş()">İYİLEŞ</button>
            <button id="vazgeç" @click="vazgeç()">VAZGEÇ</button>
        </div>
    </section>
...

Bu 4 metodu içleri boş olarak JavaScript'imize ekleyelim.

app/app.js
...
    methods: {
        oyunuBaşlat: function(){
            this.çalışıyor = true;
            this.oyuncuSağlık = 100;
            this.yaratıkSağlık = 100;
        },
        saldır: function(){

        },
        özelSaldırı: function(){

        },
        iyileş: function(){

        },
        vazgeç: function(){
            
        }
    }
...

Biraz mantığı düşünelim. vazgeç metodu hariç diğerlerinde yaratık oyuncuya zarar verir. saldır metodunda oyuncu da yaratığa zarar verir. özelSaldırı metodunda oyuncu yaratığa daha fazla zarar verir. iyileş metodunda oyuncu sağlığı yükselirken yaratık zarar vermeye devam eder. vazgeç metodunda ise oyuncuya yeni oyun başlatma isteği sorulacak.

saldır metoduyla başlayalım. İlk yapılacak şey karşıya verilecek zararların hesaplanması. Bu zarar alt ve üst sınırlarını vereceğimiz bir rastgele değer olmalı.

...
        saldır: function(){
            var max = 10;
            var min = 3;
            var zarar = Math.max(Math.floor(Math.random() * max) + 1, min);
        },
...

Math.random fonksiyonu 0 ile 0.99999.. arasında rastgele bir sayı üretir. Bunu max değeri olan 10 ile çarparsak 0 ile 9.99.. arası bir sayı elde ederiz. Math.floor fonksiyonu ise bu değerin sadece tamsayı kısmını bize verir. Böylece 0-9 arası bir tamsayı elde ederiz. Buna 1 ekleyerek 1-10 arası bir tamsayı elde ederiz. Math.max fonksiyonu ise parametresinde verilen 2 değerden hangisi büyükse onu geri döner. Bu durumda rastgele sayımız 1 ya da 2 çıkarsa min değeri olan 3 geri dönerek en az 3 değeri çıkması sağlanır.

Bu rastgele hesaplanan değerle yaratığa zarar verelim. Daha sonra benzer şekilde oyuncuya zarar veren bir rastgele miktar da hesaplayalım ama bu biraz daha fazla olsun, ne de olsa yaratık vuruyor.

app/app.js
...
        saldır: function(){
            var max = 10;
            var min = 3;
            var zarar = Math.max(Math.floor(Math.random() * max) + 1, min);
            this.yaratıkSağlık -= zarar;

            max = 12;
            min = 5;
            zarar = Math.max(Math.floor(Math.random() * max) + 1, min);
            this.oyuncuSağlık -= zarar;            
        },
...

Aynı kodları 2 defa tekrarladık DRY tekniğine (Don't Repeat Yourself) uymadı düzenlemek lazım. Ama önce bir çalıştıralım. Sayfayı yenilediğimizde artık SALDIR butonuna tıkladıkça her iki tarafa da rastgele zararlar vermeye başladı. Ama işin sonu yok. Butona basmaya devam ettikçe sağlık değeri eksiye düşse bile devam ediyor. Bunun kontrol edilip sağlık değeri eksiye düşenin ölmesini sağlamalıyız.

app/app.js
...
        saldır: function(){
            var max = 10;
            var min = 3;
            var zarar = Math.max(Math.floor(Math.random() * max) + 1, min);
            this.yaratıkSağlık -= zarar;

            if (this.yaratıkSağlık <= 0){
                alert("Sen Kazandın!");
                this.çalışıyor = false;
                return;
            }

            var max = 12;
            var min = 5;
            var zarar = Math.max(Math.floor(Math.random() * max) + 1, min);
            this.oyuncuSağlık -= zarar;            

            if (this.oyuncuSağlık <= 0){
                alert("Kaybettin!");
                this.çalışıyor = false;
            }
        },
...

Yaratık sağlığını kontrol edip eğer sıfır ya da altında bir değerse bir mesaj ile oyuncunun kazandığını bildiriyoruz. Sonra çalışıyor değerini false yaparak YENİ OYUN BAŞLAT butonunun görünmesini sağlıyoruz. return ile fonksiyonu yarıda kesip çıkmasını sağlıyoruz. Çünkü kod aşağı devam edip oyuncuya da bir zarar verir ve oyuncu sağlığı da sıfır ya da altına düşerse iki tarafında kazandığı ya da kaybettiği bir durum ortaya çıkacak.


Ama olmaz ki yaratık çok zarar veriyor hep oyuncu kaybediyor. Oyuncunun kabiliyetlerini arttırmak lazım.

Şimdi Refactor zamanı kodumuzu biraz düzenleyelim, fazla dağılmadan.

Önce zarar hesabını bir fonksiyona atalım,

app/app.js
...
    methods: {
...
        saldır: function(){
            this.yaratıkSağlık -= this.zararHesapla(3, 10);

            if (this.yaratıkSağlık <= 0){
                alert("Sen Kazandın!");
                this.çalışıyor = false;
                return;
            }

            this.oyuncuSağlık -= this.zararHesapla(5, 12);            

            if (this.oyuncuSağlık <= 0){
                alert("Kaybettin!");
                this.çalışıyor = false;
            }
        },
...
        zararHesapla: function(min, max){
            return Math.max(Math.floor(Math.random() * max) + 1, min);
        }
    }
...

Şimdi de oyunun bittip bitmediğini başka bir metod ile belirleyelim. Bu kontrol diğer butonlarda da lazım olacak, tekrar tekrar yazmayalım. Bir de ilave yapalım ve oyuncuya sonucu bildirirken yeni bir oyun isteyip istemediğini soralım.

...
        saldır: function(){
            this.yaratıkSağlık -= this.zararHesapla(3, 10);
            if (this.kazananKontrolü()){
                return;
            }

            this.oyuncuSağlık -= this.zararHesapla(5, 12);            
            this.kazananKontrolü();
        },
...
        kazananKontrolü: function(){
            if (this.yaratıkSağlık <= 0){
                if (confirm("Sen Kazandın! Yeni oyun?")){
                    this.oyunuBaşlat();
                } else {
                    this.çalışıyor = false;
                }
                return true;
            } else if (this.oyuncuSağlık <= 0){
                if (confirm("Kaybettin! Yeni oyun?")){
                    this.oyunuBaşlat();
                } else {
                    this.çalışıyor = false;
                }
                return true;
            }
            return false;
        }
...


confirm ile bir soru penceresi açılır ve kullanıcı burada Tamam butonuna tıklarsa geriye true değeri döner. Kullanıcı Tamam butonunu tıklarsa zaten daha önce yazmış olduğumuz oyunuBaşlat metodunu çağırarak yeni bir oyun başlatıyoruz. İptal ederse çalışıyor bilgisini false yaparak YENİ OYUN BAŞLAT butonunun görünmesini sağlıyoruz.


Özel Saldırı metodunu yazalım

Bu metod içinde saldır metodunda yapılanları yapacağız ama oyuncunun yarattığı zararın daha büyük olmasını sağlamak için sınırlarını büyüteceğiz.

...
        özelSaldırı: function(){
            this.yaratıkSağlık -= this.zararHesapla(10, 20);
            if (this.kazananKontrolü()){
                return;
            }

            this.oyuncuSağlık -= this.zararHesapla(5, 12);            
            this.kazananKontrolü();
        },
...

Yaratığın oyuncuya verdiği zararı aynı tuttuk. Burada da bir kod kopyalaması oldu. Yaratığın verdiği zarar kısmı aynı olduğu için bir metodda toplayalım.

...
        saldır: function(){
            this.yaratıkSağlık -= this.zararHesapla(3, 10);
            if (this.kazananKontrolü()){
                return;
            }

            this.yaratıkSaldırır();
        },
        özelSaldırı: function(){
            this.yaratıkSağlık -= this.zararHesapla(10, 20);
            if (this.kazananKontrolü()){
                return;
            }

            this.yaratıkSaldırır();
        },
...
        yaratıkSaldırır: function(){
            this.oyuncuSağlık -= this.zararHesapla(5, 12);            
            this.kazananKontrolü();
        },
...

Oyuncu artık ÖZEL SALDIRI butonuna basarak yaratığa çok daha fazla zarar verebilir. Böyle olunca da hep oyuncu kazanıyor rahatça. Ben kendi versiyonumda bu butona 5 turda sadece 1 kez tıklama izni vermiştim mesela.


iyileş metodu yazılması

Zarar görmenin rastgele değerlerle olması aksine iyileşmede %10 bir sağlık artışı sağlayacağız. Bu arada yaratık da saldırmaya ve zarar vermeye devam ediyor olacak. 

app/app.js
...
        iyileş: function(){
            this.oyuncuSağlık += 10;
            this.yaratıkSaldırır();
        },
...

İyileşme işlemi de tamam gibi. Ancak bu butona istediğimiz zaman basabiliyoruz. Bu durumda sağlığımız tamken de bassak değer artmaya devam ediyor.


...
        iyileş: function(){
            if (this.oyuncuSağlık <= 90){
                this.oyuncuSağlık += 10;
            } else {
                this.oyuncuSağlık = 100;
            }
            this.yaratıkSaldırır();
        },
...

Oki doki, bunu da hallettik.

Dikkat ettiniz mi, VueJs nasıl da bize sağladığı imkanlar ile kodumuzu hem kolay hakim olunabilir hem de parça parça parça adımlarla çok daha kısa kodlarla yapmamızı sağlıyor. Bu kod salt JavaScript ile de yazılırdı ama DOM elemanları ve değerlerini güncellemeler ile o kadar uğraşırdık ki kodumuz çorbaya dönerdi. Halbuki VueJs'in bize sağladığı imkanlar ile biz sadece değişken değerleri ile ilgileniyoruz DOM elemanları ile etkileşimi ise sadece başlangıçta bir tarif ettik gerisini VueJs yapıyor.


Aksiyon butonlarımızı bitirelim

Aslında vazgeç metodu içinde yapılacak iş sadece çalışıyor değerinin false yapılması ama butona kazara basılırsa diye bir confirm ile oyuncudan emin olmasını isteyebiliriz. 

app/app.js
...
        vazgeç: function(){
            if (confirm("Oyundan çıkmak istiyor musun?"))
                this.çalışıyor = false;
        },
...


Bu projenin son bulması için yapılacak tek şey kaldı, aşağıdaki bölüme mesajlar yazarak oyuncuyu bilgilendirmek.



Aksiyon log yazılımı

Bu amaçla ilk önce mesajları içeren bir array tanımını data bölümüne ekleriz ve buna yapacağımız ilaveler ile mesajlar gösterilir. 

app/app.js
...
    data: {
        oyuncuSağlık: 100,
        yaratıkSağlık: 100,
        çalışıyor: false,
        mesajlar: []
    },
...

Oyuncu saldırdığında onun saldırdığını ve verdiği zararın miktarını mesajlar içine eklememiz gerekiyor. saldır metodunu şöyle değiştirelim,

...
        saldır: function(){
            var zarar = this.zararHesapla(3, 10)
            this.yaratıkSağlık -= zarar;
            this.mesajlar.unshift({
                oyuncuMu: true,
                yazı: "Oyuncu yaratığa " + zarar + " zarar verdi"
            });
            if (this.kazananKontrolü()){
                return;
            }

            this.yaratıkSaldırır();
        },
...

yaratıkSaldırır metodu içinde de yaratığın oyuncuya verdiği zararı kaydetmeliyiz.

...
        yaratıkSaldırır: function(){
            var zarar = this.zararHesapla(5, 12)
            this.oyuncuSağlık -= zarar;            
            this.kazananKontrolü();
            this.mesajlar.unshift({
                oyuncuMu: false,
                yazı: "Yaratık oyuncuya " + zarar + " zarar verdi"
            });
        },
...

oyuncuMu değeri burada false olarak bu mesajın oyuncunun değil yaratığın verdiği zarara ait olduğunu gösteriyor. Bu bilgiyi görselde renklendirmek için kullanacağız. unshift ile array'in en başına eleman eklenir böylece gösterimde en başa en son mesaj gelecek.

Mesajları topladık, sıra geldi görselde bunları göstermeye.



v-for ile görsele mesajları listelemek

index.html dosyamız içinde bu yazıları koymak için bir unordered list koyduk. Basit bir şekilde mesajları v-for döngüsü ile şöyle yayınlayabiliriz. 

app/index.html
...
            <ul>
                <li v-for="mesaj in mesajlar">
                    {{ mesaj.yazı }}
                </li>
            </ul>
...


Mesajlar gelmeye başladı. Yalnız özel saldırı için mesaj eklemeyi unutmuşuz. Şimdi buna biraz stil katalım. Önce mesaj yoksa bu section elemanını göstermeyerek başlayalım.

...
    <section class="row kayıtlar" v-if="mesajlar.length">
        <div class="small-12 columns">
            <ul>
                <li v-for="mesaj in mesajlar">
                    {{ mesaj.yazı }}
                </li>
            </ul>
        </div>
    </section>
...

mesajlar array'i uzunluğu sıfırsa yani mesaj yoksa bu section görünmeyecektir.



Mesaj kayıtlarını bitirelim

Önce özelSaldırı metoduna mesaj ekleyerek başlayalım,

app/app.js
...
        özelSaldırı: function(){
            var zarar = this.zararHesapla(10, 20)
            this.yaratıkSağlık -= zarar;
            this.mesajlar.unshift({
                oyuncuMu: true,
                yazı: "Oyuncu yaratığa " + zarar + " büyük zarar verdi"
            });
            if (this.kazananKontrolü()){
                return;
            }

            this.yaratıkSaldırır();
        },
...

iyileş metodu içine de iyileşme miktarını belirten mesaj eklemeliyiz.

...
        iyileş: function(){
            if (this.oyuncuSağlık <= 90){
                this.oyuncuSağlık += 10;
            } else {
                this.oyuncuSağlık = 100;
            }
            this.mesajlar.unshift({
                oyuncuMu: true,
                yazı: "Oyuncu 10 birim iyileşti"
            });
            this.yaratıkSaldırır();
        },
...

ayrıca yeni oyun başlarken mesajları da boşaltmamız gerekir.

...
        oyunuBaşlat: function(){
            this.çalışıyor = true;
            this.oyuncuSağlık = 100;
            this.yaratıkSağlık = 100;
            this.mesajlar = [];
        },
...

Sıra geldi mesajları renklendirmeye.


Mesajları koşula göre renklendirme

CSS dosyamızda player-turn ve moster-turn adında 2 stil mevcut. Bunları kullanacağız. 

app/index.html
...
                <li v-for="mesaj in mesajlar"
                    :class="{ 'player-turn': mesaj.oyuncuMu, 'monster-turn': !mesaj.oyuncuMu }">
                    {{ mesaj.yazı }}
                </li>
...


İşte bu kadar! Gördüğünüz gibi bir uygulamayı VueJs ile oluşturmak ve üzerinde hakimiyet kurmak bu kadar kolay.

Bu yazıyı şimdilik burada kesip yayınlayalım Ama devam edecek inşallah. Daha öğreneceklerimiz var.

Kalın sağlıcakla..










Hiç yorum yok:

Yorum Gönder