Why Vue regular slots also available in this.$scopedSlots? - javascript

Please see this minimum example
Test.vue
<template>
<div>
<slot name="this_is_not_scoped_slots"/>
</div>
</template>
<script >
import Vue from "vue";
export default Vue.extend({
mounted() {
console.log(Object.keys(this.$scopedSlots));
}
});
</script>
App.vue
<template>
<Test>
<template #this_is_not_scoped_slots>But it shows in this.$scopedSlots</template>
</Test>
</template>
<script>
import Test from "./Test.vue";
export default {
components: {
Test
}
};
</script>
In the above example, this console will log out ["this_is_not_scoped_slots"].
Why is this happening?
There are two properties in Vue instance
this.$slots
this.$scopedSlots
These two act really differently:
If you use v-slot:my_scope_name="{ someValue }", then my_scope_name won't show up in this.$slots
However, no matter what you define, your named slots will always show up in this.$scopedSlots
Why is this happening?
I'm building a library, I want to conditional rendering if the user has provided named slots or not, should I always use this.$scopedSlots to detect those things?

According to the official API :
....
All $slots are now also exposed on $scopedSlots as functions. If you work with render functions, it is now recommended to always access slots via $scopedSlots, whether they currently use a scope or not. This will not only make future refactors to add a scope simpler, but also ease your eventual migration to Vue 3, where all slots will be functions.

Related

How to use a template ref on a custom component in vue 3 compositon api

When I try to get the ref of my custom components it results in:
Proxy {__v_skip: true}
[[Handler]]: Object
[[Target]]: Proxy
[[IsRevoked]]: false
but works just fine when replacing d-icon-button with a div tag
Here is a quick example that returns the console log from above:
<template>
<d-icon-button ref="button">
...
</d-icon-button>
</template>
<script lang="ts" setup>
/* imports ... */
const button = ref(null);
onMounted(()=>{
console.log(button.value)
})
And here is the d-icon-button component itself: vuelize -> d-icon-button
I think it has something to do with the wrapper I use in every component, but that's all I know so far
I think this answer might be related to your issue.
You have to expose refs from components because they are "closed" by default: https://vuejs.org/api/sfc-script-setup.html#defineexpose

NuxtJS / Vue.js - Import external component

I am trying to add a widget/plugin/extension system to my existing web ui written with NuxtJS. I have a pages/view.vue single-file component where I would like to implement the extension system. My idea so far is to load dynamically component into the single-file component indicated via a query parameter e.g. /view?extension=example-a.
Idea 1
So far the best i could find is something like this: Include external javascript file in a nuxt.js page. I am just not sure, how the compiled their component, because I tried to build a webpack resource from my example-a component, but couldn't import it in the end like the example above. This was the error message [Vue warn]: Unknown custom element: <example-a> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
Idea 2
Thought I could do it with the http-vue-loader, but I do not know where to start
Idea 3
Maybe I am thinking to far and there is even a easier solution.
You need to directly load all your component into your code. Then you can find your parameter from url in this.$route.query.extension (if you use vue-router) and then load component you want by <component :is="..."/> putting into 'is' a component you want.
<template>
<div>
<component :is="loadedComponent" v-if="loadedComponent !== null"/>
</div>
</template>
<script>
import exampleA from "./exampleA.vue";
import exampleB from "./exampleB.vue";
export default {
data(){
return {components:{'example-a':exampleA , 'example-b':exampleB }}
},
computed:{
loadedComponent(){
return this.components[this.$route.query.extension] ?? null;
}
}
}
</script>

How to detect if vue-router is used in current Vue instance?

I want to develop a library with vue.js component inside. This component will have navigation elements inside. I want it to work with and without vue router. In router mode it should use <router-link> and if no router is used it should return standard <a> tags.
<template>
<div>
<div v-if="vueRouterIsUsed">
<router-link v-bind:to="url">Router link</router-link>
</div>
<div v-else>
<a :href="url">No router</a>
<div>
</div>
</template>
<script>
export default{
props: {
url: {
type: String,
}
}
}
</script>
How to detect if vue-router is used in current Vue instance?
Is there a better way that if/else for doing <router-link> to <a> fallback if no router is installed?
You can check in the created (or mounted) lifecycle hook what is in this.$router you can access all the routes and the router object, which means you can check what you need. Set the isRouter variable based on that.
If you are using Vue3, you can use getCurrentInstance like this :
const isVueRouterInstalled =
!!getCurrentInstance().appContext.config.globalProperties.$router;
However, as the documentation says :
getCurrentInstance is only exposed for advanced use cases, typically in libraries. Usage of getCurrentInstance is strongly discouraged in application code

