我正在尝试使用vuejs构建可重用的选项卡组件。我还在学习vue的一些基本概念,很难完成制表和切换逻辑。现在可以在组件本身的选项卡之间切换。但是我让我的组件听外部触发器有一些问题。
现在,我可以在$refs
的帮助下将我的标签切换到组件之外。但是当我试图让它可重复使用时,这种方法听起来并不实用。我该怎么办?
以下是JSFiddle
Vue.component('tabs', {
template: `
<div class="tabs">
<div class="tab-titles">
<a :class="{'active':tab.active}" v-for="tab in tablist" href="#" class="tab-title" @click.prevent="activateTab(tab)">{{tab.title}}</a>
</div>
<div class="tab-contents">
<slot></slot>
</div>
</div>
`,
data() {
return {
tablist: [],
}
},
methods: {
activateTab: function(tab) {
this.tablist.forEach(t => {
t.active = false;
t.tab.is_active = false
});
tab.active = true;
tab.tab.is_active = true;
},
activateTabIndex: function(index) {
this.activateTab(this.tablist[index]);
},
collectTabData: function(tabData) {
this.tablist.push(tabData)
}
},
});
//==============================================================================
Vue.component('tab', {
template: `
<div :class="{'active':is_active}" class="tab-content">
<slot></slot>
</div>
`,
data() {
return {
is_active: this.active
}
},
mounted() {
this.$parent.collectTabData({
tab: this,
title: this.title,
active: this.active,
is_active: this.is_active
});
},
props: {
title: {
type: String,
required: true
},
active: {
type: [Boolean, String],
default: false
},
}
});
//==============================================================================
Vue.component('app', {
template: `
<div class="container">
<tabs ref="foo">
<tab title="tab-title-1">
<h3>content-1</h3>
Initial content here
</tab>
<tab title="tab-title-2" active>
<h3>content-2</h3>
Some content here
</tab>
<tab title="tab-title-3">
<h3>content-3</h3>
Another content here
</tab>
</tabs>
<a href="#" @click='switchTab(0)'>switch to tab(index:0)</a>
</div>
`,
methods: {
switchTab: function () {
vm.$children[0].$refs.foo.activateTabIndex(0);
}
},
});
//==============================================================================
const vm = new Vue({
el: '#inner-body',
});
&#13;
@import url('https://fonts.googleapis.com/css?family=Lato');
#inner-body{
font-family: 'Lato', sans-serif;
background-color:#ffffff;
padding:20px;
}
.tab-titles {
}
.tab-title {
display: inline-block;
margin-right: 10px;
color: #bbb;
text-decoration: none;
}
.tab-title.active {
color: #06cd92;
border-bottom:1px solid #06cd92;
}
.tab-contents{
border: 1px solid #ddd;
border-width:1px 0;
margin-top:-1px;
margin-bottom:20px;
}
.tab-content {
display: none;
padding-bottom:20px;
}
.tab-content.active {
display: block;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.5/vue.min.js"></script>
<div id="inner-body">
<app></app>
</div>
&#13;
答案 0 :(得分:2)
Vue组件应该通过Props单向传达给孩子(只有父母会改变孩子们的道具,而不是孩子们自己),孩子们通过发出事件与父母交流。使嵌套组件更容易推理,并正确地分离组件。那么当父母想要更改标签时你会怎么做?让我带您完成一个过程:
1)想象一下,我们在标签组件中添加了一个名为activeTab
的道具(我在这里没有直接关注您的问题中的代码,只是松散地将其展示给它来展示这个过程更容易)。父母将随时改变该道具的价值。标签组件(在本例中也称为子组件)不应更改activeTab
道具的值。相反,在标签组件内,为此道具添加观察者:
(即标签)
props: {
/**
* Prop parent can use to set active tab
*/
'activeTab': {
type: Number
}
},
watch: {
/**
* Watch for changes on the activeTab prop.
*
* @param {boolean} val The new tab value.
* @param {boolean} oldVal The old tab value.
* @return {void}
*/
activeTab: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
// do something here to make the tabs change
// and never alter the prop itself.
this.switchTab(val)
}
},
2)现在,在您的父级上,您应该拥有一个反应数据属性,如果您愿意,可以将其命名为与您的道具相同:
父组件中的(即app)
data: {
activeTab: 0
}
3)然后我们需要将它改为上面改变数据属性的位置,支柱也会被改变。这是标签组件标签上的样子:
父组件中的(即app)
<tabs :activeTab="activeTab" ...
4)如果您希望标签组件有时也改变活动标签,您会怎么做?简单,只需在更改活动选项卡时发出事件:
子组件中的(即标签)
methods: {
switchTab (newActiveTabValue) {
// store the new active tab in some data property in this component, but not the "activeTab" prop, as mentioned earlier.
this.whatever = newActiveTabValue
// ... now emit the event
this.$emit('switched', newActiveTabValue)
}
5)您的父级现在应该侦听此发出的事件并更新自己的数据属性:
父组件中的(即app)
<tabs :activeTab="activeTab" @switched="activeTab = arguments[0]" ...
似乎需要更多的努力,但随着您的应用程序在复杂性方面的增长以及更多的东西变得嵌套,这一切都值得。您可以在官方文档here中阅读有关撰写组件的更多信息。