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öffentlicht am 29.10.2019 von Bernhard


Fragen / Kommentare


Wir verwenden Cookies, um Inhalte und Anzeigen zu personalisieren, Funktionen für soziale Medien anbieten zu können und die Zugriffe auf unsere Website zu analysieren. Außerdem geben wir Informationen zu Ihrer Nutzung unserer Website an unsere Partner für soziale Medien, Werbung und Analysen weiter. Details anzeigen.