import and export statements

I am new to Vue and have previously used React to build small apps.
Now, I was going through through the boilerplate code for Vue
Consider this app.vue
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
components: {
HelloWorld
}
}
</script>
Here, I am unable to comprehend following things related to import and export.
Starting from the beginning
<HelloWorld msg="Welcome to Your Vue.js App"/>
here it seems we passing props to our child component.
In react, we used to import statements at the top of the app and then use it in our stateful or stateless component but in contrast, in the above code snippet we are importing it after inside the script tag so as JS compiles the code, how would it know what
<HelloWorld msg="Welcome to Your Vue.js App"/>
is HelloWorld? since it is declared afterwards.
Secondly, I have always worked with exporting and importing functions/classes and this is different and now for me to comprehend. Consider this children component
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
Here, I am unable to comprehend what is happening in export default? I know what export default does but like what is the significance of having properties like name and props inside it?
It's the way Vue is structured. The export default part that you write in the bottom is the part you import/export to the Vue ecosystem (and to your components), this is an ES6/ES2015 feature(module system), one thing to note that the structure you are using is called Single File Components (.vue files).
One great thing about single file components that I like is that you can import another component within the script tag (See: Component Registration), just above export default, then you can reference it in the export default object(exposing it to your component).

Using component without even declaring it

I am very new to Vue and I have read an article or two about it (probably vaguely).
Also, Since I have some understanding of react, I tend to assume certain things to work the same way (but probably they do not)
Anyway, I just started with Quasar and was going through the Quasar boilerplate code
In the myLayout.vue file, I see being used inside my template
<template>
<q-layout view="lHh Lpr lFf">
<q-layout-header>
<q-toolbar
color="negative"
>
<q-btn
flat
dense
round
#click="leftDrawerOpen = !leftDrawerOpen"
aria-label="Menu"
>
<q-icon name="menu" />
</q-btn>
based on my vaguely understanding, I thought for every component we are using to whom we need to pass props we need to import it as well but unfortunately I can't see it in my import-script area
<script>
import { openURL } from 'quasar'
export default {
name: 'MyLayout',
data () {
return {
leftDrawerOpen: this.$q.platform.is.desktop
}
},
methods: {
openURL
}
}
</script>
I would've thought the script to be something like
<script>
import { openURL } from 'quasar'
import {q-icon} from "quasar"
or at least something like that but here we only have
import { openURL } from 'quasar'
Also, Even if we remove the above snippet, our boilerplate app looks to be working fine so here are my two questions
Question 1: What is the use of import { openURL } from 'quasar' (like what it does)
Question 2: How can template contain <quasar-icon> or <quasar-whatever> without even importing it in script tag?
How can template contain <quasar-icon> or <quasar-whatever> without even importing it in script tag?
There are two ways to import components. The first way (which I recommend, and being most similar to React) is to import the component and add it to the components option inside the component that you want to use it within.
App.vue
<div>
<my-component/>
</div>
import MyComponent from 'my-component'
export default {
components: {
MyComponent
}
}
The second way is to import it globally for use within any Vue component in your app. You need only do this once in the entry script of your app. This is what Quasar is doing.
main.js
import Vue from 'vue'
import MyComponent from 'my-component'
Vue.component('my-component', MyComponent)
What is the use of import { openURL } from 'quasar' (like what it does)
I'm not familiar with Quasar, so I can't give you a specific answer here (I don't know what openURL does). You should check the Quasar docs.
openURL is being used as a method here. Perhaps it is being called from somewhere in the template (which you have excluded from the question).
A1) Import statement is 1 way (es6) way to split your code into different files and then import functions/objects/vars from other files or npm modules see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
A2) Vue allows 2 mechanisms to register components. Global and local. Globally registered components does not have to be imported and registered in every component before use (in template or render fn). See URL from comment above https://v2.vuejs.org/v2/guide/components-registration.html#Global-Registration

Categories