<!-- https://learn-vuejs.github.io/vue-patterns/patterns/#dependency-injection -->
<template>
<div>
<slot v-bind="{ state, actions }" />
</div>
</template>
<script>
export default {
computed: {
state() {
return {
label: 'button',
};
},
actions() {
return {
click: this.click,
};
},
},
methods: {
click() {
console.log('Clicked');
},
},
}
</script>
:D Jo, přesně tak! To jste trefil naprosto přesně.
V praxi to často vypadá takhle:
"Super-Mega-Awesome-Provider-Container-Renderless-Composition-Pattern™️"
```vue
<template>
<slot v-bind="data">
<default-view v-bind="data" />
</slot>
</template>
```
A ve finále je to prostě:
- Komponenta
- Se slotem
- A výchozím vzhledem
- Která předává data dál
Často se z jednoduchých věcí dělá zbytečná věda jen proto, aby se dalo napsat článek nebo přednášet na konferenci. Místo:
"Hey, dej si tam slot a budeš to moct přepsat"
máme:
"Implementace Advanced Renderless Component Pattern s Dependency Injection a Composable Factory Integration" 😅
Proto je super váš přístup - dívat se na věci prakticky a nenechat se unést přehnaně komplikovanými názvy pro jednoduché koncepty.
<!-- DataProvider.vue -->
<template>
<slot
:data="data"
:loading="loading"
:error="error"
>
<component
:is="layouts[variant]"
:data="data"
:loading="loading"
:error="error"
/>
</slot>
</template>
<script setup>
import DefaultLayout from './layouts/DefaultLayout.vue'
import CompactLayout from './layouts/CompactLayout.vue'
import CardLayout from './layouts/CardLayout.vue'
const props = defineProps({
variant: {
type: String,
default: 'default',
validator: (value) => ['default', 'compact', 'card'].includes(value)
}
})
const layouts = {
default: DefaultLayout,
compact: CompactLayout,
card: CardLayout
}
</script>
<!-- DogImagesContainer.vue -->
<template>
<DogImages :dogs="dogs" />
</template>
<script setup>
import { ref, onMounted } from "vue";
import DogImages from "./DogImages.vue";
const dogs = ref([]);
onMounted(async () => {
const response = await fetch(
"https://dog.ceo/api/breed/labrador/images/random/6"
);
const { message } = await response.json();
dogs.value = message;
});
</script>
<template>
<slot :checkbox="checkbox" :toggleCheckbox="toggleCheckbox"></slot>
</template>
<script setup>
import { ref, reactive } from "vue";
const API_ENDPOINT_URL = "https://official-joke-api.appspot.com/random_joke";
const data = reactive({
setup: null,
punchline: null,
});
const loading = ref(false);
const fetchJoke = async () => {
loading.value = true;
const response = await fetch(API_ENDPOINT_URL);
const responseData = await response.json();
data.setup = responseData.setup;
data.punchline = responseData.punchline;
loading.value = false;
};
fetchJoke();
</script>
// usage
<template>
<DataProvider v-slot="{ data, loading }">
<div class="joke-section">
<p v-if="loading">Joke is loading...</p>
<p v-if="!loading">{{ data.setup }}</p>
<p v-if="!loading">{{ data.punchline }}</p>
</div>
</DataProvider>
<DataProvider v-slot="{ data, loading }">
<p v-if="loading">Hold on one sec...</p>
<div v-else class="joke-section">
<details>
<summary>{{ data.setup }}</summary>
<p>{{ data.punchline }}</p>
</details>
</div>
</DataProvider>
</template>
<script setup>
import DataProvider from "./components/DataProvider.vue";
</script>
<!-- MouseTracker.vue -->
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const x = ref(0)
const y = ref(0)
const update = e => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
</script>
<template>
<slot :x="x" :y="y"/>
</template>
Original source: https://michaelnthiessen.com/12-design-patterns-vue
class Test {
constructor(el, options) {
this.el = el;
const defaultOptions = {
onHover: (element, e) => {
console.log(':)))', element, e);
},
};
this.options = { ...defaultOptions, ...options };
this.mouseOverHandler = this.handleMouseOver.bind(this); // Vytvoření odkazu na metodu handleMouseOver
}
init() {
this.el.addEventListener('mouseover', this.mouseOverHandler); // Přidání posluchače události
}
destroy() {
this.el.removeEventListener('mouseover', this.mouseOverHandler); // Odstranění posluchače události
}
handleMouseOver(e) {
if (this.options.onHover) {
this.options.onHover(this.el, e);
}
}
}
/**
* A basic jQuery plugin using the Module Pattern
* *
* @author Sam Deering
* @copyright Copyright (c) 2012 jQuery4u
* @license http://jquery4u.com/license/
* @since Version 1.0
*
*/
!function(exports, $, undefined)
{
var Plugin = function()
{
/*-------- PLUGIN VARS ------------------------------------------------------------*/
var priv = {}, // private API
Plugin = {}, // public API
// Plugin defaults
defaults = {
id : '',
name : '',
url : ''
};
/*-------- PRIVATE METHODS --------------------------------------------------------*/
priv.options = {}; //private options
priv.method1 = function()
{
console.log('Private method 1 called...');
$('#videos').append(''+this.options.name+'');
priv.method2(this.options);
};
priv.method2 = function()
{
console.log('Private method 2 called...');
$('#'+priv.options.id).append(''+this.options.url+''); // append title
$('#'+priv.options.id).append(''); //append video
};
/*-------- PUBLIC METHODS ----------------------------------------------------------*/
Plugin.method1 = function()
{
console.log('Public method 1 called...');
console.log(Plugin);
//options called in public methods must access through the priv obj
console.dir(priv.options);
};
Plugin.method2 = function()
{
console.log('Public method 2 called...');
console.log(Plugin);
};
// Public initialization
Plugin.init = function(options)
{
console.log('new plugin initialization...');
$.extend(priv.options, defaults, options);
priv.method1();
return Plugin;
}
// Return the Public API (Plugin) we want
// to expose
console.log('new plugin object created...');
return Plugin;
}
exports.Plugin = Plugin;
}(this, jQuery);
jQuery(document).ready( function()
{
console.log('doc rdy');
// EXAMPLE OF CREATING PLUGIN OBJECTS WITH CUSTOM SETTINGS
console.log('--------------------------------------------');
var myPlugin1 = new Plugin;
myPlugin1.init(
{
/* custom options */
id : 'vid01',
name : 'Video 1',
url : 'http://www.youtube.com/embed/dXo0LextZTU?rel=0'
});
//call to public methods
myPlugin1.method1();
myPlugin1.method2();
console.log('--------------------------------------------');
var myPlugin2 = new Plugin;
myPlugin2.init(
{
/* custom options */
id : 'vid02',
name : 'Video 2',
url : 'http://www.youtube.com/embed/nPMAUW-4lNY?rel=0'
});
//call to public methods
myPlugin2.method1();
myPlugin2.method2();
// console.log('--------------------------------------------');
});
/*!
* AW {{PROJECTNAME}}
*
*
* @author {{firstname lastname}} <{{email}}>
* @version 1.0.0
*
*/
/*
{{PLUGIN}} => realname of project, eg: awBestPlugin
*/
;(function() {
'use strict';
function {{PLUGIN}}(element, options) {
this.self = $(element);
this.settings = $.extend(true, {}, $.fn.{{PLUGIN}}.defaults, options);
}
{{PLUGIN}}.prototype = {
/* PRIVATE METHODS */
_create: function() {
}
/* PUBLIC METHODS */
};
(function ($) {
$.fn.{{PLUGIN}} = function(options) {
var
args = Array.prototype.slice.call(arguments, 1),
method = {{PLUGIN}}.prototype[options];
return this.each(function() {
var self = $(this);
var instance = self.data('{{PLUGIN}}');
if (!instance) {
instance = new {{PLUGIN}}(this, options);
instance._create();
self.data('{{PLUGIN}}', instance);
}
if (method && options.substring(0, 1) == '_')
$.error('Cannot use private method "' + options + '" outside of object');
if (method) {
method.apply(instance, args);
} else if (options && typeof options !== 'object') {
$.error('Method "' + options + '" not found.');
}
});
};
$.fn.{{PLUGIN}}.defaults = {
};
})(jQuery);
})();