#javascript #vue.js #vuex
#javascript #vue.js #vuex
Вопрос:
Я изучаю Vue, использую его с Vuex (без Webpack), но у меня есть несколько вопросов при реализации этого простого примера, это непонятно для меня в документах.
-
Не знаю почему, но я не могу получить доступ к хранилищу Vuex, используя
this
указатель внутри свойства компонентаcomputed
, например:this.$store.state.nav.title
, что приводит меня к использованию глобальнойapp
переменной вместо этого. Кроме того,this.$parent
и$root
не работают. -
Правильно ли инициализировать несколько компонентов Vue одновременно, например, таким образом, и не должны ли они монтироваться автоматически, когда я передаю
components
свойство объекту Vue construct? Как правильно инициализировать, например, компоненты верхнего, нижнего колонтитулов и тела одновременно?
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);
}
}
Вот полный пример:
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>
Ответ №1:
Вы, кажется, запутались в экземпляре Vue и компоненте Vue. В принципе, вам нужен только один экземпляр Vue с несколькими компонентами для создания вашего приложения.
Чтобы ответить на ваш первый вопрос, это не работает, потому что вы не установили хранилище для каждого созданного вами экземпляра Vue (вы устанавливаете только 1 экземпляр с именем 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);
}
}
Рабочий пример здесь
На самом деле вы можете просто использовать,
store
поскольку всеstore
иapp.$store
иthis.$store
— это один и тот же объект. Преимуществоthis.$store
в том, что вам не нужно импортироватьstore
в каждый файл компонента для отдельных файловых компонентов.
Чтобы ответить на ваш второй вопрос,
-
Вы путаете глобальную регистрацию и локальную регистрацию. Вы должны использовать только один для компонента.
-
Для компонентов рендеринга вы можете определить свой шаблон внутри
<div id="app">
так же, как:
<div id="app">
<componentheader></componentheader>
<componentnavbar></componentnavbar>
<componentbody></componentbody>
<componentfooter></componentfooter>
</div>
Рабочий пример здесь
Комментарии:
1. Спасибо за ответ на первый вопрос, который я теперь понимаю. Но что касается второго вопроса, причина, по которой я не использую привязку тегов шаблонов непосредственно внутри #app, заключается в том, что я хочу использовать vue router в будущем и монтировать компоненты по требованию.