How to customize style of VueJS 2.0 using stylus? - vuejs2

I am using v-text-field without vuetify.min.css just use stylus.
Here is my code.
<template>
<v-text-field type="text" name="password"></v-text-field>
</template>
<style lang="stylus" scoped="scoped">
.input-group_details {
XXX
}
</style>
I am trying to hide some divs in v-text-field.
But I got nothing changed.

That is not possible using scoped styles (That's the point of scoping)
What you could do is either passing down a prop which indicates that the divs are hidden or handle it globally.
passing down a prop:
const textField = {
template: `
<div>
<div>Always shown</div>
<div v-if="shown">
Conditionally shown
</div>
</div>
`,
props: { shown: Boolean }
};
Vue.component('v-text-field', textField);
new Vue({}).$mount('#app');
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
<b>shown = true:</b>
<v-text-field :shown="true"></v-text-field>
<br>
<b>shown = false:</b>
<v-text-field :shown="false"></v-text-field>
</div>

As per https://vue-loader.vuejs.org/en/features/scoped-css.html#notes
you need to use >>> operator for CSS
So this should work:
<style scoped>
>>> .input-group_details {
//your css
}
</style>
You can use lang="stylus" and it will work, but your IDE might throw some syntax errors.
I'm not sure what's correct stylus syntax for that.
Note that it was implemented in v12.2.0

Related

[Vue warn]: Unknown custom element: <cc-text-area> - did you register the component correctly?

I am making a component InputText.vue as follows:
<template>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<h4>Edit Text:</h4>
<textarea class="form-control" cols="50" rows="4" placeholder="Enter text here..." v-model="textBoxInput" #keyup="textChanged"></textarea>
</div>
</div>
</div>
</template>
<script>
export default{
data: function(){
return {
textBoxInput: ""
}
},
methods: {
textChanged: function(){
this.$emit('displayTextChanged', this.textBoxInput);
}
}
}
</script>
Then I am registering and using it in CardFront.vue component as follows:
<style>
.edit-area {
padding: 20px;
height: 800px;
background-color: #d2f9f9;
}
.card-display {
padding: 20px;
height: 800px;
}
</style>
<template>
<div class="row">
<div class="card col-sm-6 edit-area">
<cc-text-area></cc-text-area>
</div>
<div class="card col-sm-6 card-display">
</div>
</div>
</template>
<script>
import TextInput from './TextInput.vue'
export default{
components: {
ccTextArea: TextInput
}
}
<script>
It gives this error:
Error
Please help me out. I am using Vue version 2. Whenever I try to refresh the page, it gives error like: [Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I am making a component InputText.vue as follows:
Check that the filename and component names match.
If you import TextInput from './TextInput.vue' in the using component, then also make sure you name your component that, and optionally add a name property as suggested in the comments.
// TextInput.vue (not InputText.vue)
export default {
name: 'TextInput',
...
}
I solved the issue. Thank you so much everyone for your help. The issue lied in the closing script tag in CardFront.vue component.

Why does this Vue3 transition break data binding?

I have this issue I've been hitting for hours now; I can't understand why it doesn't work as expected.
I pasted an example code below. The issue is that when editing the name, {{name}} is not updated. However, if I remove either of the <transition> element or the v-if="show" condition, then data binding works as expected. Same if the {{name}} is placed outside the transition.
So it seems the transition blocks data binding? However I don't find anything about it in the docs or elsewere. I tested this code in a Vue2 playground, and it works as expected (data binding works). So the behavior seems to depend on Vue3.
Is there something I'm missing? Is it a bug in Vue3?
Thanks in advance for any input or idea.
<template>
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<div v-if="show">
<p>hello, {{name}}</p>
<input v-model="name" type="text" />
</div>
</transition>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
data() {
return {
name: "",
show: true,
}
}
});
</script>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.8s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
It works just fine in plain JS...
So try to focus on the differences:
TypeScript (i cannot use it here on SO) - I really doubt its the cause but you can try
Scoped CSS - did you tried to remove scoped ? There are some issues with scoped CSS and <transition>. Check this issue in Vue-loader. My example is not build with Webpack so Vue-loader is not used but it's for sure used in your project...
const app = Vue.createApp({
data() {
return {
name: "",
show: true,
}
},
template: `
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<div v-if="show">
<p>hello, {{name}}</p>
<input v-model="name" type="text" />
</div>
</transition>
</div>
`
}).mount("#app");
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.8s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.0/vue.global.js"></script>
<div id="app"></div>
I meet same question, you can try to set the initial value of 'show' to false and at the lifeCycle to modify 'show' for true.

