Laravel Vue

 

.vue Files setzen ein Webpack-Setup voraus ...

Laravel Default Setup

Vue wird in der Datei resources/assets/js/app.js eingebunden bzw. können durch das Auskommentieren des folgenden CodeBlocks automatisch alle Components des Ordners /resources/js/components geladen werden.

const files = require.context('./', true, /\.vue$/i);
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default));

Im Standard-Setup wird Vue in der app.js Datei geladen:

const app = new Vue({
    el: '#app',
});

Mit diesem Setup reicht es also Vue-Components in /resources/js/components zu hinterlegen:

Als Schreibweise wird hier Pascal case verwendet also sowas wie EditStory.vue

Die Components können in den Bladetemplates dann kleingeschrieben mit Bindestrich eingebunden werden, also 

<edit-story></edit-story>

Damit die Javascript-Sourcen in den Blade-Templates verfügbar sind, müssen diese vorher mittels npm gemerged werden:

In der Konsole werden mittels des Befehles:

npm run dev

die Dateien /css/app.css und /js/app.js erstellt. 

siehe auch:  NPM Pakete - Laravel app.js und css 

Während der Entwicklung kann auch "npm run watch" verwendet werden. "Watch" merged die Files bei jeder Änderung des Sourcecodes. 

Single File Component - ExampleComponent

Mit Single-File-Component sind die vue-Dateien im Ordner components gemeint, hier ein Beispiel:

/resources/js/components/ExampleComponent.vue

<template>
    <div class="container">
                    <div class="panel-heading">Example Component</div>
                    <div class="panel-body">
                        <slot></slot>
                    </div>
    </div>
</template>

Einsatz im Blade-Template:

@extends('layouts.app')

@section('content')

<example-component></example-component>

@endsection

Die Webseite zeigt hier 

eine kurze Anmerkung:

Vue wird hier über die Blade-Datei layouts.app geladen:

<head>
  ...
    <!-- Scripts -->
    <script src="{{ mix('js/app.js') }}" defer></script>
    <!-- Styles -->
    <link href="{{ mix('css/app.css') }}" rel="stylesheet">
  ...
<body>
<div id="app">
...

Vue kann dabei innerhalb von <div id="app"> verwendet werden: 

Slot

Der Inhalt des Slot-Bereiches kann innerhalb des Blade-Templates innerhalb der Tags mitgegeben werden:

@extends('layouts.app')

@section('content')

<example-component>SlotText</example-component>

@endsection

Anzeige:

 

props Parent Child Beispiel

Props dienen dazu Variablen von einem Parent Component in ein Child-Component zu übertragen. Das Child-Component sollte ein Property nie direkt ändern, daher werden Props häufig in den privaten Speicher der Components kopiert:

            props: ['value'],
            data: function () {
                return {  
                        privatevalue: this.value
                }
            },

Hier ein Beispiel mit 2 Components.

Component 1 bekommt mittels Property die Information welche Daten es per AJAX laden soll, ein Teil der Daten wird dann an Component 2 übergeben. Sollte Component 2 upgedated werden, werden die Änderungen durch den Einsatz von v-model auf Component 1 übertragen. 

Wir starten in der routes/web.php-Datei für den spätern AJAX-Call:

Route::get('getstory/{slug}','StoryController@getstory');

Der Call lädt eine Funktion im StoryController, sowas wie:

