I'm learning Vue, using it with Vuex (without Webpack), but I have several questions when implementing this simple example, it's not clear for me in the docs.
Don't know why, but, I can't access the Vuex store using this
pointer inside component computed
property, for example:
this.$store.state.nav.title
, leading me to use global app
variable instead. Also, this.$parent
and $root
do not work.
Is it correct to initialize multiple Vue components at one time such as this, and shouldn't they have been mounted automatically when I pass components
property to the Vue construct object? What is the right way to initialize, for example, the header, footer and body components at the same time?
var app = new Vue({
el: document.getElementById('app'),
data: {
title:store.state.nav.title
},
computed: {},
methods:{},
mounted:function(){},
updated:function(){},
store:store,
components:{
componentheader,
componentnavbar,
componentbody,
componentfooter
}
});
for (var companent_name in app.$root.$options.components) {
if(typeof app.$root.$options.components[companent_name] === 'function') {
var MyComponent = Vue.extend(app.$root.$options.components[companent_name]);
var component = new MyComponent().$mount();
document.getElementById('app').appendChild(component.$el);
}
}
Here is the full example:
var store = new Vuex.Store({
state: {
nav: {
title: 'my site'
}
},
mutations: {
changeTitle: function(t, a) {
this.state.nav.title = a;
}
}
});
var componentheader = Vue.component('componentheader', {
computed: {
title() {
return app.$store.state.nav.title
}
},
template: '#header_tpl',
mounted: function() {},
updated: function() {}
});
var componentnavbar = Vue.component('componentnavbar', {
computed: {
title() {
return app.$store.state.nav.title
}
},
template: '#navbar_tpl',
mounted: function() {},
updated: function() {}
});
var componentbody = Vue.component('componentbody', {
computed: {
title() {
return app.$store.state.nav.title
}
},
template: '#body_tpl',
mounted: function() {},
updated: function() {}
});
var componentfooter = Vue.component('componentfooter', {
computed: {
title() {
return app.$store.state.nav.title
}
},
template: '#footer_tpl',
mounted: function() {},
updated: function() {}
});
var app = new Vue({
el: document.getElementById('app'),
data: {
title: store.state.nav.title
},
computed: {},
methods: {},
mounted: function() {},
updated: function() {},
store: store,
components: {
componentheader,
componentnavbar,
componentbody,
componentfooter
}
});
Vue.use(Vuex);
for (var companent_name in app.$root.$options.components) {
if (typeof app.$root.$options.components[companent_name] === 'function') {
var MyComponent = Vue.extend(app.$root.$options.components[companent_name]);
var component = new MyComponent().$mount();
document.getElementById('app').appendChild(component.$el);
}
}
Vue.config.devtools = false;
Vue.config.productionTip = false;
* {
margin: 0;
padding: 0;
color: #fff;
text-align: center;
font-size: 19px;
}
html,
body,
.container {
height: 100%;
}
#app {
position: relative;
height: 100%;
min-height: 100%;
}
header {
width: 100%;
height: 80px;
}
nav.navbar {
box-sizing: border-box;
min-height: 100%;
padding-bottom: 90px;
width: 80px;
height: 100%;
position: absolute;
}
.container {
box-sizing: border-box;
min-height: 100%;
padding-bottom: 90px;
color: #000;
}
footer {
height: 80px;
margin-top: -80px;
}
footer,
nav,
header {
background: #000;
}
header div,
footer div {
padding: 15px;
}
nav ul {
list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.5.1/vuex.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="app">
</div>
<script type="text/x-template" id="header_tpl">
<header class="header">
<div>
header {{ title }}
</div>
</header>
</script>
<script type="text/x-template" id="navbar_tpl">
<nav class="navbar">
<ul>
<li>navbar {{ title }}</li>
</ul>
</nav>
</script>
<script type="text/x-template" id="body_tpl">
<div class="container">
<div>
body {{ title }}
</div>
</div>
</script>
<script type="text/x-template" id="footer_tpl">
<footer class="footer">
<div>
footer {{ title }}
</div>
</footer>
</script>
</body>
</html>
You seem confused about Vue Instance and Vue Component. Basically you only need just one Vue instance with multiple components to create your app.
To answer your first question, it does not work because you didn't install the store to each Vue instance that you are created (you only install just 1 instance called app).
for (var companent_name in app.$root.$options.components) {
if (typeof app.$root.$options.components[companent_name] === 'function') {
var MyComponent = Vue.extend(app.$root.$options.components[companent_name]);
var component = new MyComponent({
store // <-- install here
}).$mount();
document.getElementById('app').appendChild(component.$el);
}
}
Working example here
Actually you can just use
store
since allstore
andapp.$store
andthis.$store
is the same object. The advantage ofthis.$store
is you have no need to importstore
to every component file for Single File Components.
To answer your second question,
You are mixing about Global Registration and Local Registration. You should use only one for a component.
For render components you can define your template inside <div id="app">
just like:
<div id="app">
<componentheader></componentheader>
<componentnavbar></componentnavbar>
<componentbody></componentbody>
<componentfooter></componentfooter>
</div>
Working example here