How to fix my simple custom v-on directive that does not execute a method immediately?

I am here to ask some help about why is my custom directive not working properly. I am trying to create my own v-on (named v-myOn) directive that would just change the background color of the text when it is clicked. The problem is that the method is executed instantly when vue js application is started (meaning the element background has the color style already) and not when a certain event happened which is when the element is clicked. Thanks in advance!
Update: Problem as what Phil stated is I execute the function directly in the template. But in this case I am trying to pass an argument to the method changeColor. So how could i prevent it from executing while being able to pass arguments?
Here is my code in App.vue:
<template>
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
<h1 v-myOn:click="changeColor('blue')" :style="{background: color}" ref="heading">Directives Exercise</h1>
<!-- Exercise -->
<!-- Build a Custom Directive which works like v-on (Listen for Events) -->
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return{
color: ''
}
},
directives: {
myOn : {
bind(el, binding, vnode) {
el.addEventListener(binding.arg, binding.value)
}
}
},
methods: {
changeColor(color)
{
this.color = color;
}
}
}
</script>
<style>
</style>
You have to wrap in an arrow function otherwise it will get executed immediately as you have discovered and #Phil has pointed out.
<h1 v-myOn:click="() => changeColor('blue')" :style="{background: color}" ref="heading">Directives Exercise</h1>

Nesting a slot in a slot for vue

