I started migrating my app from vue 2 to vue 3 and in my project I use class components.
I didn't find way how can I use mixins in Vuejs 3.
Is it possible and how to use mixins in vuejs 3?
current code:
export default class HomePage extends Mixins(Vue, PageMixin) {}
I know it is not a direct answer to your question but as stated here
https://vuejs.org/api/options-composition.html#mixins
In Vue 2, mixins were the primary mechanism for creating reusable chunks of component logic. While mixins continue to be supported in Vue 3, Composition API is now the preferred approach for code reuse between components.
It is same with the Vue2
const mixin = {
created() {
console.log(1)
}
}
Here you can use it:
createApp({
mixins: [mixin],
created() {
console.log("test")
},
})
Related
We are trying to update a library and the newer version requires Vue 3 instead of Vue 2, namely tinymce-vue. Unfortunately, it is a company project using bootstrap-vue, which has no full compatibility with Vue 3 yet (bootstrap-vue3 is not production-ready and we use some components that are not migrated yet).
Migrating the full app to Vue 3 has been the main attempt. However, it does not allow to use the Bootstrap components in Vue 3, or if the compatibility mode is used, part of the app works but those that would require the component do not appear/work or then the other parts of the component needing Vue 3 are broken. Is there any way to provide maybe library-specific compatibility or what is the suggested way to proceed in this case when needing two libraries that require two different versions of Vue in the same component?
I am not sure if this question should be asked differently, it is my first question in StackOverflow, so please let me know if I need to reformulate or provide more details.
The problem is that Vue 2 and 3 applications are hard to impossible to coexist in the same project because they rely on vue package with the same name but different versions. Even if it's possible to alias vue package under a different name or use modular Vue (import Vue from 'vue') for one version and Vue CDN (window.Vue) for another version in first-party code, another problem that needs to be addressed is that Vue libraries need to use specific Vue version.
This requires to build and bundle sub-apps with their preferred Vue version and libraries, which is quite close to the concept of micro frontend applications.
Given that there is Vue 3 sub-app that uses Vue 3-specific library (tinymce-vue) and specifically written to expose all public API to communicate with the outside world:
let MyV3Comp = {
template: `<div>{{ myV3Prop }} {{ myV3Data }}</div`,
props: ['myV3Prop'],
emits: ['myV3Event'],
setup(props, ctx) {
const myV3Data = ref(1);
const myV3Method = () => {};
ctx.emit('myV3Event', Math.random());
// Component public api needs to be exposed to be available on mount() instance
ctx.expose({ myV3Data, myV3Method });
return { myV3Data, myV3Method }
},
};
// Sub-app entry point
let createMyV3App = initialProps => createApp(MyV3Comp, initialProps);
export default createMyV3App;
There is Vue 2 wrapper component that acts as a bridge between Vue 3 sub-app and the rest of Vue 2 app:
import createMyV3App from '.../my-v3-app-bundled';
let MyV2WrapperComp = {
template: `<div ref="v3AppWrapper"></div>`,
props: ['myV2Prop'],
emits: ['myV2Event'],
data() {
return { myV2Data: null };
},
methods: {
// Sync wrapper events
onMyV3Event(v) {
this.$emit('myV2Event', v);
}
},
watch: {
// Sync wrapper props and data
myV2Data(v) {
this.v3AppCompInstance.myV3Data.value = v;
},
myV2Prop(v) {
// Hacky! Better use data and methods from public api to pass info downwards
this.v3AppCompInstance._instance.props.myV3Prop = v;
},
},
mounted() {
// Vue 3 automatically translates onMyV3Event prop as myV3Event event listener
// Initial prop values make app props reactive
// and allow to be changed through _instance.props
this.v3App = createMyV3App({ onMyV3Event: this.onMyV3Event, myV3Prop: null });
// also available as undocumented this.v3App._instance.proxy
this.v3AppCompInstance = this.v3App.mount(this.$refs.v3AppWrapper);
// Sync wrapper data
// Hacky! Better use event from public api to pass info upwards
this.v3AppCompInstance._instance.proxy.$watch('myV3Data', v => this.myV2Data = v);
},
unmounted() {
this.v3App.unmount();
},
};
In case wrapper and sub-app need to be additionally synchronized based on specific points, e.g. provide/inject, template refs, etc, this needs to be specifically implemented. At this point it's no different than Vue 3->Vue 2 adapter or adapters that involve other frameworks (Angular, React).
Could you advise what is the equivalent of the created() in the new Vue composition API, which I'm using from within Vue2 like this:
import { reactive, toRefs } from '#vue/composition-api'
From the Composition API docs on Lifecycle Hooks:
Because setup is run around the beforeCreate and created lifecycle hooks, you do not need to explicitly define them. In other words, any code that would be written inside those hooks should be written directly in the setup function.
Anything you would have done in the created hook you can do in setup.
to help the community, the created() method can be used this way.
hope this helps :)
<script>
import TenantsAPI from "#/api/tenants";
export default {
setup() {
const tenantsAPI = new TenantsAPI(); //compositon api
};
}
//options api
//async created(){
// this.tenantsAPI = new TenantsAPI();
//}
</script>
Is this instance lifecycle hooks diagram also valid(the same) for a vue.js single file component or a global component(vue.componnet())? or is it only used for a Vue instance(new Vue)??
thanks.
Yes, these lifecycle hooks are there for all vue instances: SFCs, global components, explicit new Vue, vue-test-utils wrappers, and so on.
The only thing that SFC do are to write the .render method for you because it's way simpler to write it with an html-like syntax rather than write the render function manually.
In an SFC, you'd tap into them as such:
<script>
export default {
created() {
// do something on created
}
}
</script>
In an explicit new Vue, like this:
new Vue({
created() {
// do something on created
}
});
You get the point.
Usually I use a js code with functions to run on some events.
Now I am using nuxt.js and I wonder where to put this file or how to create a global method to use these functions in every component.
I could write the methods that I need inside every a specific component but after it wouldn't be usable outsite of it.
How to do that in vue/nuxt?
So one way to do it in vue.js is by using mixins, in nuxt you can also use mixins, then you should register them as plugins, but first:
Non global mixins
Create an extra folder for your mixins. For example in a /mixins/myMixin.js
export default {
methods: {
commonMethod() {
console.log('Hello')
}
}
}
Then import in a layout, page or component and add it via the mixins object:
<script>
import myMixin from '~/mixins/myMixin.js'
export default {
mixins: [myMixin]
}
</script>
Global mixins
For example in a new file plugins/mixinCommon.js:
import Vue from 'vue'
Vue.mixin({
methods: {
commonMethod() {}
}
})
Include the file in nuxt.config.js like that:
plugins: ['~/plugins/mixinCommon']
After that you would have the method everywhere available and call it there with this.commonMethod(). But here an advice from the vue.js docs:
Use global mixins sparsely and carefully, because it affects every
single Vue instance created, including third party components. In most
cases, you should only use it for custom option handling like
demonstrated in the example above. It’s also a good idea to ship them
as Plugins to avoid duplicate application.
I am trying to create some plugins according to this article:
https://alligator.io/vuejs/creating-custom-plugins/
I have a plugin that needs to run something when the root Vue instance mounts or is created. So far I can only see a way to inject something into all components which is not what I would want.
I simply need to do something when the main Vue instance mounts. How can I do this with a plugin?
The install method from the plugin does not seem to do the trick because this seems to happen before the actual created method.
It's possible to have multiple root Vue components. A "root component" is just a component created with the new syntax and no parent component, so you can detect this as follows:
Vue.mixin({
created() {
if (!this.$parent) {
// This is either the root component or a component
// created with `new` and no parent
}
}
})
It's actually easy to include mixins for just a particular component!
In your component that you want to add the mixin to, just import it like you would anything else, and include an array in your component called mixins like so:
import myMixin from 'src/mixin/myMixin'
export default {
mixins: [myMixin]
}
Then your myMixin code would look like this (don't use Vue.mixin, which is global):
export default {
beforeMount () {
console.log('Your component is about to be mounted!')
}
}