如何在 Vuex 中为 mapbox 地图设置集中状态? [英] How to setup a centralized state for a mapbox map in Vuex?
问题描述
我刚开始在 vue 中使用 vuex.我确实(大致)了解文档.我有一个特定的问题,我不确定是否应该使用 vuex,如果是,该怎么做.
我有一个应用程序,其中 mapbox 地图在各种布局和组件等中无处不在.因为我将制作几个 vue 单文件组件,但正在使用 mapbox 地图的一个相同实例,我认为这是有意义的在 vuex 商店中启动和管理 mapbox 地图.所以例如当我更改地图布局或其他内容时,它将反映在所有组件中.
当我继续朝着这个方向前进时,我对一些事情感到困惑:
- 地图不仅仅是一个变量/数组,而是一个mapbox类地图的实例.所以我假设初始状态是一个空对象,然后需要对其进行初始化.正确吗?
- 初始化是异步的,我想只能在页面加载后发生.这可能就是我下面的代码不起作用的原因!?
我尝试了以下操作:
制作了一个mapboxmap模块,用
mapboxmap.js
import simple from '../../components/simplestyle'让 mapboxgl = require('mapbox-gl/dist/mapbox-gl.js')//初始状态常量状态 = {我的地图:{},地图加载:假}常量突变 = {loadMap(状态,myMap){state.myMap = myMapstate.mapLoaded = true}}常量动作 = {加载映射(上下文){'使用严格'mapboxgl.accessToken = 'mysecretmapboxcode'让 myMap = new mapboxgl.Map({容器:'地图',风格:简单,哈希:真实,中心:[-74.0073, 40.7124],变焦:16})context.commit('loadMap', myMap)}}导出默认{状态,突变,行动}
作为组件:
Maplayout.vue
<div><div id='map' class='map'>
模板><script type='text/babel'>导出默认{挂载(){this.computed.myMapForView.set().then(() => this.computed.myMapForView.get())},计算:{myMapForView:{//吸气剂得到:函数(){返回 this.$store.state.myMap},//设置器设置:函数(){this.$store.dispatch('loadMap')}}}}
这不起作用.非常感谢有关解决方法和具体方法的任何建议.
我在浏览器中收到的错误消息:
vue.runtime.common.js?d43f:433 TypeError:无法读取未定义的属性myMapForView"在 VueComponent.mounted (eval at 162 (0.ce2d9bf....js:21), :8:18)在 callHook(在 <anonymous> (app.js:794), <anonymous>:2335:19 处评估)在 Object.insert (eval at (app.js:794), :2525:5)在 invokeInsertHook (eval at (app.js:794), :4352:28)在 VueComponent.patch [as __patch__] (eval at (app.js:794), :4508:5)在 VueComponent.Vue._update (eval at (app.js:794), :2222:19)在 VueComponent.eval (eval at (app.js:794), :2189:10)在 Watcher.get(在 (app.js:794), :1652:27 处评估)在 Watcher.run(在 <anonymous> (app.js:794), <anonymous>:1721:22 评估)在flushSchedulerQueue (eval at (app.js:794), :1539:13)logError @ vue.runtime.common.js?d43f:433
从 this.computed.myMapForView
更改为 this.myMapForView
后,我在浏览器中收到以下错误消息:
vue.runtime.common.js?d43f:433类型错误:无法读取未定义的属性set"在 VueComponent.mounted (eval at 162 (0.85b2be9....js:21), :6:22)在 callHook(在 <anonymous> (app.js:794), <anonymous>:2335:19 处评估)在 Object.insert (eval at (app.js:794), :2525:5)在 invokeInsertHook (eval at (app.js:794), :4352:28)在 VueComponent.patch [as __patch__] (eval at (app.js:794), :4508:5)在 VueComponent.Vue._update (eval at (app.js:794), :2222:19)在 VueComponent.eval (eval at (app.js:794), :2189:10)在 Watcher.get(在 (app.js:794), :1652:27 处评估)在 Watcher.run(在 <anonymous> (app.js:794), <anonymous>:1721:22 评估)在flushSchedulerQueue (eval at (app.js:794), :1539:13)logError @ vue.runtime.common.js?d43f:433
在我看来 new mapboxgl.Map()
是一个异步函数并且在 vuex Actions 可以包含任意异步操作而不是来自 mutations 的变更.变异处理函数必须是同步的.
所以你应该在如下操作中执行new mapboxgl.Map()
:
import simple from '../../components/simplestyle'让 mapboxgl = require('mapbox-gl/dist/mapbox-gl.js')//初始状态常量状态 = {我的地图:{},地图加载:假}常量突变 = {loadMap(状态,myMap){state.myMap = myMap}}常量动作 = {加载映射(上下文){'使用严格'mapboxgl.accessToken = 'mysecretmapboxkey'var myMap = new mapboxgl.Map({容器:'地图',风格:简单,哈希:真实,中心:[-74.0073, 40.7124],变焦:16})context.commit('loadMap', myMap)}}导出默认{状态,突变,行动}
<小时>
编辑:
鉴于您的鼠标交互导致状态发生变化,您可以使用 使用 getter 和 setter 在 vue 实例中计算属性,如下所示:
计算:{myMapForView:{//吸气剂得到:函数(){返回 this.$store.state.我的地图},//设置器设置:功能(新地图){this.$store.commit('loadMap', newMap)}}}
<小时>
工作小提琴:http://jsfiddle.net/aucqteLn/
还要检查:Vuex store 带有strict: true";不起作用
I just started using vuex with vue. I do (roughly) understand the docs. I have a specific issue for which I am not sure whether I should use vuex and if so how to go about.
I have an app in which mapbox map(s) are omnipresent in various layouts and components etc. As I will be making several vue single file components but are working with one same instance of a mapbox map I think it makes sense to have the mapbox map initiated and managed in the vuex store. So e.g. when I change the map layout or something else, it will be reflected in all components.
When I continue in this direction I am puzzled by a couple of things:
- The map is not just a variable/ array, but an instance of the mapbox class map. So I suppose the initial state is an empty object and then it needs to be initialized. Correct?
- The initialization is asynchronous and can only happen after the page is loaded, I suppose. That might be why my code below is not working!?
I tried following:
Made a mapboxmap module, with
mapboxmap.js
import simple from '../../components/simplestyle'
let mapboxgl = require('mapbox-gl/dist/mapbox-gl.js')
// initial state
const state = {
myMap: {},
mapLoaded: false
}
const mutations = {
loadMap (state, myMap) {
state.myMap = myMap
state.mapLoaded = true
}
}
const actions = {
loadMap (context) {
'use strict'
mapboxgl.accessToken = 'mysecretmapboxcode'
let myMap = new mapboxgl.Map({
container: 'map',
style: simple,
hash: true,
center: [-74.0073, 40.7124],
zoom: 16
})
context.commit('loadMap', myMap)
}
}
export default {
state,
mutations,
actions
}
And as component:
Maplayout.vue
<template>
<div>
<div id='map' class='map'>
</div>
</div>
</template>
<script type='text/babel'>
export default {
mounted () {
this.computed.myMapForView.set().then(() => this.computed.myMapForView.get())
},
computed: {
myMapForView: {
// getter
get: function () {
return this.$store.state.myMap
},
// setter
set: function () {
this.$store.dispatch('loadMap')
}
}
}
}
</script>
Which does not work. Any suggestions on the solution approach and specific way to do this is much appreciated.
Error message I get in the browser:
vue.runtime.common.js?d43f:433 TypeError: Cannot read property 'myMapForView' of undefined
at VueComponent.mounted (eval at 162 (0.ce2d9bf….js:21), <anonymous>:8:18)
at callHook (eval at <anonymous> (app.js:794), <anonymous>:2335:19)
at Object.insert (eval at <anonymous> (app.js:794), <anonymous>:2525:5)
at invokeInsertHook (eval at <anonymous> (app.js:794), <anonymous>:4352:28)
at VueComponent.patch [as __patch__] (eval at <anonymous> (app.js:794), <anonymous>:4508:5)
at VueComponent.Vue._update (eval at <anonymous> (app.js:794), <anonymous>:2222:19)
at VueComponent.eval (eval at <anonymous> (app.js:794), <anonymous>:2189:10)
at Watcher.get (eval at <anonymous> (app.js:794), <anonymous>:1652:27)
at Watcher.run (eval at <anonymous> (app.js:794), <anonymous>:1721:22)
at flushSchedulerQueue (eval at <anonymous> (app.js:794), <anonymous>:1539:13)
logError @ vue.runtime.common.js?d43f:433
EDIT:
After changing to this.myMapForView
from this.computed.myMapForView
I got following errormessage in browser:
vue.runtime.common.js?d43f:433
TypeError: Cannot read property 'set' of undefined
at VueComponent.mounted (eval at 162 (0.85b2be9….js:21), <anonymous>:6:22)
at callHook (eval at <anonymous> (app.js:794), <anonymous>:2335:19)
at Object.insert (eval at <anonymous> (app.js:794), <anonymous>:2525:5)
at invokeInsertHook (eval at <anonymous> (app.js:794), <anonymous>:4352:28)
at VueComponent.patch [as __patch__] (eval at <anonymous> (app.js:794), <anonymous>:4508:5)
at VueComponent.Vue._update (eval at <anonymous> (app.js:794), <anonymous>:2222:19)
at VueComponent.eval (eval at <anonymous> (app.js:794), <anonymous>:2189:10)
at Watcher.get (eval at <anonymous> (app.js:794), <anonymous>:1652:27)
at Watcher.run (eval at <anonymous> (app.js:794), <anonymous>:1721:22)
at flushSchedulerQueue (eval at <anonymous> (app.js:794), <anonymous>:1539:13)
logError @ vue.runtime.common.js?d43f:433
It seems to me is new mapboxgl.Map()
is an asynchronous function and in vuex Actions can contain arbitrary asynchronous operations not mutations not from mutations. mutation handler functions must be synchronous.
So you should do new mapboxgl.Map()
in actions like following:
import simple from '../../components/simplestyle'
let mapboxgl = require('mapbox-gl/dist/mapbox-gl.js')
// initial state
const state = {
myMap: {},
mapLoaded: false
}
const mutations = {
loadMap (state, myMap) {
state.myMap = myMap
}
}
const actions = {
loadMap (context) {
'use strict'
mapboxgl.accessToken = 'mysecretmapboxkey'
var myMap = new mapboxgl.Map({
container: 'map',
style: simple,
hash: true,
center: [-74.0073, 40.7124],
zoom: 16
})
context.commit('loadMap', myMap)
}
}
export default {
state,
mutations,
actions
}
Edit:
Given your mouse interactions are causing change in the state, you can have a computed property in you vue instance with getter and setter, like following:
computed: {
myMapForView: {
// getter
get: function () {
return this.$store.state. myMap
},
// setter
set: function (newMap) {
this.$store.commit('loadMap', newMap)
}
}
}
Working Fiddle : http://jsfiddle.net/aucqteLn/
Also check: Vuex store with "strict: true" does not work
这篇关于如何在 Vuex 中为 mapbox 地图设置集中状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!