VueJS single file component briefly showing SVG unstyled - vue.js

I have a really simple Vue single-file component (using Vue 2.4.2) that includes an SVG image using a set of predefined SVG symbols and work perfectly.
I notice that the icon is briefly shown unstyled before the component (non-scoped) style is applied. Important to note that:
When including the scss in our main .scss file, the problem does not occur
Using v-cloak with has no effect
Occurs on latest Chrome, FF and Safari (MacOS)
Q: I can obviously use the workaround of including it in the main scss file, but I was wondering if this is SVG-styling specific or if a delay is normal when using component-style?
My component (additional scss omitted):
<template>
<i class="icon" v-if="symbol" :class="{'icon-spin': spinning}">
<svg>
<use v-bind:xlink:href="symbol"></use>
</svg>
</i>
</template>
<script>
export default {
name: 'Icon',
props: {
icon: {type: String},
spinning: {type: Boolean, default: false}
},
computed: {
symbol () {
return this.icon ? '#' + this.icon : ''
}
}
}
</script>
<style lang="scss">
#import '../../style/variables';
.icon {
display: inline-block;
width: $icon-size;
height: $icon-size;
line-height: 1;
svg {
width: 100%;
height: 100%;
fill: currentColor;
}
...

Related

How to create a Pre-Loading/ Splash Screen in Nuxt.js before the app starts?

I have tried to add a loader as shown in the nuxt.js documentation in between the routes but its not work. But I'm not able to add a splash screen before the app starts.
Code snippet in my components/loading.vue
<template>
<div v-if="loading" class="loading-page">
<p>Loading...</p>
</div>
</template>
<script>
export default {
data: () => ({
loading: false
}),
methods: {
start(){
this.loading = true
},
finish(){
this.loading = false
}
}
}
</script>
In nuxt.js.config
export default {
...
loading: '~/components/loading.vue'
...
}
As far as I know, you can't use a Vue component as a loading indicator for your your Nuxt app.
You will have to create an HTML document instead. This HTML document does not have to have an <html>, <head> or <body>. It just has to be the splash screen you want to show.
Here's how I did it:
Create an html document ~/assets/loading.html
Add the following to nuxt.config.js file.
loadingIndicator: {
name: '~/assets/loading.html'
}
Save and reload your page, you should now have a custom loading indicator / splash screen.
Example HTML file:
Here's a very simple file to show a splash screen image, when loading a nuxt app.
<div style="height: 100vh; width: 100vw; display: flex; align-items: center; justify-content: center; flex-direction: column; background-color: #004066; margin-left: -8px; margin-top: -8px; overflow: hidden;">
<img width="90%" src="<%= options.img %>">
</div>
NOTE:
Pay attention to <%= options.img %>. I'm making use of options, which can be defined in the nuxt.config.js simply by adding more keys to loadingIndicator, an example can be seen below.
loadingIndicator: {
name: '~/assets/loading.html',
img: '/loading.gif'
}
NOTE 2:
When accessing assets such as images in the loading indicator, you will have to put them in the /static folder.
Documentation: https://nuxtjs.org/docs/2.x/features/loading#custom-indicators
Official examples: https://github.com/nuxt/nuxt.js/tree/dev/packages/vue-app/template/views/loading

Initialize components in for loop from array data

Trying initialize custom elements (3 buttons) in for loop but first element missing text.
LeftMenu.vue
<template>
<div id="left-menu">
<MenuButton v-for="mytext in buttonList" v-bind:key="mytext" v-bind:mytext="mytext"/>
</div>
</template>
<script>
import MenuButton from './components/MenuButton.vue'
export default {
name: 'left-menu',
components: {
MenuButton
},
computed: {
buttonList() {
return ["Test1", "Test2", "Test3"];
}
}
}
</script>
<style>
#left-menu {
width: 200px;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
</style>
MenuButton.vue
<template>
<div id="left-menu-button">
{{mytext}}
</div>
</template>
<script>
export default {
name: 'left-menu-button',
props: {
mytext: String
}
}
</script>
<style>
#left-menu-button {
width: 180px;
height: 50px;
margin-left: 10px;
margin-bottom: 5px;
}
</style>
main.js
import Vue from 'vue'
import LeftMenu from './LeftMenu.vue'
import MenuButton from './components/MenuButton.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(LeftMenu)
}).$mount('#left-menu')
new Vue({
render: h => h(MenuButton)
}).$mount('#left-menu-button');
I am new to vue and still trying to figure out how all part are connected and working together. It just seems very strange that I got 3 buttons but only last two of them have text and first one does not...may be someone can point me to my mistake.
You've assigned an id of left-menu-button to each of your buttons. You've then told Vue to mount something into that id. The first element (i.e. first button) with that id will be treated as the mounting element, which blows away the text.
You should remove the ids from all elements within your templates. The only id should be the one within your HTML file. For styling purposes use classes instead of ids. Then create a single Vue instance (just one call to new Vue, not two) targeting the id of the element inside your HTML file.
It is possible to create multiple Vue instance directly using new Vue but that is rarely necessary. To do that you would need to have multiple target elements within your HTML file.

VueJS + Nuxtjs Unexpected Token 'export'

