Vuetify v-card not inside v-col despite being placed there - vue.js

Okay, so I am trying to setup a simple grid layout with three v-cards at equal distances.
<v-main>
<v-container>
<v-row>
<v-col>
<v-card outlined tile>Card 1</v-card>
</v-col>
<v-col>
<v-card outlined tile>Card 2</v-card>
</v-col>
<v-col>
<v-card outlined tile>Card 3</v-card>
</v-col>
</v-row>
</v-container>
</v-main>
Now, according to the docs and examples they have this should leave me with 3 cards at equal distances, and it does indeed.
Problem is that moment I hover over any of them, they all darken. Looking through the dev tools reveals following issue:
As you can see, the v-cards are not inside v-cols as they should be. Yet, I can't see any errors in the code. Am I missing some extra rule or something?

I believe the problem with darkening on hover should be elsewhere and is not related to the oddity that you see in the Vue debugger. I don't think there is something wrong with your code (compare it to what I mention in #1 below). I tend to believe that the oddity in the debugger is either its own bug or a bug (or feature?) related to how the debugger reflects the Vuetify internals, which doesn't spoil the real app behavior. Here are my arguments:
Look at Vuetify grid with cards example - it is structured the same way as your example (ignore their 'cols' attribute of v-col tag - they showcase an uneven spread of columns, and if you remove that attribute you get pretty much your own example with 3 cards, each inside of its own v-col). However, if you try to copy-paste this standard Vuetify example into an empty Vue CLI app and look into the debugger you see the same odd hierarchy. Check my screenshot: This, however, doesn't spoil the DOM model, where the v-cards are inside of v-cols as expected: This also doesn't create any problems with the actual app behavior. Changing background color at hover (I added that simple CSS change to Vuetify original example just to try to reproduce your original problem) works like a charm. Note that red background in one card of the screenshot - it spreads to the single hovered card only.
I remember seeing the same Vuetify hierarchy oddity in Vue debugger in the past, though it didn't create any problems and didn't seem to be caused by any bugs in the code. I just ignored it at that time.
I also copied your example into a codepen adding just two basic things: the CSS to test hovering (the same as I added in #1 above) and the basic Vue object creation and mounting (which I'd suppose you should have auto-generated).
The CSS:
.v-card:hover {
background-color: red;
}
The JS:
new Vue({
vuetify: new Vuetify(),
}).$mount('#app')
The hovering also works well in that codepen (if I understand correctly the kind of problem you mentioned). I should mention there is one difference in CSS to what I had to use in #1, though. In #1 a custom CSS class (<v-card class="imgCard">) was used as v-cards are inside of another high-level v-card there, so I couldn't use '.v-card' to highlight just one nested card there - they would all highlight together otherwise. BTW, isn't that the problem you experience by chance?
So overall, I think that either your original code has something else that causes the problem (presuming you might have simplified it when writing the question), or I didn't get what kind of hovering you mean. Anyways, I'm quite certain that the oddity in Vuetify debugger doesn't mean there is something wrong with the code itself.

Related

Is it wrong to create a vue component for every svg icon?

I like to use inline svg in my projects because it gives me great control over things like width, height, fill color, stroke width and stroke color using css and js(props). I usually create a vue.js SFC (single file component) for every SVG icon. Here's an example:
<!-- IconsArrowRight.vue -->
<template>
<svg
viewBox="0 0 14 14"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.57026 0.888947L5.98842 2.46006L9.4199 5.89117L0.333374 5.89117L0.333374 8.10895H9.4199L5.98842 11.5401L7.57026 13.1112L13.6681 7.00006L7.57026 0.888947Z"
/>
</svg>
</template>
And then I would use it like this (I'm using tailwindCSS for styling):
<template>
<div>
<IconsArrowRight class="w-8 h-8 text-blue-500" />
</div>
</template>
I use more than 50 icons in my project, and I've created a vue.js component for each one; Is it a bad practice regarding production performance to have so many components just for icons? Should I use font-icons instead, or any other alternative method?
Using one .vue file for one .svg is totally fine IMO. It will not have any big impact performance-wise, just maybe take a bit longer when building your app but nothing that critical IMO.
Also, using it this way can have quite some flexibility in some rare situations regarding HTML specification.
Now, regarding the best approach ever, I'd probably say to use #unocss/preset-icons or any package based on Iconify simply because it will bring you all the available and imaginable icons on the fly, with no drawbacks and a LOT of flexibility + nice DX.
Here is an article in 4 parts that will explain all the reasoning behind this approach and how it can be integrated universally to any solution (even if not using Antfu's solution).
Most probably either using the svg as component or as font icon from performance side I would not consider any issue at all. Vue.js is a framework that can be used for large scale applications and your components are not heavy at all, they just use an SVG.
My personal preference would be to be used as font icons as you mentioned and use a component that you will be passing as props the font icon, so with this way you would have 1 component for all svgs.
About the styling, again using a prop to pass all the styles and bind that prop with the :class
This would be much cleaner I think,
Cheers

ApexCharts in Vue changing options does not work

When I switch between two different charts(that both have different series and options) from ApexChart using v-if that have different chart options set there is some kind of bug that does makes the changed chart not render correctly.
<apexchart v-if="switch1" :options="chartOptions1" :series="series1"></apexchart>
<apexchart v-else :options="chartOptions2" :series="series2"></apexchart>
So for example I have chart options that has fill set and one without. When I switch between them both have fill (the one that didnt have takes the fill options from the other).
Here is the example of this behaviour:
https://codesandbox.io/s/line-with-upper-and-lower-band-apexchart-slhbs?file=/src/components/ChartBasic.vue
Anyone has idea how to fix this?
So thanks to #pkorhone suggestion I managed to find current workaround for this matter is to use v-show instead of v-if and change the height of the other chart by a little bit so that it somehow forces the chart to rerender:
<apexchart v-show="switch1" height="400" :options="chartOptionsBands" :series="seriesBands"></apexchart>
<apexchart v-show="!switch1" height="401" :options="chartOptions" :series="series"></apexchart>

How to get rid of Mismatching childNodes vs. VNodes in NuxtJs [duplicate]

I am using Nuxt.js / Vuejs for my app, and I keep facing this error in different places:
The client-side rendered virtual DOM tree is not matching server-rendered content.
This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>.
Bailing hydration and performing full client-side render.
I would like to understand what is the best way to debug this error? Is their a way I can record/get the virtual DOM tree for client and server so I could compare and find where the error lies?
Mine is a large application and manually verifying is difficult.
Partial answer: with Chrome DevTools, you can localize the issue and see exactly what element caused the issue. Do the following (I did that with Nuxt 5.6.0 and Chrome 64.0.3282.186)
Show DevTools in Chrome (F12)
Load the page that causes "the client-side rendered virtual DOM tree..." warning.
Scroll to the warning in DevTools console.
Click at the source location hyperlink of the warning (in my case it was vue.runtime.esm.js:574).
Set a breakpoint there (left-clicking at line number in the source code browser).
Make the same warning to appear again. I'm not saying it is always possible, but in my case I simply reloaded the page. If there are many warnings, you can check the message by moving a mouse over msg variable.
When you found your message and stopped on a breakpoint, look at the call stack. Click one frame down to call to "patch" to open its source. Hover mouse over hydrate function call 4 lines above the execution line in patch. Hyperlink to the source of hydrate would open.
In the hydrate function, move about 15 lines from the start and set a breakpoint where false is returned after assertNodeMatch returned false. Set the breakpoint there and remove all other breakpoints.
Make the same warning to happen again. Now, when breakpoint is hit, execution should stop in the hydrate function. Switch to DevTools console and evaluate elm and then vnode. Here elm seem to be a server-rendered DOM element while vnode is a virtual DOM node. Elm is printed as HTML so you can figure out where the error happened.
For me this error happened cuz get Array list in AsyncData and rendered <tr> tags by v-for, i put v-for codes in <client-only> blocks and problem solved
This error can be really painfull to debug. In order to quickly get the element causing an issue edit node_modules/vue/dist/vue.esm.js and add the following lines :
// Search for this line:
function hydrate (elm, vnode, insertedVnodeQueue, inVPre) {
var i;
var tag = vnode.tag;
var data = vnode.data;
var children = vnode.children;
inVPre = inVPre || (data && data.pre);
vnode.elm = elm;
// Add the following lines:
console.log('elm', elm)
console.log('vnode', vnode)
console.log('inVpre', inVPre)
// ...
You will get in the console the failing node.
There are a lot of ways of fixing this issue, but most of them are not actual fixes, just hacky band-aids. To note a few:
wrap it into <client-only> tags, beware of some important details tho
using a v-show instead of a v-if
trying to hack some lifecycles
etc...
I highly recommend reading this gorgeous article written by Alexander Lichter
https://blog.lichter.io/posts/vue-hydration-error/
He'll explain you that you should diagnose why this happens and fix the actual issue.
Basically each time something is different from what was generated on the server and what is available when done hydrating on the client will cause this error.
Some of which are:
invalid HTML (having a block element inside of a <p>, same goes for an a tag nested into another, etc...)
3rd party scripts messing around with your components
different state on server vs client
any random is risky (new Date() for example)
any page related to authentication
I highly recommend reading the article to understand in Alexandre's own words how to handle this kind of issue. If you're in a hurry you could always use one band-aid fix but try to actually fix the issue for the best performance and to keep the code clean.
I had the same issue as of nuxt version 2.14.0 while implementing vue-particles package. The fix was to surround the tags with no-ssr and it fixed the issue.
EDIT:
Updated variant of the solution (if Nuxt version is above 2.9.0)
<client-only>
<vue-particles>
</vue-particles>
</client-only>
Old solution:
<no-ssr>
<vue-particles>
</vue-particles>
</no-ssr>
Thanks to budden73's answer, I did a little improvement on the debug process.
Open dev tool
click on the warn message, and click on the first line of the warn message, you will be directed to the Sources panel, with a file name vue.runtime.esm.js?xxxx
ctrl+f to search the above file for assertNodeMatch, not the function, but like:
if (process.env.NODE_ENV !== 'production') {
if (!assertNodeMatch(elm, vnode, inVPre)) {
return false
}
}
Add a break point at the line return false
Refresh the page, and the breakpoint will be triggered.
At the right side of the Sources panel, Under Scope->Local, click on the elm element, you will be directed back to the Elements panel.
The above element is the client side rendered element, compare with your code to see the difference.
If you can't find the source of the bug, the brutal way to fix it is using nuxt's <client-only> tag.
Another likely brutal way is described here. Add an isHydrate variable which default is false, set to true in mounted hook, and render the element after the variable set to true.
For Nuxt version above 2.10 it doesn't need to install nothing, just use the default component <client-only> as mentioned https://nuxtjs.org/api/components-client-only/.
Check the previous warning:
In "nuxt": "^2.12.2", You can spot the cause easily from the previous warning.
In my case:
Incorrect
<nuxt-link to="/game42day">
<a>Game For Today</a>
</nuxt-link>
Correct:
<nuxt-link to="/game42day">
Game For Today
</nuxt-link>
If you're rendering a component conditionally with v-if, then you have two options to solve the problem:
The first one is wrapping the element in <no-ssr></no-ssr> tag.
The second approach is replacing v-if with v-show, here is the link to Vue docs.
Turns out, in my case, I had HTML comment tags , which was causing this stupid, annoying error. Took me too long to figure it out but in case it helps someone.
In my case I had to change this:
<v-expansion-panel-header v-text="name" />
to this:
<v-expansion-panel-header>{{ name }}</v-expansion-panel-header>
I also get many errors due to this problem. I list two cases I often encounter, hope can help you.
With vuetify button, when you create a common component, you should use: <v-btn>{{text}}</v-btn>. Example:
<template>
<v-btn
:width="width"
:color="color"
:class="[rounded ? 'rounded-pill' : 'rounded-lg',textColor]"
v-on:click="onClick"
elevation="0"
:outlined="outlined"
:type="type"
:name="name"
:form="form"
:disabled="disabled"
v-bind="$attrs"
>{{ text }}</v-btn>
</template>
Don't use v-html with <p> tag.
Not use: <p v-html='html'></p>.
Use: <div v-html='html'></div>.
Besides, if you use <client-only></client-only>, this problem is definitely solved, but if you need to SEO page or show google ads, it is not good solution.
Ok this is going to sound silly. I tried a bunch of different solutions for about 15 mins such as restarting the server and deleting the .nuxt directory but I was too lazy to use #budden73's big brain solution. What ended up working for me was simply restarting my computer, give it a shot.
What I have found so far from observation is that when you are using third party packages like jQuery (specially), they sometimes inject html tags into the dom. So Vue/Nuxt looses track of the dom tree and starts complaining.
I was having the same problem and after a while I removed all jQuery and replaced jQuery functionality with Vuejs and those error were all gone.
See here for an example of how to deal with integrations (e.g. Google Analytics or FB Pixel) that modify the DOM. Basically create a plugin and exclude from SSR.
https://nuxtjs.org/faq/ga
What about:
extend (config, ctx) {
config.resolve.symlinks = false
}
See this [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content ( Nuxt / Vue / lerna monorepo )
Now that you found the code causing the problem, the first thing you should do is to verify that your markup (possibly coming from an API) is valid. Code like <p><p>Text</p></p> is not valid because a p element doesn’t allow other block elements (like a paragraph tag) inside.
Be aware, that tags are not allowed to have block level elements like <div> or <p> as children. These <span> tags are used default tag for Vue’s transitions though. You can change that though via <Transition tag="div">.
Check if have used any block-level element inside the inline element.
for example: inside , inside
If you have used an HTML table make sure you have used the tag
In my case, I changed my codes from
<p v-html="$md.render(post.content)"></p>
to
<p>{{ $md.render(post.content) }}</p>
In my case this problem was caused by markdownit module, I solved it by changing the html markup used with v-html. I was with <p> at the beginning and I ended with <div>.
I have some <p> in my v-html render (with $md.render()) so take care if you have same problems with different markups.

V-container do not apply fluid

I dont understand why v-container do not apply fluid option. It always behaves as usual container. Here is code from my App.vue
<template>
<v-app id="main" :style="{background: $vuetify.theme.themes[theme].background}">
<v-container fluid="true">
</v-container>
</v-app>
</template>
I have tried many ways like :fluid="true, or only fluid but it still acts as usual container. After inspecting page I have noticed that it seems like browser is interpretating container class before container--fluid and overlaying it's max width. as on screenshot below. Is there any way to solve this issue? I'm using firefox for inspecting.
For anyone encountering simmilar issue in future:
For learning project I've installed both boostrap-vue and vuetify. When I removed bootstrap vue dependencies container started to act as expected.

Vuetify v-btn component appears different with nuxt attribute

The v-btn (vuetify) component is displayed differently if it has the "nuxt" attribute (to be used as a in the nuxt.js framework).
How to fix it?
The first image is the v-btn component without the "nuxt" (as it should display normally) and the second has the attribute.
<v-btn
class="enter-btn"
large
color="error"
:disabled="!agreed"
>
Accept and Enter
</v-btn>
<v-btn
class="enter-btn"
large
color="error"
:disabled="!agreed"
nuxt
to="/to/url"
>
Accept and Enter
</v-btn>
When the nuxt and to attributes are added, the element changes from <button ...> to <a href="/to/url" ... >.
Unfortunately adding the two code samples to a fresh project does not show the visual difference you have.
The <a> has an additional class v-btn--router, but it doesn't cause the width difference or text alignment issues.
You can debug a little by inspecting each element in the console, looking at the Styles pane and checking for any sources of style (on the RHS) other than Vuetify ones, which are VBtn.sass & VApp.sass.
Since width is one of the problem attributes, it is also worth while checking the width value in the Computed tab.
If it is being set directly by something, you can click it open to see the source of it's value (for example, height is set to 44px by classes .v-btn:not(.v-btn--round).v-size--large in the file VBtn.sass).