How to implement smooth scroll in a nuxt3 application - vue.js

I'm a rookie in nuxt3 and i can't figure out how to implement smooth scroll. I have added a route.options.ts file in ~/app/ and tested it out, but no success.
This is my route.options.ts file:
import type { RouterConfig } from '#nuxt/schema';
// https://router.vuejs.org/api/#routeroptions
export default <RouterConfig>{
scrollBehavior(to) {
return { el: to.hash };
},
};
And this is how I set the anchor links:
<NuxtLink :to="{path: '', hash: '#testimonials'}">Let's go!</NuxtLink>

Added
scroll-behavior: smooth;
to html in css and now it works.

Related

How to Implement leaflet toolbar with vue3?

I am trying to install leaflet toolbar with vue3 but it not working
there are package available for vue2 but nothing available related to vue3.
I tried to implement the same using javascript but it is not helping
So if any have used it leaflet with vue3 using package or javascript code please let me know
Below is the screenshot of what I am trying to achieve using leaflet
enter image description here
Below is the code using which I got leaflet map working
`
<template>
<div id="mapContainer"></div>
</template>
<script>
import 'leaflet/dist/leaflet.css';
import "leaflet-draw/dist/leaflet.draw.css";
import L from 'leaflet';
import "leaflet-draw/dist/leaflet.draw-src.js";
export default {
name: "LeafletMap",
data() {
return {
map: null,
};
},
mounted() {
this.map = L.map("mapContainer").setView([51.5072, 0.1276], 5);
L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png", {
attribution:
'© OpenStreetMap contributors',
}).addTo(this.map);
//use a mix of renderers
var customPane = this.map.createPane("customPane");
var canvasRenderer = L.canvas({ pane: "customPane" });
customPane.style.zIndex = 399; // put just behind the standard overlay pane which is at 400
},
onBeforeUnmount() {
if (this.map) {
this.map.remove();
}
},
};
</script>
`

Show spinner (preloader/loading indicator) whenever page changes and hide when all assets are loaded in Vue Gridsome

I am using Gridsome (Vue static site generator with Vue Router) and I've created a preloader in index.html, its a simple div that covers everything. In index.html I also added this JS code to hide the preloader when everything loads
window.onload = function() {
document.getElementById('preloader').style.display = 'none';
};
This works only for the initial load, but when changing pages I am having trouble showing it and hiding it again.
I've tried to add this to my Layout component's beforeDestroy() hook to show the preloader again
beforeDestroy() {
this.preloader.style.display = 'block';
}
which shows it successfully when the route is changed, but then if I add the hiding logic in mounted() like this
mounted() {
this.preloader.style.display = 'none';
}
the preloader is never showed in the first place.
I was unable to find any resources about this kind of loading indicators, all I can find are one's for async calls like axios or fetch. I've created preloaders before in static HTML files, but never in SPAs. Can someone please push me in the right direction? Even googling keywords will help
you can use vuex with this case.
first, add your state src/main.js
import DefaultLayout from "~/layouts/Default.vue";
import Vuex from "vuex";
export default function(Vue, { appOptions }) {
Vue.component("Layout", DefaultLayout);
Vue.use(Vuex);
appOptions.store = new Vuex.Store({
state: {
loading: false,
},
mutations: {
on(state) {
state.loading = true;
},
off(state) {
state.loading = false;
},
},
});
}
second, add spinner to ./src/layouts/Default.vue
<template>
<div class="layout">
// add your spinner here or another
<div v-if="$store.state.loading">loading</div>
<slot />
</div>
</template>
finally, add commit code pages, templete, or components. like below.
<script>
export default {
created() {
// commit("on") first
this.$store.commit("on");
// commit("off") last, after fetch data or more.
this.$store.commit("off");
},
};
</script>

Nuxt render function for a string of HTML that contains Vue components

I'm trying to solve this for Nuxt
Codesandbox of a WIP not working: https://codesandbox.io/s/zw26v3940m
OK, so I have WordPress as a CMS, and it's outputting a bunch of HTML. A sample of the HTML looks like this:
'<h2>A heading tag</h2>
<site-banner image="{}" id="123">Slot text here</site-banner>
<p>some text</p>'
Notice that it contains a Vue component <site-banner> that has some props on it (the image prop is a JSON object I left out for brevity). That component is registered globally.
I have a component that we wrote, called <wp-content> that works great in Vue, but doesn't work in Nuxt. Note the two render functions, one is for Vue the other is for Nuxt (obviously this is for examples sake, I wouldn't use both).
export default {
props: {
html: {
type: String,
default: ""
}
},
render(h, context) {
// Worked great in Vue
return h({ template: this.html })
}
render(createElement, context) {
// Kind of works in Nuxt, but doesn't render Vue components at all
return createElement("div", { domProps: { innerHTML: this.html } })
}
}
So the last render function works in Nuxt except it won't actually render the Vue components in this.html, it just puts them on the page as HTML.
So how do I do this in Nuxt? I want to take a string of HTML from the server, and render it on the page, and turn any registered Vue components into proper full-blown Vue components. Basically a little "VueifyThis(html)" factory.
This was what worked and was the cleanest, thanks to Jonas Galvez from the Nuxt team via oTechie.
export default {
props: {
html: {
type: String,
default: ""
}
},
render(h) {
return h({
template: `<div>${this.html}</div>`
});
}
};
Then in your nuxt.config.js file:
build: {
extend(config, ctx) {
// Include the compiler version of Vue so that <component-name> works
config.resolve.alias["vue$"] = "vue/dist/vue.esm.js"
}
}
And if you use the v-html directive to render the html?
like:
<div v-html="html"></div>
I think it will do the job.
Here's a solution on codesandbox: https://codesandbox.io/s/wpcontent-j43sp
The main point is to wrap the dynamic component in a <div> (so an HTML tag) in the dynamicComponent() template, as it can only have one root element, and as it comes from Wordpress the source string itself can have any number of top level elements.
And the WpContent component had to be imported.
This is how I did it with Nuxt 3 :
<script setup lang="ts">
import { h } from 'vue';
const props = defineProps<{
class: string;
HTML: string
}>();
const VNode = () => h('div', { class: props.class, innerHTML: props.HTML })
</script>
<template>
<VNode />
</template>
There was not need to update nuxt.config.ts.
Hopefully it will help some of you.
I made some changes to your codesandbox. seems work now https://codesandbox.io/s/q9wl8ry6q9
Things I changed that didn't work:
template can only has one single root element in current version of Vue
v-bind only accept variables but you pass in a string.

