i'm making a project with vue, but the thing i'm stuck on is,
v-bind class type if vertical-navigation-mode-side
Add the open class to the header class, of course, the mobileMode value will also be checked.
same way
If the v-bind class is type vertical-navigation-mode-over, the open class in the header class will be searched and deleted for (responsive) in the first place.
exactly what I want to do is available in the image below
APP.VUE
<template>
<header class="dark" :class="type">Menu</header>
<section class="flex">
<TopHeader/>
<div class="flex">
<RouterView/>
</div>
<Footer/>
</section>
</template>
<script setup>
import TopHeader from "./layouts/TopHeader.vue";
import Footer from "./layouts/Footer.vue";
import {computed, onMounted, onUnmounted, provide, ref} from "vue";
const mobileMode = ref(false)
provide('mobileMode', mobileMode)
function useBreakpoints() {
let windowWidth = ref(window.innerWidth)
const onWidthChange = () => windowWidth.value = window.innerWidth
onMounted(() => window.addEventListener('resize', onWidthChange))
onUnmounted(() => window.removeEventListener('resize', onWidthChange))
const type = computed(() => {
if (windowWidth.value < 550) return 'mode-over'
if (windowWidth.value >= 550 && windowWidth.value < 1200) return 'mode-over'
if (windowWidth.value >= 1200) return 'mode-side'
return null;
})
const width = computed(() => windowWidth.value)
return {width, type}
}
const {width, type} = useBreakpoints()
</script>
TOPHEADER.VUE
<template>
<div class="relative">
<button #click="handleStatus">MODE</button>
</div>
</template>
<script setup>
import {inject} from "vue";
const mobileMode = inject('mobileMode');
const handleStatus = () => mobileMode.value = !mobileMode.value
</script>
FOOTER.VUE
<template>
<div class="relative">
<span class="font-medium text-secondary">FOOTER</span>
</div>
<div class="navigation-overlay" v-if="showMenu===true" #click="handleStatus"></div>
</template>
<script setup>
import {inject} from "vue";
const showMenu = inject('showMenu');
const handleStatus = () => showMenu.value = false
</script>
<style scoped>
</style>
Related
I am trying to execute a function from the Food.vue component from Page.vue.
How can I execute a function from an imported component?
I am using Vue 3 Composition API.
This is what I am trying to do:
Food.vue Component
<script setup>
var food = "blueberry"
function changeFood () {
food = "cherry";
}
</script>
<template>
<div>{{food}}</div>
</template>
Page.vue
<script setup>
import { onMounted } from "vue";
import food from "#/components/Food.vue";
onMounted(async() => {
// I want to execute changeFood() from the imported component. How can I do this?
});
</script>
<template>
<food></food>
</template>
I know this can be done with page props, but that's not what Im trying to do. I am trying to execute a function.
You have to expose the method to the parent using defineExpose;
Food.vue
<script setup>
import { ref } from "vue";
const food = ref("blueberry");
const changeFood = () => {
food.value = "cherry";
};
defineExpose({ changeFood });
</script>
<template>
<div>{{food}}</div>
</template>
Page.vue
<script setup>
import { ref, onMounted } from "vue";
import food from "#/components/Food.vue";
const myFood = ref(null);
onMounted(async() => {
if (myFood.value) {
myFood.value.changeFood();
}
});
</script>
<template>
<food ref="myFood" />
</template>
Demo
I have the following barebones component:
<template>
<div v-for="blog in blogs">
<h1 class="text-lg font-medium">{{ blog.title[0].text }}</h1>
<div v-if="blog">
<PrismicRichText :field="blog.body" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { usePrismic } from "#prismicio/vue";
import { PrismicRichText } from "#prismicio/vue";
const { client, predicate } = usePrismic();
const blogs = ref({});
async function getContent() {
const res = await client.getByType("post");
blogs.value = res.results.map((blog: any) => blog.data);
}
onMounted(getContent);
</script>
<style scoped></style>
When running this, the title is displayed just fine, but the body isn't displayed at all. I see the two nested div's being displayed, but there's no content. When logging the body, it is looking correctly, an array of objects. What am I doing wrong here?
i've got an image loader component, which is getting the image id as prop, normally, i should use the ref like this:
<template>
<img
ref="foo"
/>
</template>
<script setup>
const foo = ref(null);
onMounted( () => {
const img = (foo.value as HTMLImageElement);
if (img) {
img.addEventListener("load", () => fitImage(img));
}
});
</script>
But how do i do it with dynamic ref?
<template>
<img
:ref="dynamicRef()"
/>
</template>
<script setup>
const dynamicRef = () => {
return 'image'+props.imageId;
}
</script>
I've already tried to place this inside an array, like
const refs = [];
refs[dynamicRef] = ref(null)
also
const refs = ref([])
refs.value[dynamicRef] = ref(null);
But nothing seems to work
I am a beginner using vue3.
We can use dynamic component like this:
<script setup>
import CommonLayout from "#/components/Layout/CommonLayout.vue";
</script>
<template>
<component :is="CommonLayout>
</component >
</template>
and I try to use dynamic component like this,but it is wrong:
export default {
CommonLayout: () => import("./CommonLayout.vue"),
EmptyLayout: () => import("./EmptyLayout.vue"),
HeaderLayout: () => import("./HeaderLayout.vue"),
};
<script setup>
import layouts from "#/components/Layout/index.js";
const { default: Layout } = await layouts["CommonLayout"]();
</script>
<template>
<Layout>
something
</Layout>
</template>
not error catch but the page show nothing.
and the Layout is the same with CommonLayout:
You need to use defineAsyncComponent
<script setup>
import { defineAsyncComponent } from 'vue'
const CommonLayout = defineAsyncComponent(() => import("./CommonLayout.vue"))
const EmptyLayout = defineAsyncComponent(() => import("./EmptyLayout.vue"))
const HeaderLayout = defineAsyncComponent(() => import("./HeaderLayout.vue"))
</script>
<template>
<component :is="CommonLayout></component>
<component :is="EmptyLayout></component>
<component :is="HeaderLayout></component>
</template>
I have added the Quasar plugin onto an existing Vuejs project.
The problem I am experiencing is that when I use Quasar components, it seems that some of it's styling does not work.
Will provide pics at the bottom of the page.
In my main.js I use Quasar :
projectAuth.onAuthStateChanged(()=>{
if(!app){
app = createApp(App).use(Quasar, quasarUserOptions).use(store).use(router).mount('#app')
}
})
quasarUserOptions:
import './styles/quasar.sass'
import '#quasar/extras/material-icons/material-icons.css'
// To be used on app.use(Quasar, { ... })
export default {
config: {},
plugins: {
}
}
and finally the component in which I wish to use a Quasar component:
<template>
<div id="q-app" style="min-height: 100vh;">
<div class="q-pa-md">
<q-select
filled
hide-bottom-space
options-dense
hide-dropdown-icon
v-model="model"
use-input
clearable
multiple
input-debounce="500"
:options="filterOptions"
#filter="filterFn"
style="width: 200px"
counter
hint="Selected items"
label="Actors"
dense
hide-selected
></q-select>
</div>
</div>
<template/>
<script >
import {ref} from 'vue'
export default {
setup(){
const stringOptions = ['Google', 'Facebook', 'Twitter', 'Apple', 'Oracle']
const filterOptions = ref(stringOptions)
const model = ref(null)
const filterFn = (val, update) => {
update(() => {
if (val === '') {
filterOptions.value = stringOptions
}
else {
const needle = val.toLowerCase()
filterOptions.value = stringOptions.filter(
v => v.toLowerCase().indexOf(needle) > -1
)
}
})
}
return {filterFn, model, filterOptions, stringOptions}
}
}
</script>
<style scoped>
</style>
The following img is what It is supposed to look like and how it displays in codepen :
The following img is what It looks like in my vuejs app :
Both images aren't at the same scale but that is not the problem.
Any advice will be very appreciated