VUE: How to multiple component partials in one file? - html

home.vue
<template>
<app-navbar>
<logo title="navbar"></logo>
<div class="navbar-collapse">
<link href="#first" title="first link"></link>
<link href="#second" title="second link"></link>
<link href="#third" title="third link"></link>
</div>
</app-navbar>
</template>
<script>
export default {
name: "Home",
components: {
AppNavbar: () => import('#/components/navbar.vue')
}
}
</script>
navbar.vue
<script>
export default {
name: "AppNavbar",
props: {
title: {
type: String,
default: "navbarDemo"
},
href: {
type: String,
default: "#"
}
},
template: `
<div class="navbar-container">
<component :is="logo">
<div class="navbar-brand">{{ title }}</div>
</component>
<ul>
<component :is="link">
<li class="item">
<a :href="href" class="link">{{ title }}</a>
</li>
</component
</ul>
</div>
</div>
`
};
</script>
I WANT THIS
<div class="navbar-container">
<div class="navbar-brand">navbar</div>
<div class="navbar-collapse">
<ul>
<li class="item">
first link
</li>
<li class="item">
second link
</li>
<li class="item">
third link
</li>
</ul>
</div>
</div>
What am I doing wrong? Is component used differently? I want to use a component and have another component in it in one file (I don't want to have 20 files here just for navbar). Then compose the structure in this way. Possible?
I'm trying a similar HTML structure as here: link

Here is what you need:
home.vue
<app-navbar :links="links">
<template #logo>
<img src=""/>
</template>
</app-navbar>
data() {
return {
links: [
{ href: '#first", title: 'first link' },
{ href: '#second", title: 'secondlink' },
{ href: '#third", title: 'thirdlink' },
]
}
}
navbar.vue
<template>
<div class="navbar-container">
<div class="navbar-brand">
<slot name="logo" />
</div>
<div class="navbar-collapse">
<ul>
<li v-for="link in links" :key="link.href">
<a :href="link.href">{{ link.title }}</a>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: {
links: Array
}
}
</script>
The logo element is passed through a slot (https://fr.vuejs.org/v2/guide/components-slots.html).
You understood <component> wrongly :p <component> do not declare a component, it's only a way to use a component when its name might change.
Instead of writing
<comp1 v-if="test" /> <comp2 v-else /> you could write <component :is="test ? 'comp1" : 'comp2' />. But comp1 and comp2 components still need to be declared somewhere and imported.
Did you check https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components ?
EDIT: If you want to customize links with scoped-slots:
home.vue
<app-navbar :links="links">
<template #logo>
<img src=""/>
</template>
<template #link="{ href, title }">
<a :href="href">{{ title }}</a>
</template>
</app-navbar>
data() {
return {
links: [
{ href: '#first", title: 'first link' },
{ href: '#second", title: 'secondlink' },
{ href: '#third", title: 'thirdlink' },
]
}
}
navbar.vue
<template>
<div class="navbar-container">
<div class="navbar-brand">
<slot name="logo" />
</div>
<div class="navbar-collapse">
<ul>
<li v-for="link in links" :key="link.href">
<slot name="link" :href="link.href" :title="link.title" />
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: {
links: Array
}
}
</script>
So the looped links are passed through the slot so the parent is handling the rendering

Related

Smooth scroll when clicking a nav link - react js - react three fiber

so what I'm trying to achieve is a smooth scroll effect to a particular div on the page when I click a navbar div. I'm currently doing development with react-three-fiber and am using a custom scroll rig component . I am not too sure how to approach this. below can be found my code.
export default function App() {
const [loading, setLoading] = useState(false)
const [background, setBackground] = useState("base")
const phone = useRef()
useEffect(() => {
setTimeout(() => {
setLoading(true)
}, 2600)
}, [])
return (
<>
<Header />
{!loading ? <></> :
<Suspense>
<Canvas id={background} className="canvas-primary" camera={{ position: [0, 0, 5] }} gl={{ powerPreference: "high-performance", alpha: true, antialias: true, stencil: false, depth: true }} shadows >
<ambientLight intensity={0.5} />
<ScrollControls className='scroll-container' pages={15} >
<fog color="#161616" attach="fog" near={8} far={30} />
<BackgroundContext.Provider value={{ background, setBackground }}>
<Scene phone={phone} />
<MouseTracker phone={phone} />
<Physics allowSleep={false} iterations={15} gravity={[0, -200, 0]}>
{/* <Lamp position={[-3, 5, 0]} /> */}
</Physics>
</BackgroundContext.Provider>
<ContactShadows position={[0, -3.1, 0]} scale={10} blur={1.5} far={10} rotation={[Math.PI / 2, 0, 0]} />
<EffectComposer multisampling={15} disableNormalPass={true} >
<DepthOfField focusDistance={0} focalLength={0.02} bokehScae={2} height={480} />
<Bloom luminanceThreshold={0} luminanceSmoothing={10} height={300} opacity={1} />
</EffectComposer>
</ScrollControls>
<Html className="content"><Content /></Html>
</Canvas>
</Suspense>
}
</>
);
}
export default function Header() {
return (
<header className="primary-header">
<div className="middle">
<h1>SYMPHONY</h1>
</div>
<nav className='primary-navigation'>
<ul className="nav-area" >
<li className="item"><div id="About-us" className="link" onClick={() => handleClick(1)}>About Us</div></li>
<li className="item"><div id="D2C" className="link" onClick={() => handleClick(2)}>D2C Marketing</div></li>
<li className="item"><div id="B2B" className="link" onClick={() => handleClick("B2B")}>B2B Marketing</div></li>
<li className="item"><div id="Team" className="link" onClick={() => handleClick(4)}>Our Team</div></li>
</ul>
</nav>
<div id="et_mobile_nav_menu">
<div className="mobile_nav hidden">
<span className="select_page">Select Page</span>
<span className="mobile_menu_bar mobile_menu_bar_toggle"></span>
<ul id="mobile_menu" className="et_mobile_menu" style={{ display: "none" }}><li id="menu-item-377" className="menu-item menu-item-type-post_type menu-item-object-page menu-item-377 et_first_mobile_item">Marketing</li>
<li id="menu-item-376" className="menu-item menu-item-type-post_type menu-item-object-page menu-item-376">Web Design</li>
<li id="menu-item-374" className="menu-item menu-item-type-post_type menu-item-object-page menu-item-374">Resume</li>
<li id="menu-item-378" className="menu-item menu-item-type-post_type menu-item-object-page menu-item-378">Contact</li>
</ul>
</div>
</div>
</header >)
}
function handleClick(link) {
$("#B2B").on('click', function () { //id of the link which is being clicked
console.log(document.getElementsById('ID09'))
$('*').animate({
scrollTop: $("#ID09").offset().top //id of div to be scrolled
}, 1000);
});
}
export default function Content() {
return (
<div className="content">
<div id={"ID00"} >
<div className="Landing-page-content">
<div className="Landing-page-content-inner">
<h1>Your Marketing To The Next Generation</h1>
<h3> 5,000,000+ viewers</h3>
</div>
</div>
</div>
<div id={"ID01"} />
<div id={"ID02"} />
<div id={"ID03"} />
<div id={"ID04"} />
<div id={"ID05"} />
<div id={"ID06"} />
<div id={"ID07"} />
<div id={"ID08"} />
<div id={"ID09"} />
<div id={"ID010"} />
<div id={"ID011"} />
<div id={"ID012"} />
<div id={"ID013"} />
<div id={"ID014"} />
<div id={"ID015"} />
</div>
)
}
So, I have tried multiple approaches to this, the content component is a child to the main canvas which has an in build scrolling, However I am unsure how to manipulate the scroll bar of this particular component through vanilla js or jquery.

How can I use v-html to pass a text with props and images?

I'm trying to pass different texts to a component list. Each text has a different title and also different content, but the same style. To do this I'm using another component that takes a v-html. I need to pass an image inside this v-html and also several props. However, the image does not appear and the props do not work. How can I solve this? I don't want to change my "message" component because I'm using it in other areas of my website and it's working fine.
App.Vue:
<template>
<div id="app" class="raleway">
<link href='https://fonts.googleapis.com/css?family=Raleway' rel='stylesheet'>
<section class="container grid">
<div
v-for="metadata in this.metadatas"
:key="metadata.id"
class="steps-wrapper text"
>
<Team :metadata="metadata"/>
</div>
</section>
</div>
</template>
<script>
import Team from "./components/Team.vue";
export default {
name: "App",
components: {
Team,
},
data() {
return {
metadatas: [
{
id: 1,
name: "Title1",
country: "Brazil"
},
{
id: 2,
name: "Title2",
country: "England"
},
],
};
},
};
</script>
Component (Team):
<template>
<div id="app" class="raleway">
<section>
<div class="steps-wrapper text">
<Step/>
<div class="image-cropper">
<img src="../assets/me.jpg" alt="" class="profile-pic">
</div>
<Message v-html="content" />
</div>
</section>
</div>
</template>
<script>
import Step from "./CreationView";
import Message from "./Message";
export default {
name: "App",
components: {
Step,
Message
},
props: {
metadata: Object,
},
data() {
return {
content:
"<h2>{{metadata.name}}</h2>\
<h2><img src='../assets/discord.svg' alt=''>Head</h2>\
<p id='country'> {{metadata.country}} </p>\
};
},
};
</script>
Component (Message):
<template>
<div class="container">
<section>
</section>
</div>
</template>
<script>
export default {
name: 'Message',
}
</script>

how to conditionally style links in Nuxt/Vue

I'm building a Nuxt app and am having trouble with conditional styling. What I'm trying to do is apply a different background color to the active link depending on what page it is. I know I can use .nuxt-link-exact-active to style the active link, but I'm stuck on how to make that different on each page.
I have the links in a component that gets rendered on each page. I've tried using .nuxt-link-exact-active at the page level, but it doesn't get picked up.
Here's what I've got so far, which does change the styling depending on the page, but it does it for all the links, and I only want it on the active link. Please let me know if I can clarify anything. Thanks!
<template>
<nav class="flex-container flex-column mt-1">
<NuxtLink to="/about" class="link" :class="classObject">about</NuxtLink>
<div class="mt-1 flex-container">
<NuxtLink to="/projects" class="link" :class="classObject"
>projects</NuxtLink
>
</div>
<div class="mt-1 flex-container">
<NuxtLink to="/contact" class="link" :class="classObject"
>contact</NuxtLink
>
</div>
</nav>
</template>
<script>
export default {
// apply current route name as a class to the matching div
computed: {
classObject() {
return {
about: this.$route.name === 'about',
projects: this.$route.name === 'projects',
contact: this.$route.name === 'contact',
}
},
},
}
</script>
<style lang="scss" scoped>
.about {
background-color: $near-white;
}
.projects {
background-color: $blue;
}
.contact {
background-color: $yellow;
}
</style>
illustration of what I'm trying to do
Instead of changing .nuxt-link-exact-active at the page level, change it in the layout.
So for example, in layouts/default.vue:
<style>
.nuxt-link-exact-active {
background: red;
}
</style>
I came up with a solution— not sure if it's the best way, but it works. Each link is now preceded by a div that only gets rendered on the corresponding page, otherwise a link is rendered.
<template>
<nav class="flex-container flex-column mt-1">
<div v-if="currentPageName === 'about'" class="box about">
<h2>about</h2>
</div>
<div v-else>
<NuxtLink to="/about" class="link">about</NuxtLink>
</div>
<div v-if="currentPageName === 'projects'" class="box projects">
<h2>projects</h2>
</div>
<div v-else>
<NuxtLink to="/projects" class="link">projects</NuxtLink>
</div>
<div v-if="currentPageName === 'contact'" class="box contact">
<h2>contact</h2>
</div>
<div v-else>
<NuxtLink to="/contact" class="link">contact</NuxtLink>
</div>
</nav>
</template>
<script>
export default {
computed: {
currentPageName() {
return this.$route.name
},
},
}
</script>
<style lang="scss" scoped>
.box {
width: 150px;
height: 150px;
}
.about {
background-color: $near-white;
}
.projects {
background-color: $blue;
}
.contact {
background-color: $yellow;
}
</style>
I think the easiest way to check if the path is active or not is $nuxt.$route.path.
<template>
<ul>
<li>
<nuxt-link :to="links[0].path" :class="{'bg-black text-white': links[0].path == path }">{{ links[0].name }}</nuxt-link>
<nuxt-link :to="links[1].path" :class="{secondStyle: links[1].path == path }">{{ links[1].name }}</nuxt-link>
</li>
</ul>
</template>
<script>
export default {
name: "Header",
data() {
return {
path: null,
links: [
{path: "/link1", name: "Link 1"},
{path: "/link2", name: "Link 2"}
],
};
},
mounted() {
this.path = $nuxt.$route.path;
},
};
</script>

Data Property to Hold Index of Array Object during Mouse Over Vuejs

I've used list rendering to create a menu with items from an array. I'm now trying to create a new data property which holds the index of the array item when the item of the menu is mouse-overed but I'm not sure of how to do it. Here's what I've tried:
HTML:
<header>
<nav class="pure-menu pure-menu-horizontal">
<ul id="topmenu" class="pure-menu-list">
<li v-for="item in topmenu" class="pure-menu-item">
<a v-bind:href="item.url" v-on:mouseover="mouseOver" class="pure-menu-link">{{ item.title }}</a></li>
<li v-for="item in topmenu.submenus" class="pure-menu-item">
<a v-bind:href="item.url" class="pure-menu-link">{{ item.title }}</a></li>
</ul>
<div class="pure-menu">
<ul id="submenu" class="pure-menu-list">
</ul>
</div>
</nav>
</header>
JS:
var vueinst = new Vue({
el: '#vuemain',
data: {
topmenuitem : 0,
topmenuhover : false,
topmenu: [
{ title:'Home', url:'/', submenus: [] },
{ title:'About', url:'/about',
submenus: [
{ title:'Who we are', url:'/about#us' },
{ title:'What we do', url:'/about#store' },
{ title:'Our range', url:'/about#range' }
]
},
{ title:'Contact Us', url:'/contact',
submenus: [
{ title:'Information', url:'/contact#info' },
{ title:'Returns', url:'/contact#return' },
{ title:'Locate Us', url:'/contact#locate' }
]
}
]
},
methods: {
mouseOver: function(){
this.topmenuitem = this.topmenu.index;
}
}
});
I'm pretty new to web developing, please help me with this. Thank you!
In your html pass the index of the current item to the mouseOver function like the following:
<header>
<nav class="pure-menu pure-menu-horizontal">
<ul id="topmenu" class="pure-menu-list">
<li v-for="item in topmenu" :key="item.index" class="pure-menu-item">
<a v-bind:href="item.url" v-on:mouseover="mouseOver(item.index)" class="pure-menu-link">{{ item.title }}</a></li>
<li v-for="item in topmenu.submenus" class="pure-menu-item">
<a v-bind:href="item.url" class="pure-menu-link">{{ item.title }}</a></li>
</ul>
<div class="pure-menu">
<ul id="submenu" class="pure-menu-list">
</ul>
</div>
</nav>
</header>
And you should bind key in the v-for like :key="item.index". And then in your mouseOver function accept the index of the item as a parameter and push the element on that index into your new array ass follows.
mouseOver: function(index){
this.topmenuitem.push(index);
}
This way you could get the index of all items hovered on.

Href link issues

I am trying to display all the projects I have coded in my career for my portfolio. I made them into an obj called projects and have mapped through them to render. The problem is that a lot of them are not deployed yet so, for those I want an alert saying "not linked yet" but the link is defaulted to local:3000 and just reloads the page
portfolio: [
{
name: "OmniFood",
description: "",
imgurl: "https://media.giphy.com/media/hvLOGi1KsF02XiZ1DD/giphy.gif",
href: "https://github.io/SbOmniFood/"
},
{
name: "Forkify",
description: "",
imgurl: "https://media.giphy.com/media/ekeOYzzNEpW73RIcSb/giphy.gif",
href: ""
},
{
name: "Connect Four",
description: "",
imgurl: "https://media.giphy.com/media/YrC2lEAcG4loOj2aLI/giphy.gif",
href: ""
},
here is how i render it.
<section id="portfolio">
<h1>Check Out Some of My Projects!</h1>
<div className="portfolioGrid">
{resumeData.portfolio &&
resumeData.portfolio.map(item => {
return (
<a href={`${item.href}`} target="_blank">
<div className="portfolio-item portfolioGridSquare">
<div className="item-wrap">
<div>
<img
src={`${item.imgurl}`}
alt="my projects"
className="item-img"
/>
<div className="overlay">
<div className="portfolio-item-meta">
<h5>{item.name}</h5>
<p>{item.description}</p>
</div>
</div>
</div>
</div>
</div>
</a>
);
})}
<div id="portfolio-wrapper" className=""></div>
</div>
</section>
You should only render a link if the project has a valid href. For example:
const PortfolioList = () => (
<div className="portfolioGrid">
{portfolio.map(item => item.href ? (
<a href={item.href} target="_blank">
<PortfolioItem item={item} />
</a>
) : (
<div onClick={() => alert("not linked yet")}>
<PortfolioItem item={item} />
</div>
))}
</div>
);
const PortfolioItem = ({ item }) => (
<div className="portfolio-item portfolioGridSquare">
<div className="item-wrap">
<div>
<img src={`${item.imgurl}`} alt="my projects" className="item-img" />
<div className="overlay">
<div className="portfolio-item-meta">
<h5>{item.name}</h5>
<p>{item.description}</p>
</div>
</div>
</div>
</div>
</div>
);