When I click on a component, the text changes. Is it possible to smoothly animate this addition of text and increase the height of the block?
Some example:
new Vue({
el: '#app',
data: {
message: 'Hello, i need smooth animation when text added(click me please)'
}
})
new Vue({
el: '#app2',
data: {
message: 'Hello, i need smooth animation when text added(click me please)'
},
methods: {
addText() {
console.log('1');
TweenLite.to(document.getElementById('test'), 2, {text:"This is animation with GSAP (vue plugin to animate anything) and i don't know how to animate it smooth", ease:Linear.easeNone});
}
}
})
#app, #app2 {
border: 1px solid black;
width: 150px;
text-align: center;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenLite.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/plugins/TextPlugin.min.js"></script>
<div id="app" #click="message = message+message+message">
<p>{{ message }}</p>
</div>
<div id="app2" #click="addText">
<p id="test">{{ message }}</p>
</div>
Yes! In fact Vue provides a very robust engine for performing pretty much any kind of web GUI animation you could imagine, using a concept called "transitions". All you need to know is basic CSS! Here's the main documentation for it, and there are plenty of other examples to be found on Google.
https://v2.vuejs.org/v2/guide/transitions.html
U can watch the text value. like this doc.
Related
Thanks #zero298, the dup doesn't apply in important ways. I want to show all of the items in the object array, just conditionally add some UI to each based on user signal. Furthermore, v-if and v-show are very different (as noted here and elsewhere). vue q/a on this site seems to be pretty light -- because it's new -- seems like a mistake to aggressively close on such a new topic.
I can make show work this way...
(NOTE... Please run the snippets in "Expand Snippet" mode to see the behavior over the console stuff. Not sure how to suppress the vue messages in console)
const app = new Vue({
el: '#app',
data: {
show: false
},
methods: {
}
});
.demo{
width: 100px;
height: 30px;
background-color: green;
margin: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.14/vue.js"></script>
<div id="app">
<h3>Hi there</h3>
<div class="demo" #click="show = !show">Click me</div>
<div v-show="show">Show or hide me</div>
</div>
But why can't I make it work this way...
const app = new Vue({
el: '#app',
data: {
objects: [ { name: 'a' }, { name: 'b' }, { name: 'c' } ],
show: [false, false, false]
},
methods: {
}
});
.demo{
width: 100px;
height: 30px;
background-color: green;
margin: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.14/vue.js"></script>
<div id="app">
<div v-for="(object, i) in objects">
<h3>Hi there {{ object.name }} show status is {{ show[i] }}</h3>
<div class="demo" #click="show[i] = !show[i]">Click me</div>
<div v-show="show[i]">Show or hide me</div>
</div>
</div>
I've seen doc content saying not to use v-if in a loop, but what's wrong with v-show? There's evidence that the #click expression assigning to the show array isn't running (see the variable state next to the "hello" message), but why not?
I've tried moving that logic to a method, and moving the v-show check to a method, but with the same results.
Also, my array of objects will appear async and have an unknown (but small) length. I don't want to add a "show" property to those objects because user can save them back to the server. What's the right time and place to allocate a show array of bools that matches the objects array?
This because of vue's change detection. Vue cannot detect that the array is changing.
You have to do something like this to detect it:
<div class="demo" #click="$set(show, i, !show[i])">Click me</div>
Helpful: https://v2.vuejs.org/v2/guide/list.html#Array-Change-Detection
Here is my fiddle : DEMO
new Vue({
el: '#app',
data: {
modules: ['abc', 'def']
}
})
How can I hide/show with v-if based on the values found in an array ( modules[] ) ?
Any help would be appreciated.
Thank you.
You have at least a couple of options to manage this, which I'll describe here. The first is a simple check inside of v-if to see if the item is contained within modules. For example:
<div class="abc box" v-if="modules.indexOf('abc') >= 0">abc</div>
<div class="def box" v-if="modules.indexOf('def') >= 0">def</div>
...
This is a little bit crude and not great from a maintenance or performance perspective. Another option would be to use the modules array as the source for your collection of divs, using v-for. For example:
<div class="box" v-for="module in modules" :class="module">{{ module }}</div>
There's a few things to note here:
v-for looks directly at the modules array to determine the number of divs to render.
The value in the array is used both as the text for the div ({{ module }}) and as one of the classes (:class="module").
The class box is always applied, using the standard class attribute. The combination of this and the :class binding end up with e.g. abc box as the class list.
Here's a working example demonstrating the v-for approach.
new Vue({
el: '#app',
data: {
modules: ['abc', 'def']
}
});
.box {
height: 75px;
width: 75px;
background: #444;
padding: 10px;
margin: 5px;
color: #fff;
}
<script src="https://unpkg.com/vue#2.5.6/dist/vue.js"></script>
<div id="app">
<div class="box" v-for="module in modules" :class="module">{{ module }}</div>
</div>
Using vue.js (and quasar framework), I have a card component. When an event is triggered a button at the bottom of the card is shown. When the button appears, the size of the card increases due to the height of the button which is added. I find this ugly and would prefer the size of the card to be the same before and after having a button.
I tried with some <br> before the button is added to compensate for the height difference, but this is clumsy and does not work properly when I animate the appearance of the button with a fade-in e.g.
As the card(s) will contain various content(size), making a fixed size for card will not really work.
How can I have the same size of my card before and after showing the button?
Quick fix: you must know button height before. Then nest it to element with same height achieved with min-height property :
<div id="button-container" style="min-height: /* your button height */">
<button>Hidden yet</button>
</div>
It is not very elegant way. Use it only if you are not able to use visibility: hidden on button, instead of display: none, as #musicformellons suggest in comment.
I think, this example demonstrates your problem:
new Vue({
el: '#app',
data: {
canShow: false
},
methods: {
toggleButton () {
this.canShow = !this.canShow
}
},
created () {
setInterval(function () {
this.toggleButton()
}.bind(this), 500)
}
})
.bordered {
position: absolute;
border: 2px solid black;
}
<div id="app">
<div class="bordered">
<p>Lorem Ipsum, bla, bla, bla...</p>
<button v-if="canShow">I am just troublemaker</button>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
And I think this is the most elegant, "true Vue way" solution. Moreover, with this solution you need not to know button height before...
new Vue({
el: '#app',
data: {
visibility: false
},
methods: {
toggleButton () {
this.visibility = !this.visibility
},
logIt () {
console.log('button clicked')
}
},
created () {
setInterval(function () {
this.toggleButton()
}.bind(this), 1000)
}
})
.bordered {
position: absolute;
border: 2px solid black;
}
.animate-me {
transition: all .4s;
}
.is-hidden {
opacity: 0;
}
<div id="app">
<div class="bordered">
<p>Lorem Ipsum, bla, bla, bla...</p>
<!-- Render it always, but change visibility as needed instead -->
<button
class="animate-me"
:class="{'is-hidden': visibility}"
#click="logIt"
:disabled="visibility"
>
I am just troublemaker
</button>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
You could give the css of the button position: absolute and the card position: relative, and then fiddle around with the bottom; left; top; right; position settings of the button.
this is my code:
<input type="checkbox" id="checklist-1-checkbox-1" v-on:click="addGreenClass(this)" name="checkbox1-1">
vue.js
new Vue({
el: '#admin-dashboard',
methods: {
addGreenClass(element) {
console.log(element);
},
}
});
In my console, I get the object referring to the whole document rather than referring to the input tag that the checkbox is sourcing the event from.
I'm sure I have the code wrong, but I can't seem to find my answer in similar questions that are asking for the code in pure Javascript in. Could someone help me here? Thank you.
Passing this from the context of an inline statement in the Vue instance's template is going to pass a reference to the Window object.
If you want to access an element from a method in your Vue instance, you can use a ref. No need to pass anything.
Here's the documentation on the ref attribute.
Here's an example:
new Vue({
el: '#app',
methods: {
addGreenClass() {
console.log(this.$refs.input)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
<input ref="input" #click="addGreenClass">
</div>
If you're trying to add a class to the element, you don't need to reference the element at all in your addGreenClass method. Simply bind an array of class names (say inputClasses) to your input using :class="inputClasses", and then push the name of the class you want to the array in your addGreenClass method. Vue will update the DOM automatically:
new Vue({
el: '#app',
data() {
return {
inputClasses: ['large'],
}
},
methods: {
addGreenClass() {
this.inputClasses.push('green');
}
}
})
.large {
height: 40px;
}
.green {
border: 3px solid green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
<input :class="inputClasses" #click="addGreenClass">
</div>
Since you are using checkboxes, I'm stealing a little code from #thanksd and showing how it might be done without even using a method. This highlights Vue's data driven approach.
new Vue({
el: '#app',
data() {
return {
classes: [],
}
}
})
.large {
height: 40px;
}
.green {
border: 3px solid green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
<div :class="classes">Styled DIV</div>
<label>
<input type="checkbox" value="green" v-model="classes">
Green
</label>
<label>
<input type="checkbox" value="large" v-model="classes">
Large
</label>
</div>
I just made my first project with VueJS and Vue-loader.
So I made my first component to show a simple message, it works fine when I make one message, but I get an error when I make multiple messages:
(Emitted value instead of an instance of Error)
Error compiling template:
<message>This is a small message!</message>
<message>Another one</message>
- Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.
This is my code. I'm very new to this and I can't figure out what's wrong.
App.vue
<template>
<message>This is a small message!</message>
<message>Another one</message>
</template>
<script>
import Message from './Components/Message.vue';
export default {
name: 'app',
components: {
Message,
},
data () {
return {
}
}
}
</script>
Message.Vue
<template>
<div class="box">
<p>
<slot></slot>
</p>
</div>
</template>
<script>
export default {
}
</script>
<style>
.box { background-color: #e3e3e3; padding: 10px; border: 1px solid #c5c5c5; margin-bottom: 1em;}
</style>
I hope somebody can help!
The error is pretty self-explanatory. You should have only one root element in each component. So just pack everything in a div.
<template>
<div>
<message>This is a small message!</message>
<message>Another one</message>
</div>
</template>