I have this weird problem where my v-if loop generates a random whitespace in the DOM. I can also visually see it (see image). You see the whitespace to the left of the upload link. The code used to generate the links are pretty simple, but I cannot find out where the whitespace is coming from. Any ideas? Or am I doing something wrong? I tried to reset the cache also to see if that fixed it, but nope.
<template>
<nav class="navbar">
<ul class="nav">
<li class="nav-item nav-brand">
<router-link class="brand nav-link" :to="{ name: 'home' }">{{ this.$appName }}</router-link>
</li>
<template v-for="(link, index) in links">
<li class="nav-item" :key="index">
<router-link class="nav-link" :to="{ name: link.name }">{{ link.title }}</router-link>
</li>
</template>
</ul>
</nav>
</template>
And here is how I use the template:
<AppNavigation :links="[
{ name: 'upload', title: 'Upload' },
{ name: 'login', title: 'Login' }
]" />
<style lang="scss">
// Import variables and mixins
#use '../../scss/vars';
#use '../../scss/mixins';
.navbar {
height:vars.$headerHeight;
.nav {
margin:0;
padding:0;
list-style:none;
height:inherit;
}
.nav-brand {
.brand {
background:-moz-linear-gradient(-35deg, #33b2d9 0%, #e368f5 100%);
background-size:100% 100%;
transition:background-size .25s ease-in-out!important;
&:hover {
background:-moz-linear-gradient(-35deg, #33b2d9 0%, #e368f5 100%)!important;
background-size:100% 200%!important;
}
}
}
.nav-item {
display:inline-flex;
height:inherit;
.nav-link {
height:100%;
display:flex;
align-items:center;
padding:0 20px;
color:vars.$navLinkColor;
font-size:vars.$navLinkSize;
transition:background .05s ease-in-out;
&:hover {
background:lighten(vars.$navItemBg, 5%);
}
}
}
}
</style>
I reproduced the problem by having a predefined <li> element. Then following that, a v-for on a <li> element. Like this:
<li ...>Test</li>
<li v-for="" ...></li>
The whitespace gets added above the v-for.
Solved it by just adding the brand to the list of links to be rendered, and removing the predefined brand element.
Related
I use vue with Axios to read an RSS feed of book titles and display them in a list. Users have a search box to filter the results in the list. This works fine.
However, the transition does not have any effect.
HTML index file
<ul class="booklist">
<my-book
v-for="book in bookFeed"
v-bind:id="book.id"
v-bind:title="book.node_title"
v-bind:body="book.body"
v-bind:path="book.path"
v-bind:author="book.author"
v-bind:coverimg="book.medium_img" >
</my-book>
</ul>
Vue js file
Vue.component('my-book', {
props: ['title','body','coverimg','id','path','author'],
template: `
<transition name='section'>
<li class="row-animated border-bo-dd mb10 pb10 imgshadow" >
...html content of a single book item
</li>
</transition>
`
});
CSS file
.section-leave-active,
.section-enter-active {
transition: .5s;
}
.section-enter {
transform: translateY(100%);
}
.section-leave-to {
transform: translateY(-100%);
}
Any idea where my mistake is? Thank you for any hint.
rhodes
Try to use transition-group component and place it instead of ul tag like :
<transition-group name="section" tag="ul" class="booklist">
<my-book
v-for="book in bookFeed"
v-bind:id="book.id"
v-bind:title="book.node_title"
v-bind:body="book.body"
v-bind:path="book.path"
v-bind:author="book.author"
v-bind:coverimg="book.medium_img" >
</my-book>
</transition-group>
<style src="./LoginButton.scss" lang="scss"></style>
<i18n src="./LoginButton.txt"></i18n>
<script src="./LoginButton.js"></script>
<template>
<div class="header-login component-same ml-10">
<span v-if="showLoggedIn">
<router-link :to="{ name: 'user' }" data-test="login-info-name">
<i class="dl-icon-user12"></i>
<span class="target-text hidden-xs hidden-sm">{{
$t('myAccount')
}}</span>
</router-link>
</span>
<!-- <span v-if="showLoggedIn" class="hidden-xs">
<a #click="logout" data-test="logout-button">
<span>{{ $t("signOut") }}</span>
</a>
</span>-->
<span v-else data-test="login-button">
<router-link :to="{ name: 'login' }">
<i class="dl-icon-user12"></i>
<span class="target-text hidden-xs hidden-sm">{{ $t('Register') }}</span>
</router-link>
</span>
</div>
</template>
I have written the above code for login, Where in this particular line
User has a register button, As soon as the user clicks on the register button, the User will be redirected to another page where he can fill up the basic details, So Instead of redirecting into another page, I want the Register button as a Popup, wherein the popup user can enter details.
also, I tried bootstarp-vue but I wasn't able to find the solution.
It's easier than what you think and mostly you won't need a special CSS lib for that, so the thing to do is just to make another component and call it whatever you want(but modal.vue makes sense here):
//inside modal.vue:
<template>
<div className="modal__wrapper">
<div className="modal">
<slot/>
</div>
</div>
</template>
<style lang="scss" scoped>
.modal{
width: 300px;
height: 100px;
border-radius: 10px;
background-color: white;
padding: 20px 20px;
z-index: 1200;
&__wrapper{
background-color: rgba(0,0,0,0.4);
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
position: absolute;
top: o;
}
}
</style>
in its simplest form, it's just a component with some styling to make it look like a modal (a transparent background(to make it look it's over the previous page) and an absolute position for its wrapper(the transparent one) and some centering techniques for its actual content),I didn't put any script in it(because it's just a simple modal I'm showing you to give the idea how to make yours) and then there is this slot part meaning you can pass your registration form to this modal component, from your parent component and use a boolean flag to just show it on register click
(sure you might need to add some more CSS to the .modal class):
<i18n src="./LoginButton.txt"></i18n>
<script src="./LoginButton.js"></script> <!-- the cleaner thing would
be to import them in your script section somehow -->
<template>
<div class="header-login component-same ml-10">
<span v-if="showLoggedIn">
<router-link :to="{ name: 'user' }" data-test="login-info-name">
<i class="dl-icon-user12"></i>
<span class="target-text hidden-xs hidden-sm">{{
$t('myAccount')
}}</span>
</router-link>
</span>
<span v-else data-test="login-button">
<!-- no need to rerouting to another path -->
<Modal>
<!--your template for registration will go here-->
<i class="dl-icon-user12"></i>
<span class="target-text hidden-xs hidden-sm">{{ $t('Register') }}</span>
</Modal>
</span>
</div>
</template>
//you gotta import the modal component so in your script section you have sth like this(BTW what type of structure are you using for your project? are you using vue-cli's scaffold or what? Are you using babel? cuz I'm gonna assume you are!)
<script>
import Modal from 'The_Relative_Path_to_the_Modal_you_just_created';
export default {
components:{
Modal
},
data(){
return{
showLoggedIn: false
}
}
}
</script>
<style src="./LoginButton.scss" lang="scss"></style>
Well, I have this component and I want to display my data in a grid that looks like this:
I'm looping through my last 3 items of my array
async created(){
const res = await axios.get("https://base-url/posts")
const data = res.data;
this.destaques= data.slice(-3);
}
But when I use v-for I do not see a way to put them in the positions above.
<div v-for="(destaque, i) in destaques" :key='i'>
<nuxt-link :to="`/${destaque.id}`">
<p>{{destaque.title}}</p>
</nuxt-link>
</div>
I've tried this way
<div class="destaques__principal">
<nuxt-link tag="a" :to='`/${destaques[0].id}`' class="wrap-link">
<img :src="`${destaques[0].image[0].name}`" alt="">
<div class="white-box">
<h1 class="white-box__title">{{destaques[0].title}}</h1>
</div>
</nuxt-link>
</div>
<div class="destaques__cima">
<nuxt-link tag="a" :to='`/${destaques[1].id}`' class="wrap-link">
<img :src="`${destaques[1].image[0].name}`" alt="">
<div class="white-box">
<h1 class="white-box__title">{{destaques[1].title}}</h1>
</div>
</nuxt-link>
</div>
<div class="destaques__baixo">
<nuxt-link tag="a" :to='`/${destaques[2].id}`' class="wrap-link">
<img :src="`${destaques[2].image[0].name}`" alt="">
<div class="white-box">
<h1 class="white-box__title">{{destaques[2].title}}</h1>
</div>
</nuxt-link>
</div>
and first it works but when I click on the logo to get back to home page, it gives me an error. I don't get that error when I display the data like this destaque.title. So I was wondering if there is a way to dynamically arrange the items to specific positions on the grid. Is there anyone that could help me out, please?
You could use CSS grid to achieve this. DEMO: https://jsfiddle.net/kpset24g/1/
HTML
<div class="grid">
<div v-for="(item, i) in items" class="box" :class="{'full-height-box': i == 0}">
{{item}}
</div>
</div>
CSS
.grid {
display: grid;
grid-template-columns: 50% 50%;
grid-template-rows: 2;
grid-gap: 10px; /* OPTIONAL */
}
.full-height-box {
grid-row: 1 / span 2;
}
.box { /* Custom styles of your box */ }
JS (Just as demo)
new Vue({
//...
data: {
items: ['Block 1', 'Block 2', 'Block 3']
}
})
<transition-group name="slide">
<section-tree v-for="(section,index) in form.sections" :key="section.random"
:index = "index"
:section = "section"
#selectedSectionAndLesson="selectedSectionAndLesson"
>
</section-tree>
</transition-group>
Transition working fine in above.
Inside Section tree component there is a lesson tree component.
<template>
<ul class="iw-sider-card-wrap">
<div class="iw-sider-card-header">
<a class="card-title"> Course Builder</a>
</div>
<transition-group name="slide">
<lesson-tree v-for="(lesson,index) in lessons" :key="lesson.random"
:index = "index"
#selectedSectionAndLesson="selectedSectionAndLesson"
>
</lesson-tree>
</transition-group>
</ul>
</template>
Random is unique in component. but transition is not working for this component. I am increasing the no of records in sections an lessons array dynamically.
Thanks in Advance.
Did you added some CSS styling too?
This is copied and edited for your case:
.slide-item {
display: inline-block;
margin-right: 10px;
}
.slide-enter-active, .slide-leave-active {
transition: all 1s;
}
.slide-enter, .slide-leave-to /* .slide-leave-active below version 2.1.8 */ {
opacity: 0;
transform: translateY(30px);
}
I'm using app-layout with app-drawer / app-drawer-layout and app-header / app-header-layout (see MWE below). The paper-badge is attached to an element inside the app-header. The first time the page is loaded, it briefly appears in the correct position (issue #12), than disappears off the right of the screen, exactly 256px too far to the right, which is the exact size of the app-drawer.
When the screen is resized, it recalculates the position to the correct place. I suspect that the position is calculated before the drawer is fully loaded.
This does not happen when the app-drawer is retracted and not visible.
I tried running updatePosition() at ready but that did not help.
Here is my MWE:
<template>
<style is="custom-style">
app-drawer {
--app-drawer-content-container: {
background-color: green;
};
}
app-header {
background-color: yellow;
}
</style>
<app-drawer-layout fullbleed>
<app-drawer slot="drawer">
<div id="drawerbox">Navigation Drawer</div>
</app-drawer>
<div class="container">
<app-header-layout>
<app-header id="header" condenses reveals effects="waterfall" slot="header">
<app-toolbar id="toolbarheader">
<div main-title id="toolbartitlebox">Title Toolbar</div>
<paper-icon-button id="discoursebutton" icon="communication:forum"></paper-icon-button>
<paper-badge for="discoursebutton" label="20" title="20 results"></paper-badge>
</app-toolbar>
</app-header>
</app-header-layout>
</div>
</app-drawer-layout>
</template>
One hack that works is to set a setTimeouton the updatePosition():
ready: function() {
var self = this;
setTimeout(function(){
self.$$('paper-badge').updatePosition();
}, 100);
}
But is there a more elegant way of solving this?
Thanks for your help!
One solution is to put paper-badge outside/after app-drawer-layout :
<template>
<style>
app-drawer {
--app-drawer-content-container: {
background-color: green;
}
;
}
app-header {
background-color: yellow;
}
paper-badge {
margin-top: 10px;
}
</style>
<app-drawer-layout fullbleed>
<app-drawer id="drawer" slot="drawer">
<div id="drawerbox">Navigation Drawer</div>
</app-drawer>
<app-header-layout>
<app-header id="header" condenses reveals effects="waterfall" slot="header">
<app-toolbar id="toolbarheader">
<paper-icon-button id="toggle" on-tap="_onToggle" icon="menu"></paper-icon-button>
<div main-title id="toolbartitlebox">Title Toolbar</div>
<paper-icon-button id="discoursebutton" icon="inbox"></paper-icon-button>
<!-- <paper-badge for="discoursebutton" label="20" title="20 results"></paper-badge>-->
</app-toolbar>
</app-header>
</app-header-layout>
<div class="container">
container
</div>
</app-drawer-layout>
<paper-badge for="discoursebutton" id="pd" label="20" title="20 results"></paper-badge>
</template>
Plnkr: http://plnkr.co/edit/V7zGBpqqzRonbAYyudea?p=preview
I avoided this same issue by putting the <paper-icon-button> and <paper-badge> in a container with position: relative, and stopped using the for attribute.
<div style="position: relative">
<paper-icon-button id="notification-icon" icon="social:notifications" onclick="[[showNotifications]]">
</paper-icon-button>
<template is="dom-if" if="[[messages.length]]">
<paper-badge label="[[messages.length]]" class="red"></paper-badge>
</template>
</div>