So i have this code as my index page and It was working, but a couple minutes later it just stopped.
the error is:
SyntaxError
Unexpected token export
Within the script section, If i remove my import then the error will go away, but I need to import it and use it. It was working with the package being imported, but I have looked this code up and down I have no idea what the heck is going on.
Anyone have any suggestions? Am I dumb and have missed something so simple?
<template>
<section class='container'>
<img class='my-4' src="~/assets/images/carousel/1.png" alt="card" />
<div class='text-center mx-auto my-4'>
<button> Send a card </button>
<p class='subtle my-4'> Or </p>
<button class='btn-blue'> Open a card </button>
</div>
<div id="qrcode"></div>
</section>
</template>
<script>
import qrcode from 'qrcode-generator-es6'; <<<<<<<<< SYNTAX ERROR AROUND HERE
export default{
data : function(){
return {};
},
methods : {
},
mounted : function(){
const qr = new qrcode(0, 'M');
qr.addData('https://app.voxicard.com/?v=vx-9FEFCA66-F592-4FF5-97B8-93B2FD78666D');
qr.make();
document.getElementById('qrcode').innerHTML = qr.createSvgTag({
margin : 0,
cellColor : function(){
return "#48658B";
},
});
},
};
</script>
<style>
#qrcode {
width: 200px;
height: 200px;
background-color: red;
}
img {
display: block;
max-height: 500px;
text-align: center;
margin: auto;
}
button {
font-size: 125%;
}
</style>
In your build property in nuxt.config.js you'll need to add a transpile block that targets this library:
build: {
transpile: [
'qrcode-generator-es6'
]
}
This is due to the fact that nuxt expects libraries to export as CJS modules and not ES6 modules.
In nuxt.config.js replace export default { on module.exports = {

How to change Vuetify Text fields text input color

How to change Vuetify v-text-fields input text color. I tried many ways but none of them is worked.
enter image description here
I tried to change the "Hello" text to red. It is not working.
if you want to change color to white just add props dark to v-text-input
There are few ways to do this.
One convenient way is to set a class on the v-text-field, then using specificity set the color of the input.
Note that you need to use the !important flag when not editing the Vuetify theme directly.
In the template,
<v-text-field class="text-green"></v-text-field>
In the CSS (e.g. style tag),
.text-green input {
color: green !important;
}
Live Snippet:
new Vue({
el: '#app',
data: () => ({
name: 'John'
})
})
.text-green input{
color: green !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<div id="app">
<v-app>
<v-text-field class="text-green" v-model="name"></v-text-field>
</v-app>
</div>
What worked for me is exporting the themes colors as css variables (custom properties). Code below
// src/plugins/vuetify.js
import Vue from 'vue'
import Vuetify from 'vuetify/lib'
export default new Vuetify({
theme: {
options: {
customProperties: true,
},
},
})
and then in the scss using the following code:
.v-text-field {
input {
color: var(--v-primary-base);
}
}
This works:
<v-text-field class="text-input-blue"/>
In combination with CSS:
.text-input-blue .v-text-field__slot input {
color: #00f !important;
}
One of the downsides of Javascript frameworks is that the CSS is often hard to customize.
In case you are using v-custom the below scss override will work for you:
<div class="input-text-wrapper">
<v-text-field class="input-text"/>
</div>
Style:
<style scoped lang="scss">
.input-text {
::v-deep {
.v-text-field {
input {
color: blue;
}
}
}
}
</style>
You need to create a file related to CSS styles in the Styles section and name it Override. In that file, you can make any desired changes you need. Put the following code in that file, you can change the color of the border:
.v-text-field {
input {
color: rgba(169, 169, 169, 0.33);
}
}

Vue: Using material-design-icons offline / size

I am using materialdesignicons in my vue project.
require ('../node_modules/#mdi/font/css/materialdesignicons.min.css);
Vue.use(Vuetify, {iconfont:'mdi'});
I have a handful of icons which I dynamically create:
<v-icon>{{ some-mdi-file }}</v-icon>
When I build for production via (npm run build) I get the following error:
asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
img/materialdesignicons-webfont.someHash.svg (3.77 MiB)
That file size is huge because it includes every icon, regardless of whether it's being used. Is there a way to trim that file size down by only packaging the specific icons used. Is there a different package I should be using? Caveat: The project is hosted offline, so I need to include the fonts directly in my project.
I looked at vue-material-design-icons but it looks like it may not work for dynamic icon names and it says nothing about the overall file size/performance.
I have also looked here but clicking on the 'size warning' link brings me to a page where the Vue portion is not filled out
https://dev.materialdesignicons.com/getting-started/webfont
I would recommend using the #mdi/js package for this which provides SVG paths for each icon and supports tree shaking. Currently Vuetify doesn't support SVG icons but it should in the future.
For now, it's easy enough to create a custom icon component:
<template>
<svg :class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path :d="path" />
</svg>
</template>
<script>
export default {
name: 'my-icon',
data: () => ({
path: '',
}),
methods: {
updatePath() {
if (!this.$scopedSlots) return
if (typeof this.$scopedSlots.default !== 'function') return
this.path = this.$scopedSlots
.default()
.map((n) => n.text)
.join('')
},
},
mounted() {
this.updatePath()
},
updated() {
this.updatePath()
},
}
</script>
<style scoped>
.icon {
display: block;
color: inherit;
fill: currentColor;
width: 24px;
height: 24px;
}
<style>
Then to use it you just need to import your component and the icon you want to use:
<template>
<div class="app">
<my-icon>{{mdiCheck}}</my-icon>
</div>
</template>
<script>
import MyIcon from 'path/to/my/icon.vue'
import { mdiCheck } from '#mdi/js'
export default {
name: 'my-app',
components: {
MyIcon,
}
data: () => ({
mdiCheck,
}),
}
</script>