Last active
April 11, 2018 12:57
-
-
Save treshugart/b27bf304a5cba2f79b5eafa5436c414e to your computer and use it in GitHub Desktop.
Vue renderer for SkateJS. In action: https://www.webpackbin.com/bins/-Ksoy2D-9EEMXzJU6BH_.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<x-vue yell>World</x-vue> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { props, withProps } from 'skatejs/esnext/with-props'; | |
import { withRender } from 'skatejs/esnext/with-render'; | |
import Vue from 'vue'; | |
// The base Vue component renderer. | |
// | |
// Since vue doesn't have an imperative re-render | |
// (at least I don't think it does) we only allow | |
// rendering the template once and subsequent prop | |
// sets don't actually render, but just update the | |
// instance it has stored from the first render. | |
const withVue = Base => class extends withRender(withProps(Base || HTMLElement)) { | |
rendererCallback(renderRoot, renderCallback) { | |
const { props } = this; | |
if (this._vue) { | |
Object.assign(this._vue, props); | |
} else { | |
// Vue calls cloneNode() so we can't use the | |
// shadowRoot directly as "el" because you can't | |
// clone a shadow root. | |
const vueRoot = document.createElement('div'); | |
vueRoot.innerHTML = renderCallback(); | |
renderRoot.appendChild(vueRoot); | |
this._vue = new Vue({ | |
el: vueRoot, | |
data: props | |
}); | |
} | |
} | |
} | |
// Simple custom element that uses the Vue renderer | |
// to show both slotted content via the real-slot | |
// and props. | |
class XVue extends withVue() { | |
static props = { | |
yell: props.boolean | |
} | |
renderCallback() { | |
return ` | |
Hello, | |
<strong v-if="yell"><real-slot></real-slot></strong> | |
<real-slot v-else></real-slot>! | |
`; | |
} | |
} | |
// Vue eats <slot /> elements because it uses them | |
// for their internal distirbution algorithm, so we | |
// must work around it somehow. This just bypasses | |
// Vue and uses a custom element to render a real | |
// slot as light DOM. We can't do it as shadow DOM | |
// because it needs to appear in the context of the | |
// parent shadow root. | |
class RealSlot extends HTMLElement { | |
connectedCallback() { | |
this.innerHTML = '<slot></slot>'; | |
} | |
} | |
customElements.define('real-slot', RealSlot); | |
customElements.define('x-vue', XVue); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think the above bin is broken for skatejs 5.1.x onwards ? @treshugart . Is it possible to make it in sync with 5.1.1 ? Don't know how to make it work correctly with vuejs