使用自定义方法构建可重用组件
我正在尝试使用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',
});
@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;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.5/vue.min.js"></script>
<div id="inner-body">
<app></app>
</div>
Vue的组件通过道具(其中只有父母变异道具上的孩子,从来没有孩子自己)都应该进行通信单向下来的孩子孩子们通过发布活动与父母沟通。使嵌套组件更容易推理,并正确地分离组件。那么当父母想要更改标签时,你会怎么做?让我带你经历一个过程:
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)你的父母现在,你应该有一个可如果你想被命名为相同的道具反应数据属性:
在父组件(即应用程序)
data: {
activeTab: 0
}
3)然后我们需要把它变成当你改变上面的数据属性时,prop也会被改变。下面是它会是什么样子选项卡上的成分标签:
在父母组件(即应用程序)
<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)你的父母现在应该听听这个发射事件,并更新自己的数据属性:
在父组件(即应用程序)
<tabs :activeTab="activeTab" @switched="activeTab = arguments[0]" ...
看起来有点多努力,但随着应用程序复杂度的增长以及更多事物的嵌套,这一切都是值得的。您可以在官方文档here中阅读更多有关撰写组件的内容。
我的回答是否有意义? – prograhammer
感谢您的帮助和解释。我已经逐行阅读了所有内容。现在我正在使用您提供的信息更新我的代码。但是我仍然对它的某些部分感到困惑。我会尽力将它们解释为更新。 – effe
好的,在你做出更新后,在这里留下另一条评论,我会尽力解决它们。 – prograhammer