Component
<template lang="html">
<div class="chat-log">
<chat-message v-for="message in messages" :message="message"></chat-message>
</div>
</template>
<script>
export default {
props: ["messages"]
}
</script>
<style lang="css">
.chat-log .chat-message:nth-child(even) {
background-color: #ccc;
}
.chat-log {
overflow-y: auto;
max-height: 400px;
}
</style>
When I change the above script code to below. I get errors..
<script>
export default {
props: ["messages"]
},
created() {
$(".chat-log").scrollTop($(".chat-log").prop('scrollHeight'));
}
</script>
Error Details
Unexpected token, expected ;
Issue comes only when adding the created method, Am I missing anything?
The created lifecyle method goes within the body of the Vue component itself, not outside. I mean:
export default {
props: ["messages"],
created() {
$(".chat-log").scrollTop($(".chat-log").prop('scrollHeight'));
}
}
Vue.js Lifecycle
Your created(){} method should be encapsulated within your export default {} block.
In other words, change your code this:
export default {
props: ["messages"],
created() {
$(".chat-log").scrollTop($(".chat-log").prop('scrollHeight'));
}
},
Related
I added a new route, and added an animation in transition to the new route.
I added the following code which pushes the new route (/first) when a button is clicked:
/* From the Template */
<router-view #clickedNext1="onClickTransition" v-slot="{ Component }">
<transition name="route1" mode="out-in">
<component :is="Component"></component>
</transition>
</router-view>
/* From the Script */
methods: {
onClickTransition() {
this.$router.push("/first");
},
Now the problem is that when I click the button and invoke the "onClickTransition" method, the router seems to be pushed just fine, but the page is empty. The components are rendered only when I manually refresh the page by pressing ctrl+R.
I believe the problem perhaps comes from insertion of the animation, but if I refresh the page manually, the animation works just fine. So I have no idea what the problem is. I will be very grateful for help.
Here is the rest of the code for app.vue:
<template>
<router-view #clickedNext1="onClickTransition" v-slot="{ Component }">
<transition :key="$route.fullPath" name="route1" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</template>
<script>
export default {
name: "App",
components: {},
data() {
return {};
},
methods: {
onClickTransition() {
this.$router.push("/first");
},
leave(event) {
event.preventDefault();
event.returnValue = "";
},
},
mounted() {
window.addEventListener("beforeunload", this.leave);
},
beforeUnmount() {
window.removeEventListener("beforeunload", this.leave);
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #fff;
background-color: #151515;
position: relative;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
margin: 0px;
}
/* route transition */
.route1-enter-from {
opacity: 0;
}
.route1-enter-active {
transition: all 3s ease-in;
}
.route1-leave-to {
opacity: 0;
}
.route1-leave-active {
transition: all 3s ease-in;
}
</style>
code section from index.js:
import { createRouter, createWebHistory } from "vue-router";
import MainPage from "../views/MainPage.vue";
import FirstScene from "../views/FirstScene.vue";
const routes = [
{
path: "/",
name: "main",
component: MainPage,
},
{
path: "/first",
name: "first",
component: FirstScene,
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
export default router;
The "onClickTransition" method comes from the "PreStartPage.vue" component, which is the child component of "MainPage.vue" which is the main route.
Once the "Next" button is clicked in the "PreStartPage.vue", it sends an event to the "MainPage.vue" with this.$emit."MainPage.vue" then receives the event with a method named "onClickNext1", which sends out a signal to "App.vue" with another this.$emit. That is where the "#clickedNext1" that is shown in the App.vue comes from.
Here is the code from "PreStartPage.vue":
<script>
export default {
name: "PreStartPage",
methods: {
onClickNext() {
this.$emit("clickedNext");
},
},
};
</script>
Here is the code from "MainPage.vue":
<script>
import PreStartPage from "../components/PreStartPage.vue";
export default {
name: "MainPage",
components: { PreStartPage },
data() {
return { showMain: true, showPre: false };
},
methods: {
toggleMain() {
this.showMain = !this.showMain;
this.showPre = !this.showPre;
},
onClickNext1() {
this.$emit("clickedNext1");
},
},
};
</script>
Try modifying your code like this:
/* From the Template */
<router-view #clickedNext1="onClickTransition" v-slot="{ Component }">
<transition :key="$route.fullPath" name="route1" mode="out-in">
<component :is="Component"></component>
</transition>
</router-view>
The "key" property set to $route.fullPath should ensure that the transition is done correctly whenever the route is changed.
EDIT
To solve this, you can add a ":enter-active-class" and ":leave-active-class" property to the transition component, which allows you to specify the class that should be applied to the element during the transition.
In your App.vue component, you can update the transition component like this:
<transition :key="$route.fullPath" name="route1" mode="out-in" :enter-active-class="'route1-enter-active'" :leave-active-class="'route1-leave-active'">
<component :is="Component" />
</transition>
This will ensure that the correct classes are applied to the element during the transition, and that the components are fully rendered before the animation starts.
For more info i should you to visit the official wiki: https://vuejs.org/guide/built-ins/transition.html#css-based-transitions
You can try using
created() {
this.$watch(() => this.$route.params, () => {
// WATCH FOR ROUTE CHANGES
},
}
Some of my single-file components need to take hover color from props.
My solution is that i set css variables in the following way (the main part is in the mounted(){...})
<template>
<div class="btnWrapper" ref="btnWrapper">...</div>
</template>
...
...
props() {
color1: {type: String, default: 'blue'},
},
mounted () {
this.$refs.btnWrapper.style.setProperty('--wrapHoverColor', this.color1)
}
...
...
<style scoped>
.btnWrapper {
--wrapHoverColor: pink;
}
.btnWrapper:hover {
background-color: var(--wrapHoverColor) !important;
}
</style>
This solution seems kind of woowoo.
But maybe there is no better way with pseudo elements, which are hard to control from js.
Do you guys ever take pseudo element's properties from props in vue components?
You have two different ways to do this.
1 - CSS Variables
As you already know, you can create CSS variables from what you want to port from JS to CSS and put them to your root element :style attr on your components created hooks, and then use them inside your CSS codes with var(--x).
<template>
<button :style="style"> Button </button>
</template>
<script>
export default {
props: ['color', 'hovercolor'],
data() {
return {
style: {
'--color': this.color,
'--hovercolor': this.hovercolor,
},
};
}
}
</script>
<style scoped>
button {
background: var(--color);
}
button:hover {
background: var(--hovercolor);
}
</style>
2 - Vue Component Style
vue-component-style is a tiny (~1kb gzipped) mixin to do this internally. When you active that mixin, you can write your entire style section inside of your component object with full access to the component context.
<template>
<button class="$style.button"> Button </button>
</template>
<script>
export default {
props: ['color', 'hovercolor'],
style({ className }) {
return [
className('button', {
background: this.color,
'&:hover': {
background: this.hovercolor,
},
});
];
}
}
</script>
I am coming from React and Vue frankly seems to be way different to me even from Javascript prospective.
From the boiler plate code (HelloWorld.vue), Say we have the following code snippet
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br />
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener"
>vue-cli documentation</a
>.
</p>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
</style>
Here, I am unable to comprehend how does our export default knows What we need to export
Since the question was marked closed due to duplicate, Sharing the difference between the both
Consider, In case of react (or take it as any function) if we created a function
const someFunc = () => (
<div>
<h1> Test Component </h1>
</div>
)
export default someFunc
Here i am exporting my somefunc which I can import and use it with whatever way I want in other component
import Whatever from "./location"
But in the above Vue snippet, I cannot comprehend the significance of
export default {
name: "HelloWorld",
props: {
msg: String
}
};
What is the significance of exporting this object?
Also, where would If suppose I need to will I write my functions, class?
Everything inside the curly braces on export default {} including methods and data will be exported, and can be imported using import like in your example on React
import Whatever from "./location"
Just to answer your question
Also, where would If suppose I need to will I write my functions, class?
Methods and other data can be included inside the curly braces on export default {}. For example,
<script>
export default {
name: "HelloWorld",
props: {
message: {
type: String
}
},
data() {
return {
// put any data here, e.g.,
isVueDeveloper: true
}
},
methods: {
// put any methods here, e.g.,
firstMethod() {
return;
}
}
}
</script>
I added v-cloak directive on the top div in my component and added css as in docs, set a timeout but it does not work I can see else content and the form styles.
Component code:
<div class="form-in-wrap" v-cloak>
<ul id="example-1" v-if="reports.length>0">
<report-component v-for="report in reports" :report="report" :key="report.id" :options="options">
</report-component>
</ul>
</div>
Component script:
<script>
import ReportComponent from "./ReportComponent";
export default {
components: {ReportComponent},
data: function () {
return {
reports: {
type: Array,
},
report: {
...
},
}
},
created: function () {
var self = this
setTimeout(function () {
self.loadData('/reports')
}, 2000);
},
methods: {
loadData: function() {
get method
}
}
</script>
<style scoped>
[v-cloak] {
display: none !important;
}
</style>
All example creates a Vue instance, but I am using export default in my component. Also it is not a main component, it is included with router can this be the case why it does not work?
I have a component called "item-detail" that has a "item" prop on it, like so:
<item-detail v-ref="itemDetail" v-if="showItemDetail" v-on:clicked="showItemDetail = false"></item-detail>
Then I have an item view component like this:
<item-view v-on:click="onItemClick(this)" title="head" :item="equipment.head"></item-view>
I'm trying to make it so that when the item-view click event fires, it passes that views "item" prop over to the item-detail component. So my onItemClick looks like this:
onItemClick: function(item) {
this.$refs.itemDetail.item = item;
appState.showItemDetail = true;
}
I can't see from the docs how to get a handle to the item-view inside that v-on:click attribute. "this" always equates to the Vue app instance inside the onItemClick method and "item" is also set to the Vue app instance.
Basically the use case is "When the item view is clicked, pass its 'item' property value to the item-detail component and display the item-detail component.".
After having a conversation I proposed that using Vuex was more suitable that passing logic up the chain which could lead to lots of scaling problems later in the project life cycle.
https://github.com/LiamDotPro/VuexStoreExample
This example shows how you can use a store to easily pass logic between components without direct relationships or chaining.
store
/* eslint-disable space-before-function-paren */
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
titleText: "hmm.."
}
const actions = {
changeHomeText: ({commit}, context) => {
commit('UPDATE_TEXT', context)
}
}
const mutations = {
UPDATE_TEXT(state, text) {
state.titleText = text
}
}
const getters = {}
export default new Vuex.Store({
strict: true,
state,
getters,
actions,
mutations
})
app
<template>
<div id="app">
<router-view/>
<div>
<h1>{{getTitle}}</h1>
</div>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
msg: '',
}
},
computed: {
getTitle: function () {
return this.$store.state.titleText;
}
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Inner component
<template>
<div class="innerTile">
<h1>Inner Tile</h1>
<button #click="ChangeTileText()">inner tile button..</button>
</div>
</template>
<script>
export default {
name: '',
data() {
return {
msg: '',
}
},
methods: {
ChangeTileText: function () {
this.$store.dispatch("changeHomeText", "Hi from inner tile..");
}
}
}
</script>
<style scoped>
</style>