Vue 3

Makale İçerik Listesi

Laravel için UI/Vue Scaffolding Kurulumu

  1. composer require laravel/ui
  2. php artisan ui vue
  3. Böyle yapında script tag'imizin olduğu sayfalarda #app container'i içerisinde Vue componentleri kullanabiliriz.
  4. Vue3'nin bootstrap.js dosyası ve Vue initialization biraz daha farklı
  5. Vue 3 kullanmak için bu scaffoldingi yaptıktan sonra da yine de npm install vue@next laravel-mix@next dememiz lazım.
  6. bootstrap.js dosyasındaki window.Vue referanslarını ve Vue'ye bağlı şeyleri siliyorum.
  7. app.js dosyası aşağıdaki bölümde olduğu gibi olacak.

Laravel'de Vue Kullanmaya Başlamak

  1. Öncelikle projemizde Vue kullanmak için npm install vue@next diyerek Vue3ü yükleyelim.
  2. Laravel Mix'in son sürümü de olmalı (zaten vardır ama) npm install laravel-mix@next
  3. Vue ile çalışmak için sayfanın script dosyası olan ex. app.js'i webpack'te Vue olarak compile edilmesi gerektiğini Webpack.mix.js dosyasında belirtmen lazım. 
    mix.js('resources/js/app.js', 'public/js')
        .vue(3)
        .version()
        .disableNotifications();
  4. Sonrasında ana script dosyamızda Vue'yu başlatıyoruz. app.js 
    require('./bootstrap');
    
    import { createApp } from 'vue';
    import App from './components/App.vue';
    
    createApp(App).mount('#app');
  5. Bunu yaptıktan sonra compile ettirmek için npm run dev veya npm run prod veya npm run watch diyebilirim.
  6. Bundan sonra tabii ki sayfada aktif olması için öncelikle scripti sayfada çalıştır ve #app template'ini belirt. 
    <div id="app" class="container"></div>
    <script src="{{ mix('js/app.js') }}"></script>

Laravel'de Vue'yu Yer Yer Kullanmak

  1. Laravel'de ana Div'e #app ID'si verdikten sonra birbirlerinden habersiz Vue componentleri oluşturabilir, bunları nerede istersek oraya ekleyerek kullanabiliriz.
  2. Bunun için yine npm install vue@latest && npm install --save-dev vue-loader@next diyerek öncelikle Vue'yu ve Vue Loader'ı projemize ekleyelim.
  3. Vue'yu çalıştıracak app.js dosyasını webpack.mix.js dosyasında Vue'yu da algılayacak şekilde belirtelim. webpack.mix.js 
    mix.js('resources/js/app-vue.js', 'public/js').vue().version().disableNotifications();
  4. resources/js içinde .vue ile biten bütün dosyaları bulup onları birer Vue Component olarak register edecek kodu yaz app-vue.js içersine yaz. 
    // burada axios'da eklenir ve çalıştırılır
    require('./bootstrap');
    
    import Vue from 'vue';
    
    const files = require.context('./', true, /\.vue$/i);
    files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default));
    
    Vue.config.productionTip = false
    
    // ID'si app olan container element'i bir Vue container'ına dönüşür.
    const app = new Vue({
        el: '#app'
    })
  5. Bu yapıldıktan sonra resource içindeki componentler aynı şekilde uygulama içinde çalışır hale gelir. Ör. resources/js/components/ExampleComponent.vue diye bir Vue component'imiz olsa... 
    <template>
        <div>
            <form>
                <input type="search" name="q" autocomplete="off" class="form-control" v-model="searchTerm" :placeholder="placeholder">
            </form>
            <slot :hits="hits"></slot>
        </div>
    </template>
    
    <script>
        export default {
            props: [
                'token',
                'placeholder',
                'searchUrl'
            ],
            watch: {
                searchTerm() {
                    axios.get(this.searchUrl + '?q=' + encodeURI(this.searchTerm), {
                            headers: {
                                'Authorization': `Bearer ${this.token}`
                            }
                        })
                        .then(response => {
                            this.hits = response.data;
                            this.isOpen = true;
                        })
                }
            },
            data() {
                return {
                    searchTerm: '',
                    hits: [],
                }
            },
        };
    </script>
  6. Onu blade dosyamızın içinde X bir yerde çağırarak kullanabiliriz. 
    <hos-search token="{{ $token->plainTextToken }}"
                 placeholder="Müşteri adını yazarak ara..."
                 search-url="api/customers">
                <template v-slot="{ hits }">
                    <ul class="list-group">
                        <a v-for="(hit, index) in hits"
                           :key="index"
                           :href="(`customers/${hit.id}`)"
                           class="list-group-item list-group-item-action">
                            @{{ hit.name }}
                        </a>
                    </ul>
                </template>
    </hos-search>

