在編寫組件時,記住是否要複用組件有好處。一次性組件跟其它組件緊密耦合不要緊,可是可複用組件應當定義一個清晰的公開接口。--官方文檔css
在看這篇文章前,強烈推薦你們看這篇文章Thinking in Vue之一:組件擴展的嘗試
項目Github
演示Demohtml
就像官方文檔所說的同樣,本身一般寫的都是一次性的組件,沒有往可複用組件方面去思考。vue
對vue的render函數有所瞭解,對自定義事件有所瞭解,沒有也不要緊。
render函數 文檔
自定義事件 文檔git
// src/components/BaseButton.vue <script> export default{ name: 'base-button', props: [], render(createElement) { return createElement( 'a', { class: ['button', 'ripple'], }, this.$slots.default ) }, methods: { } }; </script> <style scoped> /*button默認樣式*/ a.button { display: inline-block; line-height: 1; text-align: center; white-space: nowrap; cursor: pointer; user-select: none; border: none; border-radius: 2px; position: relative; padding: 8px 30px; margin: 10px 1px; font-size: 14px; font-weight: 500; text-transform: uppercase; letter-spacing: 0; will-change: box-shadow, transform; transition: box-shadow 0.2s cubic-bezier(0.4, 0, 1, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), color 0.2s cubic-bezier(0.4, 0, 0.2, 1); text-decoration: none; background: transparent; background-color: #EEEEEE; color: rgba(0, 0, 0, 0.87); } a.button:active { box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.2); } /*button 擴展樣式*/ a.button.default { background-color: #EEEEEE; color: rgba(0, 0, 0, 0.87); } a.button.primary { background-color: #009688; color: rgba(255, 255, 255, 0.84); } a.button.success { background-color: #4caf50; color: rgba(255, 255, 255, 0.84); } a.button.info { background-color: #03a9f4; color: rgba(255, 255, 255, 0.84); } a.button.warning { background-color: #ff5722; color: rgba(255, 255, 255, 0.84); } a.button.danger { background-color: #f44336; color: rgba(255,255,255, 0.84); } .ripple { position: relative; overflow: hidden } /*button 水波紋點擊效果*/ .ripple:after { content: ""; display: block; position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; background-image: radial-gradient(circle, #000 10%, transparent 10.01%); background-repeat: no-repeat; background-position: 50%; transform: scale(10, 10); opacity: 0; transition: transform .5s, opacity 1s } .ripple:active:after { transform: scale(0, 0); opacity: .2; transition: 0s } </style>
完成了一個Button的基礎樣式,而後經過render函數來建立一個想過等同於<a class="button"></a>
的template.
在App.vue中使用它:github
<BaseButton>Base</BaseButton>
渲染的結果:瀏覽器
組件樹的結果:ide
此時這個BaseButton就是一個可用的組件了,那麼如何複用它呢?這篇文章也有提到Thinking in Vue之一:組件擴展的嘗試
根據這篇文章提供的思路,建立一個TypeButton組件而後將BaseButton組件給包裹起來,這樣就不須要爲每個Button組件重新複製粘貼那些默認樣式了。函數
// src/components/TypeButton.vue <script> import Button from './BaseButton.vue' export default{ name: "type-button", render(createElement){ return createElement(Button, { class:["info"] }, this.$slots.default ) }, methods: { }, components: {} }; </script> <style scoped> </style>
在App.vue中掛載上去
渲染的結果:ui
DOM節點結果:this
組件樹結果:
固然,此時能夠說完成了複用,可是並不完美。咱們能夠作一個工廠方法同樣的組件複用。此時咱們就會用到prop來傳遞屬性。
// 進一步修改src/components/TypeButton.vue <script> import Button from './BaseButton.vue' export default{ name: "type-button", //將傳遞過來的type在props中註冊,並進行驗證 props: { type: { validator: function (typeStr) { if (typeof typeStr === 'string') { switch (typeStr) { case 'defaul': case 'primary': case 'info': case 'success': case 'warning': case 'danger': return true; default: return false; } } else return false; } } }, render(createElement){ return createElement(Button, { class: [this.type], on:{ click:this.click } }, this.$slots.default ) }, methods: { }, components: {} }; </script> <style scoped> </style>
此時咱們就能夠這樣使用組件了
<TypeButton type="defaul">defaul</TypeButton> <TypeButton type="primary">primary</TypeButton> <TypeButton type="info">info</TypeButton> <TypeButton type="success">success</TypeButton> <TypeButton type="warning">warning</TypeButton> <TypeButton type="danger">danger</TypeButton>
就很完美了有木有!!!!
此時若是你想這樣來實現點擊事件:<TypeButton @click="defualt" type="defaul">defaul</TypeButton>
,你會發現是不可行的。這是就須要自定義事件。
// App.vue的methods methods: { defaul(){ console.log('defaul') } }
// TypeButton.vue的render函數 <script> import Button from './BaseButton.vue' export default{ render(createElement){ return createElement(Button, { class: [this.type], //添加on對象 on:{ click:this.click } }, this.$slots.default ) }, //添加 methods: { click(){ //觸發組件中定義的click this.$emit('click') } }, }; </script>
// BaseButton.vue export default{ name: 'base-button', props: [], render(createElement) { return createElement( 'a', { class: ['button', 'ripple'], on: { click: this.click } }, this.$slots.default ) }, methods: { click(){ this.$emit('click') } } };
此時在組件中使用@click<TypeButton @click="defualt" type="defaul">defaul</TypeButton>
就能夠被觸發。
也就實現了一個Material Design風格,水波紋點擊效果的Button組件。