典型的解决方案是使用 Vuex(它是一个状态管理模块)。我不会在我的回答中介绍 Vuex。我只推荐它。它很强大,您最终会比您想象的更快地需要它。使用Vue.observable(如下所示)仅在简单情况下有用。当您开始需要 async 行为时,可能是时候开始使用 Vuex。
这是更简单的解决方案:Vue.observable():
声明一个Vue.observable(),其中包含您想在两个组件之间共享的任何内容。将其放在文件中并导出:例如:
export default Vue.observable({
isLoggedIn: false
})
在您想要读取或写入该状态对象的任何组件中,将其导入:
import userState from '../path/to/userState.js'
如果您只想从中读取,请将其用作简单的计算:
computed: {
isLoggedIn() { return userState.isLoggedIn }
}
如果你也想写入它,请将其用作 setter + getter 计算:
computed: {
isLoggedIn: {
get() { return userState.isLoggedIn; }
set(value) { userState.isLoggedIn = value; }
}
}
就是这样,真的。工作示例:
const userState = Vue.observable({
isLoggedIn: false
});
Vue.component('header-component', {
template: `
<label>
<input type="checkbox" v-model="isLoggedIn">
Logged in
</label>
`,
computed: {
isLoggedIn: {
get() {
return userState.isLoggedIn
},
set(value) {
userState.isLoggedIn = value
}
}
}
});
Vue.component('footer-component', {
template: `<pre v-text="{ isLoggedIn }"></pre>`,
computed: {
isLoggedIn() {
return userState.isLoggedIn
}
}
});
new Vue({
el: '#app'
})
body {
margin: 0;
}
#app {
min-height: 100vh;
display: flex;
flex-direction: column;
}
#app>* {
padding: 1rem;
border: 1px solid #eee;
}
#app main {
flex-grow: 1;
}
#app pre {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<div id="app">
<header-component></header-component>
<main>main content here...</main>
<footer-component></footer-component>
</div>
注意:Vue.observable() 是在 Vue 中引入的 2.6。
如果你想在之前的版本中使用这个功能,你可以使用 Vue 实例而不是 observable。
当您想要访问 Vue 实例必须提供的所有内容时,使用成熟的 Vue 实例而不是 Vue.observable 也很有用:观察者、计算、方法 - 可能是异步等......
const userState = new Vue({
data: () => ({
isLoggedIn: false
})
});
看看它是否正常工作(2.5):
const userState = new Vue({
data: () => ({
isLoggedIn: false
})
});
Vue.component('header-component', {
template: `
<label>
<input type="checkbox" v-model="isLoggedIn">
Logged in
</label>
`,
computed: {
isLoggedIn: {
get() {
return userState.isLoggedIn
},
set(value) {
userState.isLoggedIn = value
}
}
}
});
Vue.component('footer-component', {
template: `<pre v-text="{ isLoggedIn }"></pre>`,
computed: {
isLoggedIn() {
return userState.isLoggedIn
}
}
});
new Vue({
el: '#app'
})
body {
margin: 0;
}
#app {
min-height: 100vh;
display: flex;
flex-direction: column;
}
#app>* {
padding: 1rem;
border: 1px solid #eee;
}
#app main {
flex-grow: 1;
}
#app pre {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17"></script>
<div id="app">
<header-component></header-component>
<main>main content here...</main>
<footer-component></footer-component>
</div>