Basit Vue Componenti Yapmak

  1. Backend'te bağlı blade sayfasında backend'den gelen datayı basit bir Vue componentine atsak şöyle bir kurgu olur. Vue componenti: ExampleComponent.vue 
    <template>
       <div>Example Component {{ greeting }}</div>
       <div>Foo: {{ foo }}</div>
    </template>
    <script>
    import { ref } from 'vue'
    
    export default {
       props: ['Foo'],
       setup() {
          const greeting = ref('hello there')
    
          return { greeting }
       }
    }
    </script>
  2. Bu basit componenti welcome.blade.php dosyasında kullansak ve backend'den gelen datayı bu componentin içine atmak istesek burada welcome.blade.php sayfası şu şekilde olur. 
    <html>
    	<head></head>
    	<body>
    		<div id="app">
    			<h1>Statik içerik</h1>
    			<example-component foo="bar"></example-component>
    		</div>
    		<script src="{{ mix('js/app.js') }}"></script>
    	</body>
    </html>

Composition API

  1. Reactive state 
    import { reactive } from 'vue'
    
    const state = reactive({
       term: '',
    })
  2. Method 
    function incrementCount() {
       state.count++
    }
  3. Computed Props 
    import { computed } from 'vue'
    
    const itemsLeft = computed(() => state.todos.filter(todo => !todo.inComplete).length)
  4. Lifecycle Hooks 
    import { onMounted } from 'vue'
    
    onMounted(() => {
       console.log('mounted')
    })

Composition API with <script setup>

  1. Vue dosyasında export default {} içerisindeki setup'ta bulunan her şeyi (reactive state declarations, methods, computed props, watchers) dışarda return etmeye gerek kalmadan çalışmasını sağlar.
  2. <template>
        <div class="mt-4">
            <input type="search" name="q" autocomplete="off"
                   class="form-control" placeholder="Ara..."
                   v-model="state.searchTerm">
            <div class="list-group">
                <a v-for="hit of state.hits"
                   :key="hit.id"
                   :href="`/resources/${hit.uri}`"
                   class="list-group-item list-group-item-action">
                    {{ hit.title }}
                </a>
            </div>
        </div>
    </template>
    <script setup="props">
    import { reactive, watch } from 'vue'
    import axios from 'axios'
    
    const state = reactive({
        searchTerm: '',
        hits: []
    })
    
    watch(
        () => state.searchTerm,
        (newValue, oldValue) => {
            axios.get('/api/search?q=' + encodeURI(state.searchTerm))
                .then(response => {
                    state.hits = response.data
                })
        }
    )
    </script>
    

Refactor to a Component

  1. Elimde bir Inertia.js <Link> component'i var. 
    <template>
    <Link href="/users" 
          class="text-blue-500 hover:underline" 
          :class="{'font-bold underline': $page.component === 'Users' }>
        Users
    </Link>
    </template>
    <script>
    import { Link } from '@inertiajs/inertia-vue'
    
    export default {
       components: { Link },
    }
    </script>

    bunu <NavLink> diye ayrı bir komponente dönüştürmek istiyorum.

  2. Shared/NavLink.vue dosyası
    <template>
        <Link class="text-blue-500 underline"
            :class="{'font-bold underline' : active}">
            <slot />
        </Link>
    </template>
    <script>
    import { Link } from '@inertiajs/inertia-vue'
    
    export default {
       components: { Link },
       props: {
            active: Boolean,
       }
    }
    </script>
  3. Refaktör edildikten sonra ana dosya
    <template>
        <NavLink href="/users" :active="$page.component === 'Users'">
            Users
        </NavLink>
    </template>
    <script>
    import { NavLink } from './NavLink'
    
    export default {
       components: { NavLink },
    }
    </script>
  4. NavLink komponenti içinde href'ten bahsetmiyoruz. Çünkü komponent props olarak kaydedilmeyen herşeyi zaten miras olarak alır ve alttaki komponente (Link) direk aktarılır.

Global Component Registration

  1. script-setup kullanırsan sadece import etmen o komponent ile çalışman için yeterli oluyor. 
    <template>
       <Link href="/">Refresh</Link>
    </template>
    
    <script setup>
    import { Link } from '@inertiajs/inertia-vue3';
    </script>
  2. Official docs - link