vue js 看不懂keep alive
我正在使用以下代码进行测试:
https://jsfiddle.net/b2qj69o1/25/
I'm doing tests with this code:
https://jsfiddle.net/b2qj69o1/25/
<button
v-for="tab in tabs"
v-bind:key="tab.name"
v-bind:class="['tab-button', { active: currentTab.name === tab.name }]"
v-on:click="currentTab = tab"
>{{ tab.name }}</button>
<component
v-bind:is="currentTab.component"
class="tab"
></component>
还有js部分
var tabs = [
{
name: 'Home',
component: function() {
alert(); // test
return new Promise((resolve, reject) => resolve({
template: '<div>Home component</div>'
}))
}
},
{
name: 'Posts',
component: {
template: '<div>Posts component</div>'
}
},
{
name: 'Archive',
component: {
template: '<div>Archive component</div>',
}
}
]
new Vue({
el: '#dynamic-component-demo',
data: {
tabs: tabs,
currentTab: tabs[1]
}
})
我做了 alert() 测试看看 vue 是否会重新渲染组件.我看到无论是否使用 <keep-alive>
包装 <component>
,如果仅在我第一次进入 Home 选项卡时调用 alert().所以我有两个问题:
1. keep-alive到底是做什么的?因为似乎无论如何该组件只创建一次.
2. vue 是否可以显示/隐藏选项卡,而不是替换单个 DOM 元素?但是在组件显示出来之前还是不要加载它.
I did the alert() test to see whether vue will re-render the component. I see that with or without wraping <component>
with <keep-alive>
, the alert() if called only the first time I enter the Home tab. So I have two questions:
1. What exactly keep-alive does? cause it seems that anyway the component is created only once.
2. Is it possible for vue to show/hide the tabs, instead of replacing single DOM element? But still not to load the component until it is shown.
推荐答案
您已将 alert()
调用放在异步返回组件定义的函数中.这个函数只会在第一次访问组件的定义时被调用.
You've put the alert()
call in the function that asynchronously returns the component definition. This function will only get called the first time the definition of the component is accessed.
<keep-alive>
标签会缓存一个组件的实例,这样它就不会被破坏而需要重新挂载.
The <keep-alive>
tag will cache an instance of a component so that it does not get destroyed and need to be mounted again.
使用您的示例,您可以看到每次切换到主页"选项卡时都会调用 mounted
挂钩:
Using your example, you can see that the mounted
hook gets called any time you switch to the "Home" tab:
var tabs = [
{
name: 'Home',
component: function() {
return new Promise((resolve, reject) => resolve({
template: '<div>Home component</div>',
mounted() {
console.log('mounted')
}
}))
}
},
{
name: 'Posts',
component: {
template: '<div>Posts component</div>'
}
},
{
name: 'Archive',
component: {
template: '<div>Archive component</div>',
}
}
]
new Vue({
el: '#dynamic-component-demo',
data: {
tabs: tabs,
currentTab: tabs[1]
}
})
.tab-button {
padding: 6px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: 1px solid #ccc;
cursor: pointer;
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
}
.tab-button:hover {
background: #e0e0e0;
}
.tab-button.active {
background: #e0e0e0;
}
.tab {
border: 1px solid #ccc;
padding: 10px;
}
<script src="https://unpkg.com/vue"></script>
<div id="dynamic-component-demo" class="demo">
<button
v-for="tab in tabs"
v-bind:key="tab.name"
v-bind:class="['tab-button', { active: currentTab.name === tab.name }]"
v-on:click="currentTab = tab"
>{{ tab.name }}</button>
<component
v-bind:is="currentTab.component"
class="tab"
></component>
</div>
但是,通过将动态组件包装在 <keep-alive>
标记中,您是在告诉 Vue 缓存对主路由组件的引用.所以 mounted
钩子只会在组件第一次实例化时被调用:
But, by wrapping the dynamic component in a <keep-alive>
tag, you are telling Vue to cache a reference to the home route's component. So the mounted
hook only gets called the first time the component is instantiated:
var tabs = [
{
name: 'Home',
component: function() {
return new Promise((resolve, reject) => resolve({
template: '<div>Home component</div>',
mounted() {
console.log('mounted')
}
}))
}
},
{
name: 'Posts',
component: {
template: '<div>Posts component</div>'
}
},
{
name: 'Archive',
component: {
template: '<div>Archive component</div>',
}
}
]
new Vue({
el: '#dynamic-component-demo',
data: {
tabs: tabs,
currentTab: tabs[1]
}
})
.tab-button {
padding: 6px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: 1px solid #ccc;
cursor: pointer;
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
}
.tab-button:hover {
background: #e0e0e0;
}
.tab-button.active {
background: #e0e0e0;
}
.tab {
border: 1px solid #ccc;
padding: 10px;
}
<script src="https://unpkg.com/vue"></script>
<div id="dynamic-component-demo" class="demo">
<button
v-for="tab in tabs"
v-bind:key="tab.name"
v-bind:class="['tab-button', { active: currentTab.name === tab.name }]"
v-on:click="currentTab = tab"
>{{ tab.name }}</button>
<keep-alive>
<component
v-bind:is="currentTab.component"
class="tab"
></component>
</keep-alive>
</div>
这里是使用文档<keep-alive>
带有动态组件的标签.
Here's the documentation on using the <keep-alive>
tag with dynamic components.
至于你的第二个问题:如果你想最初将所有选项卡添加到 DOM 并简单地隐藏非活动选项卡组件,然后使用 v-for
指令渲染每个选项卡,并使用v-show
指令仅显示活动选项卡.
As for your second question: if you want to add all of the tabs to the DOM initially and simply hide the inactive tab components, then render each tab using the v-for
directive, and use the v-show
directive to only show the active tab.
这是一个例子:
var tabs = [
{
name: 'Home',
component: function() {
return new Promise((resolve, reject) => resolve({
template: '<div>Home component</div>',
}))
}
},
{
name: 'Posts',
component: {
template: '<div>Posts component</div>'
}
},
{
name: 'Archive',
component: {
template: '<div>Archive component</div>',
}
}
]
new Vue({
el: '#dynamic-component-demo',
data: {
tabs: tabs,
currentTab: tabs[1]
}
})
.tab-button {
padding: 6px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: 1px solid #ccc;
cursor: pointer;
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
}
.tab-button:hover {
background: #e0e0e0;
}
.tab-button.active {
background: #e0e0e0;
}
.tab {
border: 1px solid #ccc;
padding: 10px;
}
<script src="https://unpkg.com/vue"></script>
<div id="dynamic-component-demo" class="demo">
<button
v-for="tab in tabs"
v-bind:key="tab.name"
v-bind:class="['tab-button', { active: currentTab.name === tab.name }]"
v-on:click="currentTab = tab"
>{{ tab.name }}</button>
<component
v-for="tab in tabs"
v-bind:key="'component-' + tab.name"
v-bind:is="tab.component"
class="tab"
v-show="currentTab === tab"
></component>
</div>
而且,如果我正确理解了您的最后一句话,如果您真的想在选项卡最初处于活动状态之前不创建选项卡组件,但是想要在另一个选项卡处于活动状态时隐藏选项卡的 HTML 内容,您需要跟踪数据属性中哪些选项卡已被激活,然后使用 v-if
指令最初阻止组件初始化.
And, if I understand your last sentence correctly, if you really want to not create a tab component until the tab is initially active, but then want to hide the tab's HTML content when another tab is active, you'd need to keep track of which tabs have been activated in a data property and then use the v-if
directive to initially prevent the component from initializing.
类似这样的:
var tabs = [
{
name: 'Home',
component: function() {
return new Promise((resolve, reject) => resolve({
template: '<div>Home component</div>',
}))
}
},
{
name: 'Posts',
component: {
template: '<div>Posts component</div>'
}
},
{
name: 'Archive',
component: {
template: '<div>Archive component</div>',
}
}
]
new Vue({
el: '#dynamic-component-demo',
data: {
tabs: tabs,
currentTab: tabs[1],
activatedTabs: {}
},
watch: {
currentTab: {
immediate: true,
handler(tab) {
this.$set(this.activatedTabs, tab.name, true);
}
}
}
})
.tab-button {
padding: 6px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: 1px solid #ccc;
cursor: pointer;
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
}
.tab-button:hover {
background: #e0e0e0;
}
.tab-button.active {
background: #e0e0e0;
}
.tab {
border: 1px solid #ccc;
padding: 10px;
}
<script src="https://unpkg.com/vue"></script>
<div id="dynamic-component-demo" class="demo">
<button
v-for="tab in tabs"
v-bind:key="tab.name"
v-bind:class="['tab-button', { active: currentTab.name === tab.name }]"
v-on:click="currentTab = tab"
>{{ tab.name }}</button>
<component
v-for="tab in tabs"
v-if="activatedTabs[tab.name]"
v-bind:key="'component-' + tab.name"
v-bind:is="tab.component"
class="tab"
v-show="currentTab === tab"
></component>
</div>
相关文章