Vue 2.0 createHOC
by Thorsten
HTML
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<h4>This is the Normal component rendered as-is:</h4>
<base-test
@update="alert($event)"
@click.native="handleNativeClick"
:message="message"
>
<p>This goes into the default slot</p>
<p slot="test">this goes into the test slot</p>
<template slot="withScope" scope="{message}">
<p>This is a scoped slot, it received the message: {{message}}</p>
</template>
</base-test>
<hr>
<h4>This is the same component wrapped in a HOC</h4>
<hoc
@update="alert($event)"
@click.native="handleNativeClick"
:message="message"
>
<p>This goes into the default slot</p>
<p slot="test">this goes into the test slot</p>
<template slot="withScope" scope="{message}">
<p>This is a scoped slot, it received the message: {{message}}</p>
</template>
</hoc>
</div>
CSS
.default {
background-color: blue;
color: white;
}
.test {
background-color: green;
color: black;
}
.with-scope {
background-color: orange;
color: black;
}
Babel + JSX
const Component = {
name: 'Base',
template:
`<div>
<p>The message from the parent: {{message}}</p>
<button @click="$emit('update', 'hello! from the child!')">click me</button>
<a id="test-anchor" href="#" @click.prevent>Click me, for a native event!</a>
<div class="default"><slot/></div>
<div>something between the slots</div>
<div class="test"><slot name="test" /></div>
<div> And a scoped slot: </div>
<div class="with-scope"><slot name="withScope" :message="message" /></div>
</div>`,
props: ['message']
}
const HOC = createHOC(Component, {
created() {
console.log(`greetings from ${this.$options.name}`)
},
/*
* The `createRenderFn` helper create a render function that:
* - passes in all attrs, props and listeners that were defined on the component
* - merge those with any attrs, props and listeners passed to this function
* - normalize and pass on normal slots
* - pass on scoped slots
render: createRenderFn(Component, {
props: {
myProp: this.$store.getters('someGetter')
}
})
*/
/*
* If you want / have to create your own render function, you can use the
* `normalizeSlots` helper function to prepare slots to pass them:
render(h) {
return h(Component, {
// it's up to you what to pass on in the data object
// e.g. don't pass on attrs or props from the parent,
// and only pass on what you define in the HOC
}, normalizeSlots(this.$slots))
}
*/
})
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
},
components: {
'base-test': Component,
hoc: HOC,
},
methods: {
alert(event) { alert(event) },
handleNativeClick(event) {
if (event.target.id === 'test-anchor') {
alert('You clicked the link and captured a native event!')
}
}
}
})
function createHOC(component, options = {}) {
const hoc = {
// copy props from the wrapped component
props: typeof component...