Update: Here's a simplified version of what I'm trying to achieve here (from the threaded conversation below):
Accept Component A - Accept Component B - Accept a condition - if
condition is true : wrap Component B with Component A [and render]- else only
render component B.
I'm interested in creating a component that renders a wrapper conditionally. I figured a theoretical approach like this would probably be best**:**
<template>
<div>
<slot v-if="wrapIf" name="wrapper">
<slot name="content"></slot>
</slot>
<slot v-else name="content"></slot>
</div>
</template>
<script>
export default {
props: {
wrapIf: Boolean,
}
}
</script>
Then when we implement, it would look something like this:
...
<wrapper-if :wrap-if="!!link">
<a :href="link" slot="wrapper"><slot></slot></a>
<template slot="content">
content
</template>
</wrapper-if>
The idea being that, in this case, if there is a link, then let's wrap the content with the wrapper slot (which can be any component/element). If there isn't, then let's just render the content without the wrapped link. Pretty simple logic, but it seems that I'm misunderstanding some basic vue functionality because this particular example does not work.
What is wrong with my code or is there some kind of native api that already achieves this or perhaps a dependency that does this sort of thing already?
The output should look like this:
wrapIf === true
<a href="some.link">
content
</a>
wrapIf === false
content
Just focus on the content itself, and let the component worry about whether or not to wrap the default or named content slot.
If you need the wrapper to be dynamic, a dynamic component should solve that. I've updated my solution accordingly. So if you need the wrapper to be a label element, just set the tag property to it, and so on and so forth.
const WrapperIf = Vue.extend({
template: `
<div>
<component :is="tag" v-if="wrapIf" class="wrapper">
<slot name="content"></slot>
</component>
<slot v-else name="content"></slot>
</div>
`,
props: ['wrapIf', 'tag']
});
new Vue({
el: '#app',
data() {
return {
link: 'https://stackoverflow.com/company',
tagList: ['p', 'label'],
tag: 'p',
wrap: true
}
},
components: {
WrapperIf
}
})
.wrapper {
display: block;
padding: 10px;
}
p.wrapper {
background-color: lightgray;
}
label.wrapper {
background-color: lavender;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<wrapper-if :wrap-if="wrap" :tag="tag">
<a :href="link" slot="content">
content
</a>
</wrapper-if>
<div>
Change wrapper type:
<select v-model="tag">
<option v-for="tag in tagList">{{tag}}</option>
</select>
</div>
<button #click="wrap = !wrap">Toggle wrapper</button>
</div>

How to import and use image in a Vue single file component?

I think this should be simple, but I am facing some trouble on how to import and use an image in Vue single file component. Can someone help me how to do this? Here is my code snippet:
<template lang="html">
<img src="zapierLogo" />
</template>
<script>
import zapierLogo from 'images/zapier_logo.svg'
export default {
}
</script>
<style lang="css">
</style>
I have tried using :src, src="{{ zapierLogo }}", etc. But nothing seems to work. I was not able to find any example too. Any help?
As simple as:
<template>
<div id="app">
<img src="./assets/logo.png">
</div>
</template>
<script>
export default {
}
</script>
<style lang="css">
</style>
Taken from the project generated by vue cli.
If you want to use your image as a module, do not forget to bind data to your Vuejs component:
<template>
<div id="app">
<img :src="image"/>
</div>
</template>
<script>
import image from "./assets/logo.png"
export default {
data: function () {
return {
image: image
}
}
}
</script>
<style lang="css">
</style>
And a shorter version:
<template>
<div id="app">
<img :src="require('./assets/logo.png')"/>
</div>
</template>
<script>
export default {
}
</script>
<style lang="css">
</style>
It is heavily suggested to make use of webpack when importing pictures from assets and in general for optimisation and pathing purposes
If you wish to load them by webpack you can simply use :src='require('path/to/file')' Make sure you use : otherwise it won't execute the require statement as Javascript.
In typescript you can do almost the exact same operation: :src="require('#/assets/image.png')"
Why the following is generally considered bad practice:
<template>
<div id="app">
<img src="./assets/logo.png">
</div>
</template>
<script>
export default {
}
</script>
<style lang="scss">
</style>
When building using the Vue cli, webpack is not able to ensure that the assets file will maintain a structure that follows the relative importing. This is due to webpack trying to optimize and chunk items appearing inside of the assets folder. If you wish to use a relative import you should do so from within the static folder and use: <img src="./static/logo.png">
I came across this issue recently, and i'm using Typescript.
If you're using Typescript like I am, then you need to import assets like so:
<img src="#/assets/images/logo.png" alt="">
You can also use the root shortcut like so
<template>
<div class="container">
<h1>Recipes</h1>
<img src="#/assets/burger.jpg" />
</div>
</template>
Although this was Nuxt, it should be same with Vue CLI.
These both work for me in JavaScript and TypeScript
<img src="#/assets/images/logo.png" alt="">
or
<img src="./assets/images/logo.png" alt="">
..when everything else fails, like in my case as i tried to import a placeholder i used several times in a multipaged Vuelectro-app - but this time inside a sub-subcomponent where none of the suggested solutions worked (as they usually do)..
<template>
<div id="app">
<img :src="image"/>
</div>
</template>
<script>
export default {
data() { return {image: null, ...} },
methods: {
solveImage(){
const path = require('path')
return path.join(process.cwd(), '/src/assets/img/me.jpg')
},
...
},
mounted: {
this.image = this.solveImage()
...
}
}
</script>
..should do it.
if it even works better in created-lifecycle-hook or you'd prefer to require path globally and just call
this.image = path.join(...)
in one of the hooks - you should test yourself.
I encounter a problem in quasar which is a mobile framework based vue, the tidle syntax ~assets/cover.jpg works in normal component, but not in my dynamic defined component, that is defined by
let c=Vue.component('compName',{...})
finally this work:
computed: {
coverUri() {
return require('../assets/cover.jpg');
}
}
<q-img class="coverImg" :src="coverUri" :height="uiBook.coverHeight" spinner-color="white"/>
according to the explain at https://quasar.dev/quasar-cli/handling-assets
In *.vue components, all your templates and CSS are parsed by vue-html-loader and css-loader to look for asset URLs. For example, in <img src="./logo.png"> and background: url(./logo.png), "./logo.png" is a relative asset path and will be resolved by Webpack as a module dependency.
For Vue 3 I had to use
<template>
<div id="app">
<img :src="zapierLogo" />
</div>
</template>
<script>
import zapierLogo from 'images/zapier_logo.svg'
export default {
...
data: function () {
return {
zapierLogo
}
}
}
</script>
Both src="#/assets/burger.jpg" and src="../assets/burger.jpg" didn't seem to work.
I'm also facing same problem to display the assets image. Finally this two way work fine for me-
<img src="#/assets/img/bg1.png" />
and
<img :src="require('#/assets/img/bg1.png')" />
in my case i have a base64 image and have to import for parse the mimeType and data from the image
this how the template look like
<template>
<img
#click="openCardDetail(item)"
class="thumbnailInfo"
width="80"
height="50"
:src="getImageToShow(item.stationeryThumbnail)"
/>
</template>
Here i imported the image
import image from '#/assets/noimage.png'
then i instantiated it
data: () => ({
...
image: image,
})
then i used only if there is no data in the item
getImageToShow(item) {
if(item != null && item?.mimeType !== '' && item?.base64ImageData !== '') {
return `data:${item?.mimeType};base64,${item.base64ImageData};`
}
return `${this.image}`;
}
it solved my problem