Use vue components as one-offs in layout scaffolding
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
3
down vote
favorite
I've recently been getting into VueJS and CSS Grid. In the past I've always used frameworks like Bootstrap to built up my layout. However, since CSS Grids and VueJS have caught my attention, I'm trying to build a responsive layout using both.
My question now is, can (or should) one generally use vue components for the basic layout? I've built an off-canvas navigation for smaller viewpoints and turned it into a vue component:
hamburger.vue:
<template>
<div class="hamburger">
<div class="bar" :class=" 'bar-top' : this.text "></div>
<div class="bar" :class=" 'bar-middle' : this.text "></div>
<div class="bar" :class=" 'bar-bottom' : this.text "></div>
</div>
</template>
<script>
export default
props: ['text']
</script>
<style lang="scss" scoped>
@import "../../../sass/core/_variables";
.hamburger
position: absolute;
right: 15px;
top: 15px;
display: block;
cursor: pointer;
transition: transform .7s ease-in-out;
@media only screen and (min-width: $tablet)
display: none;
.bar
width: 30px;
height: 4px;
margin-bottom: 5px;
background-color: #000000;
border-radius: 3px;
transition: all .7s ease;
.bar:last-child
margin-bottom: 0px;
.bar-top
transform: translateY(9px) rotateZ(45deg);
.bar-middle
opacity: 0;
.bar-bottom
transform: translateY(-10px) rotateZ(-45deg);
</style>
And I am including it in my main layout like so:
<div id="root">
<header role="banner" :class=" 'nav-open' : mobile ">
<div class="container">
<h2>Header</h2>
<hamburger :text="mobile" @click.native="mobile = !mobile"> </hamburger>
</div>
<section class="hero is-dark is-bold">
<div class="hero-body">
<div class="container">
<h1 class="title">Hero title</h1>
<h2 class="subtitle">Hero subtitle</h2>
</div>
</div>
</section>
</header>
<nav role="navigation" :class=" 'nav-open' : mobile ">
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</div>
</nav>
<section id="main" :class=" 'nav-open' : mobile ">
<main role="main">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</main>
<aside>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim.</p>
</aside>
</section>
<footer role="footer" :class=" 'nav-open' : mobile ">
<div class="container">
<h2>Footer</h2>
</div>
</footer>
</div>
So the way it works is, on my vue instance I set mobile = false
, then by clicking the hamburger I can toggle it and therefore transition the off-canvas nav in.
navigation.scss:
@media only screen and (min-width: $tablet)
ul
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, auto));
> li
margin: 0 auto;
.toggle
display: none;
@media only screen and (max-width: $tablet - 1px)
nav
position: fixed;
top: 0;
bottom: 0;
width: $nav;
right: -$nav;
nav,
header,
section#main,
footer
transition: transform .7s ease-in-out;
.nav-open
transform: translateX(-$nav);
My main layout.scss:
/*! Mobile View */
#root
display: grid;
grid-template-columns: 1fr;
/*! Desktop View */
#root > section #main
margin: 0 auto;
@media only screen and (min-width: $tablet)
display: grid;
grid-column-gap: 20px;
grid-template-columns: repeat(10, 1fr);
main
grid-column: span 7;
aside
grid-column: span 3;
@media only screen and (min-width: $desktop)
width: 90%;
Obviously this is just scaffolding. In the end I'm not sure about 3 things:
Should I keep the mobile / off-canvas navigation as a vue component, or incorporate in my layout scss files? I did it because because this way all the styling, JavaScript and HTML is contained in a single file. On the other hand, the way I learned it, one should create a component if one wants to reuse a particular piece of code more than once, which I'm obviously not doing here. I'm only using it once. Is it still viable (also in terms of performance)?
One thing I'm unsure about is
:class=" 'nav-open' : mobile "
in my markup. The way I build it I have repeat it several times in my markup (once for sliding in the off-canvas nav, but also three times for sliding out (to the right) the header, main section and footer). It's repetitive, but I don't know if it can be done better.Would you have setup the Grid similarly using CSS Grid, or should I change something? I was trying to scaffold it with mobile-first in mind, while being as minimal / performant as possible.
performance html css mobile vue.js
add a comment |Â
up vote
3
down vote
favorite
I've recently been getting into VueJS and CSS Grid. In the past I've always used frameworks like Bootstrap to built up my layout. However, since CSS Grids and VueJS have caught my attention, I'm trying to build a responsive layout using both.
My question now is, can (or should) one generally use vue components for the basic layout? I've built an off-canvas navigation for smaller viewpoints and turned it into a vue component:
hamburger.vue:
<template>
<div class="hamburger">
<div class="bar" :class=" 'bar-top' : this.text "></div>
<div class="bar" :class=" 'bar-middle' : this.text "></div>
<div class="bar" :class=" 'bar-bottom' : this.text "></div>
</div>
</template>
<script>
export default
props: ['text']
</script>
<style lang="scss" scoped>
@import "../../../sass/core/_variables";
.hamburger
position: absolute;
right: 15px;
top: 15px;
display: block;
cursor: pointer;
transition: transform .7s ease-in-out;
@media only screen and (min-width: $tablet)
display: none;
.bar
width: 30px;
height: 4px;
margin-bottom: 5px;
background-color: #000000;
border-radius: 3px;
transition: all .7s ease;
.bar:last-child
margin-bottom: 0px;
.bar-top
transform: translateY(9px) rotateZ(45deg);
.bar-middle
opacity: 0;
.bar-bottom
transform: translateY(-10px) rotateZ(-45deg);
</style>
And I am including it in my main layout like so:
<div id="root">
<header role="banner" :class=" 'nav-open' : mobile ">
<div class="container">
<h2>Header</h2>
<hamburger :text="mobile" @click.native="mobile = !mobile"> </hamburger>
</div>
<section class="hero is-dark is-bold">
<div class="hero-body">
<div class="container">
<h1 class="title">Hero title</h1>
<h2 class="subtitle">Hero subtitle</h2>
</div>
</div>
</section>
</header>
<nav role="navigation" :class=" 'nav-open' : mobile ">
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</div>
</nav>
<section id="main" :class=" 'nav-open' : mobile ">
<main role="main">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</main>
<aside>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim.</p>
</aside>
</section>
<footer role="footer" :class=" 'nav-open' : mobile ">
<div class="container">
<h2>Footer</h2>
</div>
</footer>
</div>
So the way it works is, on my vue instance I set mobile = false
, then by clicking the hamburger I can toggle it and therefore transition the off-canvas nav in.
navigation.scss:
@media only screen and (min-width: $tablet)
ul
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, auto));
> li
margin: 0 auto;
.toggle
display: none;
@media only screen and (max-width: $tablet - 1px)
nav
position: fixed;
top: 0;
bottom: 0;
width: $nav;
right: -$nav;
nav,
header,
section#main,
footer
transition: transform .7s ease-in-out;
.nav-open
transform: translateX(-$nav);
My main layout.scss:
/*! Mobile View */
#root
display: grid;
grid-template-columns: 1fr;
/*! Desktop View */
#root > section #main
margin: 0 auto;
@media only screen and (min-width: $tablet)
display: grid;
grid-column-gap: 20px;
grid-template-columns: repeat(10, 1fr);
main
grid-column: span 7;
aside
grid-column: span 3;
@media only screen and (min-width: $desktop)
width: 90%;
Obviously this is just scaffolding. In the end I'm not sure about 3 things:
Should I keep the mobile / off-canvas navigation as a vue component, or incorporate in my layout scss files? I did it because because this way all the styling, JavaScript and HTML is contained in a single file. On the other hand, the way I learned it, one should create a component if one wants to reuse a particular piece of code more than once, which I'm obviously not doing here. I'm only using it once. Is it still viable (also in terms of performance)?
One thing I'm unsure about is
:class=" 'nav-open' : mobile "
in my markup. The way I build it I have repeat it several times in my markup (once for sliding in the off-canvas nav, but also three times for sliding out (to the right) the header, main section and footer). It's repetitive, but I don't know if it can be done better.Would you have setup the Grid similarly using CSS Grid, or should I change something? I was trying to scaffold it with mobile-first in mind, while being as minimal / performant as possible.
performance html css mobile vue.js
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I've recently been getting into VueJS and CSS Grid. In the past I've always used frameworks like Bootstrap to built up my layout. However, since CSS Grids and VueJS have caught my attention, I'm trying to build a responsive layout using both.
My question now is, can (or should) one generally use vue components for the basic layout? I've built an off-canvas navigation for smaller viewpoints and turned it into a vue component:
hamburger.vue:
<template>
<div class="hamburger">
<div class="bar" :class=" 'bar-top' : this.text "></div>
<div class="bar" :class=" 'bar-middle' : this.text "></div>
<div class="bar" :class=" 'bar-bottom' : this.text "></div>
</div>
</template>
<script>
export default
props: ['text']
</script>
<style lang="scss" scoped>
@import "../../../sass/core/_variables";
.hamburger
position: absolute;
right: 15px;
top: 15px;
display: block;
cursor: pointer;
transition: transform .7s ease-in-out;
@media only screen and (min-width: $tablet)
display: none;
.bar
width: 30px;
height: 4px;
margin-bottom: 5px;
background-color: #000000;
border-radius: 3px;
transition: all .7s ease;
.bar:last-child
margin-bottom: 0px;
.bar-top
transform: translateY(9px) rotateZ(45deg);
.bar-middle
opacity: 0;
.bar-bottom
transform: translateY(-10px) rotateZ(-45deg);
</style>
And I am including it in my main layout like so:
<div id="root">
<header role="banner" :class=" 'nav-open' : mobile ">
<div class="container">
<h2>Header</h2>
<hamburger :text="mobile" @click.native="mobile = !mobile"> </hamburger>
</div>
<section class="hero is-dark is-bold">
<div class="hero-body">
<div class="container">
<h1 class="title">Hero title</h1>
<h2 class="subtitle">Hero subtitle</h2>
</div>
</div>
</section>
</header>
<nav role="navigation" :class=" 'nav-open' : mobile ">
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</div>
</nav>
<section id="main" :class=" 'nav-open' : mobile ">
<main role="main">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</main>
<aside>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim.</p>
</aside>
</section>
<footer role="footer" :class=" 'nav-open' : mobile ">
<div class="container">
<h2>Footer</h2>
</div>
</footer>
</div>
So the way it works is, on my vue instance I set mobile = false
, then by clicking the hamburger I can toggle it and therefore transition the off-canvas nav in.
navigation.scss:
@media only screen and (min-width: $tablet)
ul
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, auto));
> li
margin: 0 auto;
.toggle
display: none;
@media only screen and (max-width: $tablet - 1px)
nav
position: fixed;
top: 0;
bottom: 0;
width: $nav;
right: -$nav;
nav,
header,
section#main,
footer
transition: transform .7s ease-in-out;
.nav-open
transform: translateX(-$nav);
My main layout.scss:
/*! Mobile View */
#root
display: grid;
grid-template-columns: 1fr;
/*! Desktop View */
#root > section #main
margin: 0 auto;
@media only screen and (min-width: $tablet)
display: grid;
grid-column-gap: 20px;
grid-template-columns: repeat(10, 1fr);
main
grid-column: span 7;
aside
grid-column: span 3;
@media only screen and (min-width: $desktop)
width: 90%;
Obviously this is just scaffolding. In the end I'm not sure about 3 things:
Should I keep the mobile / off-canvas navigation as a vue component, or incorporate in my layout scss files? I did it because because this way all the styling, JavaScript and HTML is contained in a single file. On the other hand, the way I learned it, one should create a component if one wants to reuse a particular piece of code more than once, which I'm obviously not doing here. I'm only using it once. Is it still viable (also in terms of performance)?
One thing I'm unsure about is
:class=" 'nav-open' : mobile "
in my markup. The way I build it I have repeat it several times in my markup (once for sliding in the off-canvas nav, but also three times for sliding out (to the right) the header, main section and footer). It's repetitive, but I don't know if it can be done better.Would you have setup the Grid similarly using CSS Grid, or should I change something? I was trying to scaffold it with mobile-first in mind, while being as minimal / performant as possible.
performance html css mobile vue.js
I've recently been getting into VueJS and CSS Grid. In the past I've always used frameworks like Bootstrap to built up my layout. However, since CSS Grids and VueJS have caught my attention, I'm trying to build a responsive layout using both.
My question now is, can (or should) one generally use vue components for the basic layout? I've built an off-canvas navigation for smaller viewpoints and turned it into a vue component:
hamburger.vue:
<template>
<div class="hamburger">
<div class="bar" :class=" 'bar-top' : this.text "></div>
<div class="bar" :class=" 'bar-middle' : this.text "></div>
<div class="bar" :class=" 'bar-bottom' : this.text "></div>
</div>
</template>
<script>
export default
props: ['text']
</script>
<style lang="scss" scoped>
@import "../../../sass/core/_variables";
.hamburger
position: absolute;
right: 15px;
top: 15px;
display: block;
cursor: pointer;
transition: transform .7s ease-in-out;
@media only screen and (min-width: $tablet)
display: none;
.bar
width: 30px;
height: 4px;
margin-bottom: 5px;
background-color: #000000;
border-radius: 3px;
transition: all .7s ease;
.bar:last-child
margin-bottom: 0px;
.bar-top
transform: translateY(9px) rotateZ(45deg);
.bar-middle
opacity: 0;
.bar-bottom
transform: translateY(-10px) rotateZ(-45deg);
</style>
And I am including it in my main layout like so:
<div id="root">
<header role="banner" :class=" 'nav-open' : mobile ">
<div class="container">
<h2>Header</h2>
<hamburger :text="mobile" @click.native="mobile = !mobile"> </hamburger>
</div>
<section class="hero is-dark is-bold">
<div class="hero-body">
<div class="container">
<h1 class="title">Hero title</h1>
<h2 class="subtitle">Hero subtitle</h2>
</div>
</div>
</section>
</header>
<nav role="navigation" :class=" 'nav-open' : mobile ">
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</div>
</nav>
<section id="main" :class=" 'nav-open' : mobile ">
<main role="main">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</main>
<aside>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim.</p>
</aside>
</section>
<footer role="footer" :class=" 'nav-open' : mobile ">
<div class="container">
<h2>Footer</h2>
</div>
</footer>
</div>
So the way it works is, on my vue instance I set mobile = false
, then by clicking the hamburger I can toggle it and therefore transition the off-canvas nav in.
navigation.scss:
@media only screen and (min-width: $tablet)
ul
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, auto));
> li
margin: 0 auto;
.toggle
display: none;
@media only screen and (max-width: $tablet - 1px)
nav
position: fixed;
top: 0;
bottom: 0;
width: $nav;
right: -$nav;
nav,
header,
section#main,
footer
transition: transform .7s ease-in-out;
.nav-open
transform: translateX(-$nav);
My main layout.scss:
/*! Mobile View */
#root
display: grid;
grid-template-columns: 1fr;
/*! Desktop View */
#root > section #main
margin: 0 auto;
@media only screen and (min-width: $tablet)
display: grid;
grid-column-gap: 20px;
grid-template-columns: repeat(10, 1fr);
main
grid-column: span 7;
aside
grid-column: span 3;
@media only screen and (min-width: $desktop)
width: 90%;
Obviously this is just scaffolding. In the end I'm not sure about 3 things:
Should I keep the mobile / off-canvas navigation as a vue component, or incorporate in my layout scss files? I did it because because this way all the styling, JavaScript and HTML is contained in a single file. On the other hand, the way I learned it, one should create a component if one wants to reuse a particular piece of code more than once, which I'm obviously not doing here. I'm only using it once. Is it still viable (also in terms of performance)?
One thing I'm unsure about is
:class=" 'nav-open' : mobile "
in my markup. The way I build it I have repeat it several times in my markup (once for sliding in the off-canvas nav, but also three times for sliding out (to the right) the header, main section and footer). It's repetitive, but I don't know if it can be done better.Would you have setup the Grid similarly using CSS Grid, or should I change something? I was trying to scaffold it with mobile-first in mind, while being as minimal / performant as possible.
performance html css mobile vue.js
edited Jan 27 at 22:43
Jamalâ¦
30.1k11114225
30.1k11114225
asked Jan 27 at 22:27
Artemios Antonio Balbach
161
161
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
0
down vote
I noticed that this question has been unanswered for some time, so I'll try to at least partially review your code.
Components re-use
Components are simply abstractions, an encapsulation of something that can stand on its own. If it is re-usable, that would be great, but it is not a requirement to make something their own component.
A navigation bar is something that can stand on it's own, so I would recommend putting it in a separate component, together with its styling. If most of your components are self-contained, your code will stay easy to reason about.
Repeated class definitions
You should move :class=" 'nav-open' : mobile "
to the top-most element in your application. In your separate navigation, and footer, and header component you can then use the following SCSS:
// Namespacing of all your css
.navigation
// css if your navigation is closed
.nav-open &
// css if your navigation is opened
This makes sure that whatever future element you make that needs to do something when your navigation opens can do so without a problem, even if you change your layout significantly.
Opening and closing your navigation
You currently have your navigation and hamburger icon in the same file. This works, for now, but if your header, footer and navigation get bigger, your App.vue
will become really bloated. I recommend using Vuex to keep the global state of the navigation bar, or a bus such as this one if you do not want to create a state.
You can then do this:
App.vue
<template>
<div :class="appClasses">
<app-header />
<app-navigation />
<app-footer />
</div>
</template>
<script>
import mapGetters from 'vuex'
export default
name: 'app',
computed:
...mapGetters('global', ['navigationOpen']),
appClasses ()
return
'my-app': true,
'nav-open': this.navigationOpen
</script>
<style lang="scss">
.my-app
// There should be very little css in your App.vue file
</style>
A header.vue with a hamburger that toggles the menu
<template>
<header class="app-header">
<hamburger-menu @click="toggleMenu" />
</header>
</template>
<script>
export default
name: 'app-header',
methods:
toggleMenu ()
this.$store.commit('global/toggleNavigation')
</script>
<style lang="scss">
.app-header
// Hopefully a bit more css here
</style>
And a store/modules/global.js file:
const state =
navigationOpen: false
const getters =
navigationOpen (state)
return state.navigationOpen
const mutations =
toggleNavigation (state)
state.navigationOpen = !state.navigationOpen
export default
state,
getters,
mutations
Avoid external scss files
The strength of Vue comes in that all javascript, styling and markup is in a single component file. If you move styling to a separate file, you are sort of defeating this strength as developers are required to switch between files again.
As a rule of thumb, try to limit external scss files to only contain variables, mixins and external dependencies.
Imports in components
You import a file with variables in one of your components. From experience I know this will get old really fast. I recommend splitting your external scss files in two parts:
- Files that only contain variables and mixins, but no actual styling
- Files that contain styling
You include the main styling file in your App.vue
, so it only gets included once. The main variable/mixin file can be added to your webpack config, so that any scss in your component files can use those variables and mixins without an explicit import.
Odd naming of property
Your property this.text
in your hamburger menu is named oddly. It seems to serve some purpose of making the hamburger visible, so I would recommend renaming it to visible
. You can then add it as a single class to the div with class hamburger
and style it from there.
Scss and scoped
The scoped
attribute on your style tag makes Vue add a component identifying attribute to all html elements in that component. This is great when you have classes that could be used by other components or other elements on the same page, but also makes the generated html look rather ugly.
In most cases, the same can be accomplished by using unique names for your components and adding a class to the root element of that component. Then you can style your components by "namespacing" your css:
<template>
<div class="my-component">
</div>
</template>
<script>
export default
name: 'my-component'
</script>
<style lang="scss">
.my-component
.btn
// Styling will only be applied to buttons within this component
</style>
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
I noticed that this question has been unanswered for some time, so I'll try to at least partially review your code.
Components re-use
Components are simply abstractions, an encapsulation of something that can stand on its own. If it is re-usable, that would be great, but it is not a requirement to make something their own component.
A navigation bar is something that can stand on it's own, so I would recommend putting it in a separate component, together with its styling. If most of your components are self-contained, your code will stay easy to reason about.
Repeated class definitions
You should move :class=" 'nav-open' : mobile "
to the top-most element in your application. In your separate navigation, and footer, and header component you can then use the following SCSS:
// Namespacing of all your css
.navigation
// css if your navigation is closed
.nav-open &
// css if your navigation is opened
This makes sure that whatever future element you make that needs to do something when your navigation opens can do so without a problem, even if you change your layout significantly.
Opening and closing your navigation
You currently have your navigation and hamburger icon in the same file. This works, for now, but if your header, footer and navigation get bigger, your App.vue
will become really bloated. I recommend using Vuex to keep the global state of the navigation bar, or a bus such as this one if you do not want to create a state.
You can then do this:
App.vue
<template>
<div :class="appClasses">
<app-header />
<app-navigation />
<app-footer />
</div>
</template>
<script>
import mapGetters from 'vuex'
export default
name: 'app',
computed:
...mapGetters('global', ['navigationOpen']),
appClasses ()
return
'my-app': true,
'nav-open': this.navigationOpen
</script>
<style lang="scss">
.my-app
// There should be very little css in your App.vue file
</style>
A header.vue with a hamburger that toggles the menu
<template>
<header class="app-header">
<hamburger-menu @click="toggleMenu" />
</header>
</template>
<script>
export default
name: 'app-header',
methods:
toggleMenu ()
this.$store.commit('global/toggleNavigation')
</script>
<style lang="scss">
.app-header
// Hopefully a bit more css here
</style>
And a store/modules/global.js file:
const state =
navigationOpen: false
const getters =
navigationOpen (state)
return state.navigationOpen
const mutations =
toggleNavigation (state)
state.navigationOpen = !state.navigationOpen
export default
state,
getters,
mutations
Avoid external scss files
The strength of Vue comes in that all javascript, styling and markup is in a single component file. If you move styling to a separate file, you are sort of defeating this strength as developers are required to switch between files again.
As a rule of thumb, try to limit external scss files to only contain variables, mixins and external dependencies.
Imports in components
You import a file with variables in one of your components. From experience I know this will get old really fast. I recommend splitting your external scss files in two parts:
- Files that only contain variables and mixins, but no actual styling
- Files that contain styling
You include the main styling file in your App.vue
, so it only gets included once. The main variable/mixin file can be added to your webpack config, so that any scss in your component files can use those variables and mixins without an explicit import.
Odd naming of property
Your property this.text
in your hamburger menu is named oddly. It seems to serve some purpose of making the hamburger visible, so I would recommend renaming it to visible
. You can then add it as a single class to the div with class hamburger
and style it from there.
Scss and scoped
The scoped
attribute on your style tag makes Vue add a component identifying attribute to all html elements in that component. This is great when you have classes that could be used by other components or other elements on the same page, but also makes the generated html look rather ugly.
In most cases, the same can be accomplished by using unique names for your components and adding a class to the root element of that component. Then you can style your components by "namespacing" your css:
<template>
<div class="my-component">
</div>
</template>
<script>
export default
name: 'my-component'
</script>
<style lang="scss">
.my-component
.btn
// Styling will only be applied to buttons within this component
</style>
add a comment |Â
up vote
0
down vote
I noticed that this question has been unanswered for some time, so I'll try to at least partially review your code.
Components re-use
Components are simply abstractions, an encapsulation of something that can stand on its own. If it is re-usable, that would be great, but it is not a requirement to make something their own component.
A navigation bar is something that can stand on it's own, so I would recommend putting it in a separate component, together with its styling. If most of your components are self-contained, your code will stay easy to reason about.
Repeated class definitions
You should move :class=" 'nav-open' : mobile "
to the top-most element in your application. In your separate navigation, and footer, and header component you can then use the following SCSS:
// Namespacing of all your css
.navigation
// css if your navigation is closed
.nav-open &
// css if your navigation is opened
This makes sure that whatever future element you make that needs to do something when your navigation opens can do so without a problem, even if you change your layout significantly.
Opening and closing your navigation
You currently have your navigation and hamburger icon in the same file. This works, for now, but if your header, footer and navigation get bigger, your App.vue
will become really bloated. I recommend using Vuex to keep the global state of the navigation bar, or a bus such as this one if you do not want to create a state.
You can then do this:
App.vue
<template>
<div :class="appClasses">
<app-header />
<app-navigation />
<app-footer />
</div>
</template>
<script>
import mapGetters from 'vuex'
export default
name: 'app',
computed:
...mapGetters('global', ['navigationOpen']),
appClasses ()
return
'my-app': true,
'nav-open': this.navigationOpen
</script>
<style lang="scss">
.my-app
// There should be very little css in your App.vue file
</style>
A header.vue with a hamburger that toggles the menu
<template>
<header class="app-header">
<hamburger-menu @click="toggleMenu" />
</header>
</template>
<script>
export default
name: 'app-header',
methods:
toggleMenu ()
this.$store.commit('global/toggleNavigation')
</script>
<style lang="scss">
.app-header
// Hopefully a bit more css here
</style>
And a store/modules/global.js file:
const state =
navigationOpen: false
const getters =
navigationOpen (state)
return state.navigationOpen
const mutations =
toggleNavigation (state)
state.navigationOpen = !state.navigationOpen
export default
state,
getters,
mutations
Avoid external scss files
The strength of Vue comes in that all javascript, styling and markup is in a single component file. If you move styling to a separate file, you are sort of defeating this strength as developers are required to switch between files again.
As a rule of thumb, try to limit external scss files to only contain variables, mixins and external dependencies.
Imports in components
You import a file with variables in one of your components. From experience I know this will get old really fast. I recommend splitting your external scss files in two parts:
- Files that only contain variables and mixins, but no actual styling
- Files that contain styling
You include the main styling file in your App.vue
, so it only gets included once. The main variable/mixin file can be added to your webpack config, so that any scss in your component files can use those variables and mixins without an explicit import.
Odd naming of property
Your property this.text
in your hamburger menu is named oddly. It seems to serve some purpose of making the hamburger visible, so I would recommend renaming it to visible
. You can then add it as a single class to the div with class hamburger
and style it from there.
Scss and scoped
The scoped
attribute on your style tag makes Vue add a component identifying attribute to all html elements in that component. This is great when you have classes that could be used by other components or other elements on the same page, but also makes the generated html look rather ugly.
In most cases, the same can be accomplished by using unique names for your components and adding a class to the root element of that component. Then you can style your components by "namespacing" your css:
<template>
<div class="my-component">
</div>
</template>
<script>
export default
name: 'my-component'
</script>
<style lang="scss">
.my-component
.btn
// Styling will only be applied to buttons within this component
</style>
add a comment |Â
up vote
0
down vote
up vote
0
down vote
I noticed that this question has been unanswered for some time, so I'll try to at least partially review your code.
Components re-use
Components are simply abstractions, an encapsulation of something that can stand on its own. If it is re-usable, that would be great, but it is not a requirement to make something their own component.
A navigation bar is something that can stand on it's own, so I would recommend putting it in a separate component, together with its styling. If most of your components are self-contained, your code will stay easy to reason about.
Repeated class definitions
You should move :class=" 'nav-open' : mobile "
to the top-most element in your application. In your separate navigation, and footer, and header component you can then use the following SCSS:
// Namespacing of all your css
.navigation
// css if your navigation is closed
.nav-open &
// css if your navigation is opened
This makes sure that whatever future element you make that needs to do something when your navigation opens can do so without a problem, even if you change your layout significantly.
Opening and closing your navigation
You currently have your navigation and hamburger icon in the same file. This works, for now, but if your header, footer and navigation get bigger, your App.vue
will become really bloated. I recommend using Vuex to keep the global state of the navigation bar, or a bus such as this one if you do not want to create a state.
You can then do this:
App.vue
<template>
<div :class="appClasses">
<app-header />
<app-navigation />
<app-footer />
</div>
</template>
<script>
import mapGetters from 'vuex'
export default
name: 'app',
computed:
...mapGetters('global', ['navigationOpen']),
appClasses ()
return
'my-app': true,
'nav-open': this.navigationOpen
</script>
<style lang="scss">
.my-app
// There should be very little css in your App.vue file
</style>
A header.vue with a hamburger that toggles the menu
<template>
<header class="app-header">
<hamburger-menu @click="toggleMenu" />
</header>
</template>
<script>
export default
name: 'app-header',
methods:
toggleMenu ()
this.$store.commit('global/toggleNavigation')
</script>
<style lang="scss">
.app-header
// Hopefully a bit more css here
</style>
And a store/modules/global.js file:
const state =
navigationOpen: false
const getters =
navigationOpen (state)
return state.navigationOpen
const mutations =
toggleNavigation (state)
state.navigationOpen = !state.navigationOpen
export default
state,
getters,
mutations
Avoid external scss files
The strength of Vue comes in that all javascript, styling and markup is in a single component file. If you move styling to a separate file, you are sort of defeating this strength as developers are required to switch between files again.
As a rule of thumb, try to limit external scss files to only contain variables, mixins and external dependencies.
Imports in components
You import a file with variables in one of your components. From experience I know this will get old really fast. I recommend splitting your external scss files in two parts:
- Files that only contain variables and mixins, but no actual styling
- Files that contain styling
You include the main styling file in your App.vue
, so it only gets included once. The main variable/mixin file can be added to your webpack config, so that any scss in your component files can use those variables and mixins without an explicit import.
Odd naming of property
Your property this.text
in your hamburger menu is named oddly. It seems to serve some purpose of making the hamburger visible, so I would recommend renaming it to visible
. You can then add it as a single class to the div with class hamburger
and style it from there.
Scss and scoped
The scoped
attribute on your style tag makes Vue add a component identifying attribute to all html elements in that component. This is great when you have classes that could be used by other components or other elements on the same page, but also makes the generated html look rather ugly.
In most cases, the same can be accomplished by using unique names for your components and adding a class to the root element of that component. Then you can style your components by "namespacing" your css:
<template>
<div class="my-component">
</div>
</template>
<script>
export default
name: 'my-component'
</script>
<style lang="scss">
.my-component
.btn
// Styling will only be applied to buttons within this component
</style>
I noticed that this question has been unanswered for some time, so I'll try to at least partially review your code.
Components re-use
Components are simply abstractions, an encapsulation of something that can stand on its own. If it is re-usable, that would be great, but it is not a requirement to make something their own component.
A navigation bar is something that can stand on it's own, so I would recommend putting it in a separate component, together with its styling. If most of your components are self-contained, your code will stay easy to reason about.
Repeated class definitions
You should move :class=" 'nav-open' : mobile "
to the top-most element in your application. In your separate navigation, and footer, and header component you can then use the following SCSS:
// Namespacing of all your css
.navigation
// css if your navigation is closed
.nav-open &
// css if your navigation is opened
This makes sure that whatever future element you make that needs to do something when your navigation opens can do so without a problem, even if you change your layout significantly.
Opening and closing your navigation
You currently have your navigation and hamburger icon in the same file. This works, for now, but if your header, footer and navigation get bigger, your App.vue
will become really bloated. I recommend using Vuex to keep the global state of the navigation bar, or a bus such as this one if you do not want to create a state.
You can then do this:
App.vue
<template>
<div :class="appClasses">
<app-header />
<app-navigation />
<app-footer />
</div>
</template>
<script>
import mapGetters from 'vuex'
export default
name: 'app',
computed:
...mapGetters('global', ['navigationOpen']),
appClasses ()
return
'my-app': true,
'nav-open': this.navigationOpen
</script>
<style lang="scss">
.my-app
// There should be very little css in your App.vue file
</style>
A header.vue with a hamburger that toggles the menu
<template>
<header class="app-header">
<hamburger-menu @click="toggleMenu" />
</header>
</template>
<script>
export default
name: 'app-header',
methods:
toggleMenu ()
this.$store.commit('global/toggleNavigation')
</script>
<style lang="scss">
.app-header
// Hopefully a bit more css here
</style>
And a store/modules/global.js file:
const state =
navigationOpen: false
const getters =
navigationOpen (state)
return state.navigationOpen
const mutations =
toggleNavigation (state)
state.navigationOpen = !state.navigationOpen
export default
state,
getters,
mutations
Avoid external scss files
The strength of Vue comes in that all javascript, styling and markup is in a single component file. If you move styling to a separate file, you are sort of defeating this strength as developers are required to switch between files again.
As a rule of thumb, try to limit external scss files to only contain variables, mixins and external dependencies.
Imports in components
You import a file with variables in one of your components. From experience I know this will get old really fast. I recommend splitting your external scss files in two parts:
- Files that only contain variables and mixins, but no actual styling
- Files that contain styling
You include the main styling file in your App.vue
, so it only gets included once. The main variable/mixin file can be added to your webpack config, so that any scss in your component files can use those variables and mixins without an explicit import.
Odd naming of property
Your property this.text
in your hamburger menu is named oddly. It seems to serve some purpose of making the hamburger visible, so I would recommend renaming it to visible
. You can then add it as a single class to the div with class hamburger
and style it from there.
Scss and scoped
The scoped
attribute on your style tag makes Vue add a component identifying attribute to all html elements in that component. This is great when you have classes that could be used by other components or other elements on the same page, but also makes the generated html look rather ugly.
In most cases, the same can be accomplished by using unique names for your components and adding a class to the root element of that component. Then you can style your components by "namespacing" your css:
<template>
<div class="my-component">
</div>
</template>
<script>
export default
name: 'my-component'
</script>
<style lang="scss">
.my-component
.btn
// Styling will only be applied to buttons within this component
</style>
answered May 12 at 8:42
Sumurai8
2,260315
2,260315
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186159%2fuse-vue-components-as-one-offs-in-layout-scaffolding%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password