How to install flickity carousel with vuejs and nuxtjs

I'm a new vuejs developer. I have study vueje for a while and now I decided to develop a project using vuejs.
So I learn about nuxtjs which is server side rendering. everything goes well. I can use bootstrap4 with my project.
Now I would like to use flickity carousel https://flickity.metafizzy.co on my project and I found that there is a vuejs package on https://github.com/drewjbartlett/vue-flickity
I follow the instruction how to install this component to my project by
npm install vue-flickity --save
and put on some code
<script>
import Logo from '~/components/Logo.vue'
import Searchbar from '~/components/Searchbar.vue'
import axios from 'axios'
import Flickity from 'vue-flickity';
export default {
data () {
return {
has_location: false,
flickityOptions: {
initialIndex: 3,
prevNextButtons: false,
pageDots: false,
wrapAround: true
}
}
},
components: {
Logo,
Searchbar,
Flickity
}
}
</script>
but it show window is not defined
I have try this with another component like google map, it's show the same error.
Please tell me what wrong did I do and how to install new component to the project.
Thank you.
Nuxt.js use SSR to render your website server side, therefore window object is not accessible on node.js environment.
What you need to do is use the built-in no-ssr component to prevent Nuxt.js to render it on the server side.
You can simply do this:
<no-ssr>
<Flickity :options="...">
<!-- slides -->
</Flickity>
</no-ssr>
UPDATE: If you still get an error at this point, then load Flickity in
a custom Plugin that you will load with ssr disabled
Create a file named plugins/VueFlickity.js
import Vue from 'vue'
import Flickity from 'vue-flickity'
Vue.component('Flickity', Flickity)
Then in your nuxt.config.js your add:
module.exports = {
// ...
plugins: [
{ src: '~/plugins/VueFlickity.js', ssr: false }
]
}
Don't forget to remove the Flickity local component registration:
components: {
Logo,
Searchbar
// Flickity <-- remove this line
}
This was tested and is now fully working.
I fixed it with:
let Flickity = {};
if (process.browser) {
Flickity = require('flickity.js');
}
#rayfranco pointed a great way.:) The thing is that by doing this in that way You're importing this plugin globally, but not as local component which is better for performance.
So You can do it also like this:
let Flickity;
if (process.client) {
Flickity = require('vue-flickity')
}
export default {
components: {
Flickity
}
}
and use this component this way:
Important: <no-ssr>......</no-ssr> is deprecated in Nuxt > 2.9, so use
<client-only>
<Flickity :options="...">
<div class="carousel-cell">1</div>
<div class="carousel-cell">2</div>
<div class="carousel-cell">3</div>
</Flickity>
</client-only>
you can also look into brief example by Josh Deltener
https://deltener.com/blog/common-problems-with-the-nuxt-client-only-component/

Vue 2 + Bootstrap-vue - dynamic attribute

this is my first steps in Vue 2 + bootstrap-vue, and I'm trying to figure out how to dynamically change the name of an attribute, so that at a small screen resolution the tooltip changes its position.
JS code below works fine, but tooltip not changing his position =(
Please help me improve my mistake;
.pug
JS
'use strict';
import Vue from 'vue';
import BootstrapVue from 'bootstrap-vue';
document.addEventListener("DOMContentLoaded", function () {
Vue.use(BootstrapVue);
new Vue({
el: '#freshbroccoli',
data: {
windowWidth: null,
position: this.windowWidth >= 480 ? 'left' : 'bottom'
},
mounted() {
this.$nextTick(function () {
window.addEventListener('resize', this.getWindowWidth);
this.getWindowWidth();
});
},
methods: {
getWindowWidth() {
this.windowWidth = document.documentElement.clientWidth;
console.log('this.windowWidth >= 480 ? \'left\' : \'bottom\'', this.windowWidth >= 480 ? 'left' : 'bottom', '\n', this.windowWidth);
}
},
beforeDestroy() {
window.removeEventListener('resize', this.getWindowWidth);
}
});
});
Browser - Chrome
Browser console - Chrome
Edit: my old answer assumed that was a v-b-tooltip was a component and not a directive.
From what I can tell, using a variable in a directive isn't supported. One solution would be to use vue-popper since you can update its options dynamically. Bootstrap uses Popper under the hood for its tooltips, so you wouldn't be introducing new technologies this way.
For Bootstrap-Vue tooltip there is parameter placement, so code could look like this:
<b-btn title="Title" target="d150" :placement="position">My btn</b-btn>
More at: https://bootstrap-vue.js.org/docs/components/tooltip