vue js无法理解保持活力

时间:2018-03-27 15:55:13

标签: javascript vue.js components keep-alive

我正在使用此代码进行测试:
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是否会重新渲染组件。我看到无论是否<component><keep-alive>进行包裹,只有在我第一次进入“主页”选项卡时才会调用alert()。所以我有两个问题:
1.究竟保持活力的作用是什么?因为无论如何组件只创建一次。
2. vue是否可以显示/隐藏选项卡,而不是替换单个DOM元素?但是在显示之前仍然不要加载组件。

2 个答案:

答案 0 :(得分:1)

您已将alert()调用放入异步返回组件定义的函数中。只有在第一次访问组件定义时才会调用此函数。

<keep-alive>标记将缓存组件的实例,以便它不会被破坏并需要再次安装。

使用您的示例,您可以看到每次切换到“主页”标签时都会调用mounted挂钩:

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挂钩仅在第一次实例化组件时被调用:

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>

Here's the documentation on using the <keep-alive> tag with dynamic components.

关于你的第二个问题:如果你想最初将所有选项卡添加到DOM并简单地隐藏非活动选项卡组件,然后使用v-for指令渲染每个选项卡,并使用{{1} }指令仅显示活动选项卡。

以下是一个例子:

v-show
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;
}

而且,如果我理解你的最后一句话,如果你真的想在标签最初处于活动状态之前不想创建标签组件,但是当另一个标签处于活动状态时想要隐藏标签的HTML内容,你需要跟踪数据属性中已激活哪些选项卡,然后使用<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>指令初始阻止组件初始化。

这样的事情:

v-if
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;
}

答案 1 :(得分:1)

您需要使用<keep-alive></keep-alive>

包装组件标记

我已更新您的Jsfiddle