手把手教你們使用Vue2.0編寫可複用的水波紋特效Button組件

寫在開頭

在編寫組件時,記住是否要複用組件有好處。一次性組件跟其它組件緊密耦合不要緊,可是可複用組件應當定義一個清晰的公開接口。--官方文檔css

在看這篇文章前,強烈推薦你們看這篇文章Thinking in Vue之一:組件擴展的嘗試
項目Github
演示Demohtml

思考

就像官方文檔所說的同樣,本身一般寫的都是一次性的組件,沒有往可複用組件方面去思考。vue

前提

對vue的render函數有所瞭解,對自定義事件有所瞭解,沒有也不要緊。
render函數 文檔
自定義事件 文檔git

可複用的Button組件的實現

實現一個基礎的Button組件(順便也將後面的css樣式加入進來):

// 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>

渲染的結果:
BaseButton瀏覽器中顯示瀏覽器

組件樹的結果:
BaseButton渲染結果ide

此時這個BaseButton就是一個可用的組件了,那麼如何複用它呢?這篇文章也有提到Thinking in Vue之一:組件擴展的嘗試
根據這篇文章提供的思路,建立一個TypeButton組件而後將BaseButton組件給包裹起來,這樣就不須要爲每個Button組件重新複製粘貼那些默認樣式了。函數

實現一個基礎的TypeButton組件

// 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組件。

相關文章
相關標籤/搜索