public function getstory($slug)
	{
		 $story= Story::where('slug',$slug)
		  	  ->with('hashTags');
		 return $story;

 

Im Model (Story.php) ist die Relation dazu hinterlegt:

public function hashTags()
    {
        return $this->belongsToMany('App\Hashtag')->with('parents:name');
	}

 

Also eine Story und deren Hashtags.

 

Aufruf der Website: also https://Websiteurl/STORYSLUG

Route::get('/{slug}','StoryController@show')

im StoryController

    public function show($slug)
    { 
        return View('stories.show',compact('slug'));
    }
In der View resources/view/stories/show.blade.php:
laden des ersten Vue Component und Übergabe des Slug aus der URL: STORYSLUG aus https://Websiteurl/STORYSLUG
<edit-story slug="{{$slug}}">
</edit-story>​

An dieser Stelle könnten Anstelle von AXIOS die Daten auch über den StoryController und die View über eine Blade-Variable geladen werden:  

<edit-story
    model="/story"
    :item='{{ json_encode($story) }}'>
</edit-story>​

 

im Component können dann Daten der zuvor erstellten Route via AXIOS geladen werden:

<script>
    export default {
        	props: ['slug'],	
			data() {
				return {
					item:[]
				};
			},
			created() {
				axios.get('/getstory/' + this.slug)
                .then(res => {
					this.item= res.data				
                }).catch(err => {
					console.log(err)
				})
			},
...

Das Template dieser Component kann dann ein anderes Component laden und die Hashtags der zuvorerstellten AJAX-Abfrage übergeben:

<template>
    <div>
        <hash-tags v-model="item.hashTags"></hash-tags>
    </div>
</template>

Die Component hash-tags würde die Daten dann wie folgt laden und z.B. mittles v-for anzeigen:

<template>
<div>
        <div v-for="(hashTag, index) in hashtags" :key="index">
                <input type="search" v-model="hashtags[index]">	
        </div>
</div>
</template>
<script>
    export default {
            props: ['value'],
            data: function () {
                return {  //copy the prop into private component memory
                        hashtags: this.value
                }
            },
            watch: { //whatch is needed if parent Component loads its data via AXIOS, as otherwise hashtags would not be filled
                value: function () {
                        this.hashtags= this.value
                }
            },

 

 

hideProp Example

Vue.component('example', {
	props: ['title', 'body'] , 

	data() {
		return {
			isVisible: true
		};

	},


	template:     `
		<div class="container" v-show="isVisible">
			<div class="row">
				<div class="col-md-8 col-md-offset-2">
					<div class="panel panel-default">
						<div class="panel-heading">
							 {{ title }} 
							<button type="button" @click="isVisible = false">X</button>
						</div>

						<div class="panel-body">
							<slot></slot>
						</div>
					</div>
				</div>
			</div>
		</div> 
	`
});
	<example title="title1">my TestBodyfirstExample</example>
	<example title="title2">my TestBodySecondExample</example>

Event Kommunikation

Parent-Child

Child:

this.$emit("create")

Parent:

<add-item @create="reset"></add-item>
methods: {
   reset () {

Parent-Child-Input

Parent

<select-image v-model="story.image_id" ></select-image>

Child:

<template>
  <div>
    <input v-model="image_id" autocomplete="false" class="form-control" v-on:input="$emit('input', $event.target.value)" placeholder="">
  </div>
</template>

<script>
  export default {
    props: ['value'], 
    data(){
      return {
        image_id: this.value
      }
    }
  }
</script>

zwischen Components

 <script src="/js/app.js"></script>  
<script>
	window.Event = new Vue();
	const app = new Vue({
				el: '#app'
			})	
</script>

zwischen 2 Components:

In z.B. einer method: 

Event.$emit("create")

in einem anderen:

created() {
Event.$on('create', () => alert ('event'))

X-Template

       <link href="{{ asset('css/app.css') }}" rel="stylesheet">
		
</head>
<body>
<div id="app">
<x-template-component></x-template-component>
</div>
<script src="{{ asset('js/app.js') }}"></script>

<script type="text/x-template" id="x-template-id">
<div class="checkbox-wrapper" @click="check">
Template
</div>
</script>
<script>
Vue.component('x-template-component', {
template: '#x-template-id',
data: function() {
},
methods: {
}
});
const vm = new Vue({
el: '#app'});
</script>


</body>
positive Bewertung({{pro_count}})
Beitrag bewerten:
{{percentage}} % positiv
negative Bewertung({{con_count}})

DANKE für deine Bewertung!

Veröffentlichung: 29.10.2019 von Bernhard |🔔 | Kommentare:0

Laravel Passport | Laravel | Laravel Relationship

Fragen / Kommentare