-
-
Save james2doyle/e19faf122ed6fa3380c38242389c21fe to your computer and use it in GitHub Desktop.
import Vue from 'vue'; | |
/** | |
* EventHub to listen or broadcast to all components | |
* | |
* @see https://shopify.dev/tutorials/develop-theme-sections-integration-with-theme-editor | |
* | |
* Usage: eventHub.$on('shopify:section:select:{my-section-name}', (event) => handleSelect()); | |
* | |
*/ | |
const eventHub = new Vue({ | |
created() { | |
const themeEventHandler = (event) => { | |
// emit a generic version | |
this.$emit(`${event.type}`, event); | |
// emit a specific version for the section | |
this.$emit(`${event.type}:${event.detail.sectionId}`, event); | |
}; | |
// these are custom events emitted by the Shopify section editor | |
// we are hooking them up to our Vue event dispatcher | |
document.addEventListener('shopify:section:load', themeEventHandler); | |
document.addEventListener('shopify:section:unload', themeEventHandler); | |
document.addEventListener('shopify:section:select', themeEventHandler); | |
document.addEventListener('shopify:section:deselect', themeEventHandler); | |
document.addEventListener('shopify:section:reorder', themeEventHandler); | |
document.addEventListener('shopify:block:select', themeEventHandler); | |
document.addEventListener('shopify:block:deselect', themeEventHandler); | |
} | |
}); | |
function createApp() { | |
return new Vue({ | |
el: '#app', | |
}); | |
} | |
let instance = createApp(); | |
eventHub.$on('shopify:section:select', ({ detail }) => { | |
// recreate the Vue app because the section editor destroyed it | |
if (detail.load) { | |
instance.$destroy(); | |
instance = createApp(); | |
} | |
}); | |
/** | |
* You can also do this in Vue apps | |
* Our section would be named "navigation" in this instance | |
* | |
* import eventHub from 'Functions/event-hub'; | |
* // this would go in mounted() | |
* eventHub.$on('shopify:section:select:navigation', () => { | |
* // do something once the section is opened... | |
* }); | |
* eventHub.$on('shopify:section:deselect:navigation', () => { | |
* // do something once the section is closed... | |
* }); | |
*/ |
@sillycube you will need to use something like mitt. I haven't tested this but it should work. All I'm doing here is updating the themeEventHandler
function with mitt
calls:
import mitt from 'mitt';
const emitter = mitt();
const themeEventHandler = (event) => {
// emit a generic version
emitter.emit(`${event.type}`, event);
// emit a specific version for the section
emitter.emit(`${event.type}:${event.detail.sectionId}`, event);
};
// the rest of the code...
Unfortunately, $destroy instance method is also removed in Vue 3.x. So I don't know how to recreate / reload / re-render the app. I can make it work by remounting the app. However, the data reactivity is lost:
function RemountVueApp() {
console.log('listen to shopify theme editor re-render');
// vm.$forceUpdate(); // not work
vueApp = createMyApp()
vueApp.component('product-card', productCard)
vm = vueApp.mount('#byobApp')
}
const emitter = window.mitt();
emitter.on('shopify:section:load', RemountVueApp);
const themeEventHandler = (event) => {
// emit a generic version
emitter.emit(`${event.type}`, event);
};
// these are custom events emitted by the Shopify section editor
// we are hooking them up to our Vue event dispatcher
document.addEventListener('shopify:section:load', themeEventHandler);
However, I don't know if there is a memory leak if the user continues to edit in the theme editor. So I open a thread on the official forum. You can follow the thread if you're interested.
Hmm not sure. I haven't used vue 3 with shopify yet so I'm not sure how it handles that stuff anymore. Are you sure you still need to recreate the instance?
It works now. I tried to create a <style> tag before my <div id="myVueApp">...</div>
:
<style>
.test-button {
background-color: {{ section.settings.button_color }};
}
</style>
In my template, I bind the class like this:
<button type="button" id="btnAddToBundle" class="btn" :class="'test-button'" :disabled="!available">
<span id="AddToCartText" v-if="available">
Add to Bundle
</span>
<span id="AddToCartText" v-else>
Sold Out
</span>
</button>
Now look like it works. When I change the button color in the section, it can be updated immediately. Thanks!
I am also trying to update Vue app when editor events are emitted. The $on, $off and $once instance methods are removed in v3.x. Did you try to upgrade the script?