2017-06-19 79 views
2

我是Vue的新手,我嘗試將一個組件值綁定到導出對象的屬性。初始值設置正確,但沒有反應。我不知道我使用的是正確的術語,但相關部分是VueJS反應綁定到模塊導出

// Settings.js 
export const settings = { showOverlay: true } 

// Overlay.vue 
<template> 
    <div v-show="enabled"> Some stuff </div> 
</template> 

<script> 
import { settings } from "../js/Settings.js"; 
export default { 
    data() { 
    return { 
     enabled: settings.showOverlay 
    }; 
    } 
}; 
</script> 

現在,我知道,出口文物(settings)是一個只讀視圖到對象,因爲這就是模塊的工作方式,所以Vue可能無法將其掛鉤。問題是,我希望此設置由此設置服務「擁有」,該服務負責在頁面加載之間保持值,但我不認爲服務人員應該知道該組件想要觀看值並在值更改時手動觸發組件上的更新 - 我可能只是誤解了我應該用於這種情況的模式。

這是用Webpack/babel構建的,如果這有什麼區別的話。

+1

我認爲你正在尋找一些有狀態,我想看看[vuex(http://vuex.vuejs.org/en/intro.html) – dops

+0

的原因之一,我開始使用Vue是因爲它應該是「輕量級」的,你應該能夠一次採用它。我不想將我的整個應用程序狀態切換到Vue特定的存儲區(我想我會花更多時間切換到全局消息總線模型,而不是使用Vue首先保存的內容)。有沒有什麼方法可以使用「只是一點點Vue」? – Coderer

+0

我認爲更廣泛的問題可能是我正在觀察具有已經使用getter/setter的屬性的對象 - 我相信在引擎蓋下,導出的模塊通過隱藏實際屬性並提供了只讀視圖只有一個生成的getter。所以,如果我有一個對象並想要觀察吸氣劑,那麼有沒有一個好的方法來做到這一點? – Coderer

回答

2

我現在感覺有點不好意思。根據我在您的問題中看到的一些語法,我走下了一個小兔子洞,並且讓一堆不必要的旋轉。語法是這樣的:

data() { 
    return { 
    enabled: settings.showOverlay 
    }; 
} 

其中,出於某種原因,我解釋爲「好肯定的是,每當enabled變化,settings.showOverlay會有所改變,因爲Vue公司是反應」。

是的,沒有。

在該代碼中,settings.showOverlay只是初始值對於enabled屬性。 enabled屬性將爲反應,但它絕不會將值傳遞給設置對象。基本上數據函數返回一個啓用了屬性的對象,該對象的初始值爲settings.showOverlay,然後是,即對象變爲反應對象。

如果您希望將Vue中所做的更改傳遞給您的設置對象,那麼您只需在Vue的數據對象上公開設置對象。

data() { 
    return { 
    settings, 
    }; 
} 

現在如果你有一個像

<div v-show="settings.showOverlay"> Some stuff </div> 
<button @click="settings.showOverlay= !settings.showOverlay"></button> 

settings.showOverlay代碼不僅將反應在Vue公司,但在settings對象。不需要我在下面跳過的任何箍(/ facepalm)。

FWIW我相信我在評論中提到的一些鏈接是指數據對象本身。數據對象需要是一個普通的javascript對象,不一定是它的所有屬性。

換句話說,在

data() { 
    return something 
} 

something必須是一個普通的javascript對象。

原來的答案

我已經在我的Vue公司的應用程序一對夫婦的方式做到了這一點。在我的第一個應用程序中,我想做同樣的事情,將設置存儲在一個外部模塊中,該模塊可以管理持久設置並在Vue上顯示這些設置。我最終寫了一個看起來像這樣的類。

class Settings { 
    constructor(){ 
    // read settings from persisted solution 
    } 
    get(key){ 
    // return "key" from settings 
    } 
    set(key){ 
    // set "key" in settings 
    } 
    save(){ 
    // save settings to persisted solution 
    } 
} 

export default Settings 

然後在我的Vue中這樣使用它。

import Settings from "./settings" 

new Vue({ 
    data:{ 
    someSetting: Settings.get("someSetting") 
    } 
}) 

然後稍後再觸發set()和save()。對我來說,這一點是每當路由更改被觸發時,我只需將所有設置都設置回設置對象,然後保存。

聽起來像是你正在輸出一個具有getter/setter屬性的對象,可能是這樣的。

export const settings = { 
    overlay: stored.showOverlay, 
    get showOverlay(){ 
    return this.overlay 
    }, 
    set showOverlay(v){ 
    this.overlay = v 
    } 
} 

當您觸發set時,您可能會觸發保存。我比上述解決方案更喜歡這個想法。但讓它工作是一個更多的工作。首先,我嘗試使用計算機。

new Vue({ 
    computed:{ 
    showOverlay: { 
     get(){ return settings.showOverlay } 
     set(v) { settings.showOverlay = v } 
    } 
    } 
}) 

但是這並不起作用,因爲它不反映Vue的變化。這是有道理的,因爲Vue並不知道改變的價值。添加$forceUpdate到setter也不起作用,我期望因爲計算值的緩存性質。然而,使用一個計算結合數據屬性,確實工作。

new Vue({ 
    data(){ 
    return { 
     showOverlay_internal: settings.showOverlay 
    } 
    }, 
    computed:{ 
    showOverlay: { 
     get(){ return this.showOverlay_internal } 
     set(v) { 
     settings.showOverlay = v 
     this.showOverlayInternal = v 
     } 
    } 
    } 
}) 

這改變了Vue的狀態並觸發了設置對象的改變(這反過來可以觸發持久化)。

但是,該死的,這是很多工作。

儘管有時記住我們用於實例化Vue的對象只是普通的舊javascript對象,我們可以操縱它們,這一點很重要。我想知道是否可以編寫一些爲我們創建數據屬性和計算值的代碼。從Vuex那裏得到一個提示,是的,我們可以。

我最終得到的是這個。

import {settings, mapSetting} from "./settings" 

const definition = { 
    name:"app" 
} 

mapSetting(definition, "showOverlay" 

export default definition 

mapSetting做了我們上面爲我們做過的所有工作。 showOverlay現在是一個計算屬性,對Vue中的更改起反應並更新我們的設置對象。目前唯一的缺點是它暴露了showOverlay_internal數據屬性。我不知道有多重要。可以改進它來一次映射多個屬性。

這是我寫的使用localStorage作爲持久性介質的完整代碼。

function saveData(s){ 
    localStorage.setItem("settings", JSON.stringify(s)) 
} 

let stored = JSON.parse(localStorage.getItem("settings")) 
if (null == stored) { 
    stored = {} 
} 

export const settings = { 
    overlay: stored.showOverlay, 
    get showOverlay(){ 
    return this.overlay 
    }, 
    set showOverlay(v){ 
    this.overlay = v 
    saveData(this) 
    } 
} 

function generateDataFn(definition, setting, internalName){ 
    let originalDataFn = definition.data 
    return function(){ 
    let data = originalDataFn ? originalDataFn() : {} 
    data[internalName] = settings[setting] 
    return data 
    } 
} 

function generateComputed(internalName, setting){ 
    return { 
     get(){ 
     return this[internalName] 
     }, 
     set(v){ 
     settings[setting] = v 
     this[internalName] = v 
     } 
    } 
} 

export function mapSetting(definition, setting){ 
    let internalName = `${setting}_internal` 
    definition.data = generateDataFn(definition, setting, internalName) 

    if (!definition.computed) 
    definition.computed = {} 

    definition.computed[setting] = generateComputed(internalName, setting) 
} 
+0

這是一個非常詳盡的答案 - 感謝您的辛勤工作!我認爲我現在將暫時擱置我的Vue端口。我認爲你可以同意上面的解決方案做了很多跳舞來支持綁定,但是我還有其他的(非Vue中心的)邏輯,我必須要Vue-ify才能讓它工作,而我根本沒有時間。也許我稍後會在Vuex上做更多的閱讀,當時是全部重寫的時候。 – Coderer

+0

@Coderer這是一個公平的陳述。在我提出解決方案之後,我已經對此進行了一些研究,因爲它看起來有些複雜。 Vue確實想在數據中使用[純對象](https://vuejs.org/v2/api/#data)。也就是說,Vue通常是我最容易集成到其他項目中的框架。我是支持Vuex直到你需要它的支持者。我認爲這種情況下,特別是你的外部對象的屬性已經是getters/setters,是這裏疼痛的主要來源。我始終使用具有方法和簡單屬性的對象。 – Bert

+0

@Coderer Evan你也簡單地談了一下[這裏](https://github.com/vuejs/vue/issues/2718),「所有原型方法都被忽略了。使用非簡單對象作爲狀態是一個兔子洞複雜性,並沒有得到設計的支持「。 – Bert