I have the following Vue component:
<template>
<div id="wrapper">
<div class="main-container">
<Header />
<router-view/>
<Footer/>
</div>
</div>
</template>
<script>
import './assets/js/popper.min.js';
// other imports
// ....
export default {
name: 'App',
components : {
Header,
Footer
},
mounted(){
// this is syntax error
import './assets/js/otherjsfile.js'
}
}
</script>
As is clear from the code snippet, I want to have the otherjsfile.js loaded in mounted() hook. That script file has certain IIFEs which expects the html of the web page to be fully loaded.
So how do I invoke that js file in a lifecycle hook?
This is the pattern I use. The example is importing a js file which contains an IIFY, which instantiates an object on window.
The only problem with this would occur if you want to use SSR, in which case you need Vue's <ClientOnly> component, see Browser API Access Restrictions
mounted() {
import('../public/myLibrary.js').then(m => {
// use my library here or call a method that uses it
});
},
Note it also works with npm installed libraries, with the same path conventions i.e non-relative path indicates the library is under node_modules.
I'm a little unsure of what your asking. But if you are just trying to include an external js file in your page, you can just use the script tag in your template and not have to put anything in your mounted function, like this:
<template>
<div id="wrapper">
<div class="main-container">
<Header />
<router-view/>
<Footer/>
</div>
<script src="./assets/js/otherjsfile.js"></script>
</div>
</template>
<script>
import './assets/js/popper.min.js';
// other imports
// ....
export default {
name: 'App',
components : {
Header,
Footer
},
}
</script>
Does this solve your issue?
Related
I'm discovering Nuxt 3 and and simply want to make an animation between pages. The idea is to use javascript hooks to make page transitions using js library such as gsap or animeJs.
So in my app.vue file, I simply put <NuxtPage/> into <Transition> element like this :
<NuxtLayout>
<Transition>
<NuxtPage/>
</Transition>
</NuxtLayout>
My vue pages ('./pages/index.vue' and './pages/project/myproject.vue') look like this :
<template>
<div>
<h1>My Project</h1>
</div>
</template>
<script setup>
function onEnter(el, done) {
done()
}
function onLeave(el, done) {
done()
}
</script>
I have followed both Nuxt 3 and Vue 3 documentations :
https://v3.nuxtjs.org/guide/directory-structure/pages#layouttransition-and-pagetransition
https://vuejs.org/guide/built-ins/transition.html#javascript-hooks
I also read this thread on github, but I can't find answer :
https://github.com/nuxt/framework/discussions/851
When i was using Nuxt 2 I only need to put transition object into my page like this and it's working fine :
<script>
export default {
// ... (datas, methods)
transition: {
mode: "in-out",
css: false,
enter(el, done) {
console.log("enter");
done()
},
leave(el, done) {
console.log("leave");
done()
}
}
}
</script>
<template>
<div>
<h1 class="text-center text-5xl">Hello World</h1>
</div>
</template>
Do you have any idea how to achieve it ?
Nuxt 3 doesn't need a <Transition> wrapper around pages/layouts, by default it does that for you.
Take a look at this starter template: in assets/sass/app.scss, the last part of the style is page and layout transition.
You can tweak the default named animations (page- and layout-).
More infos here
Just follow the official documentation for Nuxt 3. You need to add the following code to your nuxt.config.ts file:
export default defineNuxtConfig({
app: {
pageTransition: { name: 'page', mode: 'out-in' }
},
})
And then apply the classes inside your app.vue file, like this:
<template>
<NuxtPage />
</template>
<style>
.page-enter-active,
.page-leave-active {
transition: all 0.4s;
}
.page-enter-from,
.page-leave-to {
opacity: 0;
filter: blur(1rem);
}
</style>
Nuxt 3 uses the Vue's <Transition> component under the hood, so you don't need to add it in the template.
Be careful with the css prefix.
I'm a beginner regarding Vite/Vue3 and currently I am facing an issue where I need the combined knowledge of the community.
I've created a Vite/Vue3 app and installed TailwindCSS to it:
npm create vite#latest my-vite-vue-app -- --template vue
cd my-vite-vue-app
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Then I followed the instructions on Tailwind's homepage:
Add the paths to all of your template files in your tailwind.config.js file.
Import the newly-created ./src/index.css file in your ./src/main.js file. Create a ./src/index.css file and add the #tailwind directives for each of Tailwind’s layers.
Now I have a working Vite/Vue3/TailwindCSS app and want to add the feature to toggle dark mode to it.
The Tailwind documentation says this can be archived by adding darkMode: 'class' to tailwind.config.js and then toggle the class dark for the <html> tag.
I made this work by using this code:
Inside index.html
<html lang="en" id="html-root">
(...)
<body class="antialiased text-slate-500 dark:text-slate-400 bg-white dark:bg-slate-900">
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
Inside About.vue
<template>
<div>
<h1>This is an about page</h1>
<button #click="toggleDarkMode">Toggle</botton>
</div>
</template>
<script>
export default {
methods: {
toggleDarkMode() {
const element = document.getElementById('html-root')
if (element.classList.contains('dark')) {
element.classList.remove('dark')
} else {
element.classList.add('dark')
}
},
},
};
</script>
Yes, I know that this isn't Vue3-style code. And, yes, I know that one could do element.classList.toggle() instead of .remove() and .add(). But maybe some other beginners like me will look at this in the future and will be grateful for some low-sophisticated code to start with. So please have mercy...
Now I'll finally come to the question I want to ask the community:
I know that manipulating the DOM like this is not the Vue-way of doing things. And, of course, I want to archive my goal the correct way. But how do I do this?
Believe me I googled quite a few hours but I didn't find a solution that's working without installing this and this and this additional npm module.
But I want to have a minimalist approach. As few dependancies as possbile in order not to overwhelm me and others that want to start learning.
Having that as a background - do you guys and gals have a solution for me and other newbies? :-)
The target element of your event is outside of your application. This means there is no other way to interact with it other than by querying it via the DOM available methods.
In other words, you're doing it right.
If the element was within the application, than you'd simply link class to your property and let Vue handle the specifics of DOM manipulation:
:class="{ dark: darkMode }"
But it's not.
As a side note, it is really important your toggle method doesn't rely on whether the <body> element has the class or not, in order to decide if it should be applied/removed. You should keep the value saved in your app's state and that should be your only source of truth.
That's the Vue principle you don't want break: let data drive the DOM state, not the other way around.
It's ok to get the value (on mount) from current state of <body>, but from that point on, changes to your app's state will determine whether or not the class is present on the element.
vue2 example:
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => ({
darkMode: document.body.classList.contains('dark')
}),
methods: {
applyDarkMode() {
document.body.classList[
this.darkMode ? 'add' : 'remove'
]('dark')
}
},
watch: {
darkMode: 'applyDarkMode'
}
})
body.dark {
background-color: #191919;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.js"></script>
<div id="app">
<label>
<input type="checkbox" v-model="darkMode">
dark mode
</label>
</div>
vue3 example:
const {
createApp,
ref,
watchEffect
} = Vue;
createApp({
setup() {
const darkMode = ref(document.body.classList.contains('dark'));
const applyDarkMode = () => document.body.classList[
darkMode.value ? 'add' : 'remove'
]('dark');
watchEffect(applyDarkMode);
return { darkMode };
}
}).mount('#app')
body.dark {
background-color: #191919;
color: white;
}
<script src="https://unpkg.com/vue#next/dist/vue.global.prod.js"></script>
<div id="app">
<label>
<input type="checkbox" v-model="darkMode">
dark mode
</label>
</div>
Obviously, you might want to keep the state of darkMode in some external store, not locally, in data (and provide it in your component via computed), if you use it in more than one component.
What you're looking for is Binding Classes, but where you're getting stuck is trying to manipulate the <body> which is outside of the <div> your main Vue instance is mounted in.
Now your problem is your button is probably in a different file to your root <div id="app"> which starts in your App.vue from boilerplate code. Your two solutions are looking into state management (better for scalability), or doing some simple variable passing between parents and children. I'll show the latter:
Start with your switch component:
// DarkButton.vue
<template>
<div>
<h1>This is an about page</h1>
<button #click="toggleDarkMode">Toggle</button>
</div>
</template>
<script>
export default {
methods: {
toggleDarkMode() {
this.$emit('dark-switch');
},
},
};
</script>
This uses component events ($emit)
Then your parent/root App.vue will listen to that toggle event and update its class in a Vue way:
<template>
<div id="app" :class="{ dark: darkmode }">
<p>Darkmode: {{ darkmode }}</p>
<DarkButton #dark-switch="onDarkSwitch" />
</div>
</template>
<script>
import DarkButton from './components/DarkButton.vue';
export default {
name: 'App',
components: {
DarkButton,
},
data: () => ({
darkmode: false,
}),
methods: {
onDarkSwitch() {
this.darkmode = !this.darkmode;
},
},
};
</script>
While tailwind say for Vanilla JS to add it into your <body>, you generally shouldn't manipulate that from that point on. Instead, don't manipulate your <body>, only go as high as your <div id="app"> with things you want to be within reach of Vue.
I'm trying to access the root element a component with this.$children.$el, however, I'm getting undefined in the console. I can see the $el property on the object when I console.log(this.$children), so I'm not quite sure where I'm going wrong, any help would be greatly appreciated.
<template>
<div>
<Project
v-for="project in projects"
:key="project.sys.id"
:title="project.fields.title"
:images="project.fields.images"
/>
</div>
</template>
<script>
import Project from '~/components/Project'
export default {
mounted() {
const projects = this.$children.$el
},
components: {
Project
}
}
</script>
As stated in the vue.js documentation this.$children returns an array of children components. You could see your child component by printing this.$children[0] and its root element by priting this.$children[0].$el.
If you have many children components and want to target a specific one, you can tag your component with a ref attribute like below :
<template>
<div>
<Project
v-for="project in projects"
:key="project.sys.id"
:title="project.fields.title"
:images="project.fields.images"
ref="project"
/>
</div>
</template>
<script>
import Project from '~/components/Project'
export default {
mounted() {
console.log(this.$refs.project)
},
components: {
Project
}
}
</script>
I am using nuxt.js (which is based on vue.js) to build a custom website, I need to load an Ad on my website using a provided by my partners, and I need to place it at a specific place on my html code. So I add it to my component template but it does not render.
Here is a sample of the code I'm trying to get to work
<template>
<div>
<div class="columns is-centered is-mobile">
<p>Hello World</p>
</div>
<div>
<script type="text/javascript" src="sampleSource"></script>
</div>
</div>
</template>
<script>
export default {
}
</script>
the script that comes from src="sampleSource" doesn't load and doesn't execute, any help is appreciated. Thank you very much.
On the page, use in metadata with body: true for add script inside body
<script>
export default {
head: {
script: [
{ src: '/head.js' },
// Supported since Nuxt 1.0
{ src: '/body.js', body: true },
{ src: '/defer.js', defer: '' }
]
}
}
</script>
You need to create a (sample-source.vue) component and take it to the /components dir.
After that you need to create a plugin for your component: /plugins/sample-source.js
sample-source.js :
import Vue from 'vue'
import SampleSource from '~/components/sample-source.vue'
Vue.use(SampleSource)
nuxt.config.js:
...
module.export
...
plugins: [
'~/plugins/sample-source.js'
]
After these steps you can use your component everywhere.
Or the easiest way:
<template>
<div>
<div class="columns is-centered is-mobile">
<p>Hello World</p>
</div>
</div>
</template>
<script>
export default {
mounted () {
----your code here from sampleSource.js----
}
}
</script>
I have one external module as following:
const externalModule = {
thisMethodWantToUseInMarkup: () =>{
alert("success");
}
}
export default externalModule
i want to access thisMethodWantToUseInMarkup from component markup(from button A in following code).
<template lang="html">
<div class="bg-white">
<button #click="externalModule.thisMethodWantToUseInMarkup()">Button A</button> <!-- is it possible like this directly -->
</div>
</template>
what is the best practice to do this ?
Note: - I don't want to import global module in every component.
Use simple import in your script section of the view component (if you're using the default .vue files), or inside your javascript file. Something similar to:
<template lang="html">
<div class="bg-white">
<button #click="customMethod"> <!-- call your internal method -->
Button A
</button> <!-- is it possible like this directly -->
</div>
</template>
<script>
import { externalModule } from './externalModule'
export default {
name: 'mainComponent',
methods: {
customMethod() {
externalModule.thisMethodWantToUseInMarkup()
}
}
}
</script>
Using internal method you won't bind user interaction with a specific implementation, and therefore switching the files/logic for it will simply mean changing the import file. This is useful for testing purposes in where you could dynamically load specific files based on environment for example.