2016-11-11 64 views
0

我正在嘗試使用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>

+0

我的回答是否有意義? – prograhammer

+0

感謝您的幫助和解釋。我已經逐行閱讀了所有內容。現在我正在使用您提供的信息更新我的代碼。但是我仍然對它的某些部分感到困惑。我會盡力將它們解釋爲更新。 – effe

+0

好的,在你做出更新後,在這裏留下另一條評論,我會盡力解決它們。 – prograhammer

回答

2

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中閱讀更多有關撰寫組件的內容。