Vue組件開發姿式總結

前言

臨近畢業,寫了個簡單我的博客,項目地址是點我訪問項目地址(順便求star),本篇是系列總結第一篇。接下來會一步一步模仿一個低配版的Element 的對話框彈框組件css

正文

Vue 單文件組件開發

當使用vue-cli初始化一個項目的時候,會發現src/components文件夾下有一個HelloWorld.vue文件,這即是
單文件組件的基本開發模式。vue

// 註冊
Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})

// 建立根實例
new Vue({
  el: '#example'
})

接下來,開始寫一個dialog組件。ios

Dialog

目標對話框組件的基本樣式如圖:git

dialog基本樣式

根據目標樣式,能夠總結出:github

  1. dialog組件須要一個titleprops來標示彈窗標題
  2. dialog組件須要在按下肯定按鈕時發射肯定事件(即告訴父組件肯定了)
  3. 同理,dialog組件須要發射取消事件
  4. dialog組件須要提供一個插槽,便於自定義內容

那麼,編碼以下:vue-cli

<template>
  <div class="ta-dialog__wrapper">
    <div class="ta-dialog">
      <div class="ta-dialog__header">
        <span>{{ title }}</span>
        <i class="ios-close-empty" @click="handleCancel()"></i>
      </div>
      <div class="ta-dialog__body">
        <slot></slot>
      </div>
      <div class="ta-dialog__footer">
        <button @click="handleCancel()">取消</button>
        <button @click="handleOk()">肯定</button>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Dialog',

  props: {
    title: {
      type: String,
      default: '標題'
    },
  },

  methods: {
    handleCancel() {
      this.$emit('cancel')
    },

    handleOk() {
      this.$emit('ok')
    },
  },
}
</script>

這樣便完成了dialog組件的開發,使用方法以下:promise

<ta-dialog 
  title="彈窗標題" 
  @ok="handleOk" 
  @cancel="handleCancel">
  <p>我是內容</p>
</ta-dialog>

這時候發現一個問題,經過使用v-if或者v-show來控制彈窗的展示時,沒有動畫!!!,看上去很生硬。教練,我想加動畫,這時候就該transition組件上場了。使用transition組件結合css能作出不少效果不錯的動畫。接下來加強dialog組件動畫,代碼以下:app

<template>
  <transition name="slide-down">
    <div class="ta-dialog__wrapper" v-if="isShow">
      // 省略
    </div>
  </transition>
</template>

<script>
export default {

  data() {
    return {
      isShow: true
    }
  },

  methods: {
    handleCancel() {
      this.isShow = false
      this.$emit('cancel')
    },

    handleOk() {
      this.isShow = true
      this.$emit('ok')
    },
  },
}
</script>

能夠看到transition組件接收了一個nameprops,那麼怎麼編寫css完成動畫呢?很簡單的方式,寫出兩個
關鍵class(css 的 className)樣式便可:ide

.slide-down-enter-active {
  animation: dialog-enter ease .3s;
}

.slide-down-leave-active {
  animation: dialog-leave ease .5s;
}

@keyframes dialog-enter {
  from {
    opacity: 0;
    transform: translateY(-20px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes dialog-leave {
  from {
    opacity: 1;
    transform: translateY(0);
  }

  to {
    opacity: 0;
    transform: translateY(-20px);
  }
}

就是這麼簡單就開發出了效果還不錯的動效,注意transition組件的nameslide-down,而編寫的動畫的關鍵classNameslide-down-enter-activeslide-down-leave-active函數

封裝DialogMessageBox

Element的MessageBox的使用方法以下:

this.$confirm('此操做將永久刪除該文件, 是否繼續?', '提示', {
  confirmButtonText: '肯定',
  cancelButtonText: '取消',
  type: 'warning'
}).then(() => {
  this.$message({
    type: 'success',
    message: '刪除成功!'
  });
}).catch(() => {
  this.$message({
    type: 'info',
    message: '已取消刪除'
  });          
});

看到這段代碼,個人感受就是好神奇好神奇好神奇(驚歎三連)。仔細看看,這個組件其實就是一個封裝好的dialog,

Element MessageBox效果

接下來,我也要封裝一個這樣的組件。首先,整理下思路:

  1. Element的使用方法是this.$confirm,這不就是掛到Vueprototype上就好了
  2. Element的then是肯定,catch是取消,promise就能夠啦

整理好思路,我就開始編碼了:

import Vue from 'vue'
import MessgaeBox from './src/index'

const Ctur = Vue.extend(MessgaeBox)
let instance = null

const callback = action => {
  if (action === 'confirm') {
    if (instance.showInput) {
      instance.resolve({ value: instance.inputValue, action })
    } else {
      instance.resolve(action)
    }
  } else {
    instance.reject(action)
  }

  instance = null
}

const showMessageBox = (tip, title, opts) => new Promise((resolve, reject) => {
  const propsData = { tip, title, ...opts }

  instance = new Ctur({ propsData }).$mount()
  instance.reject = reject
  instance.resolve = resolve
  instance.callback = callback

  document.body.appendChild(instance.$el)
})


const confirm = (tip, title, opts) => showMessageBox(tip, title, opts)

Vue.prototype.$confirm = confirm

至此,可能會疑惑怎麼callback呢,其實我編寫了一個封裝好的dialog並將其命名爲MessageBox,
它的代碼中,有這樣兩個方法:

onCancel() {
  this.visible = false
  this.callback && (this.callback.call(this, 'cancel'))
},

onConfirm() {
  this.visible = false
  this.callback && (this.callback.call(this, 'confirm'))
},

沒錯,就是肯定取消時進行callback。我還想說一說Vue.extend,代碼中引入了MessageBox,
我不是直接new MessageBox而是藉助new Ctur,由於這樣能夠定義數據(不單單是props),例如:

instance = new Ctur({ propsData }).$mount()

這時候,頁面上實際上是尚未MessageBox的,咱們須要執行:

document.body.appendChild(instance.$el)

若是你直接這樣,你可能會發現MessageBox打開的時候沒有動畫,而關閉的時候有動畫。解決方法也很簡單,
appendChild的時候讓其還是不可見,而後使用類這樣的代碼:

Vue.nextTick(() => instance.visible = true)

這樣就有動畫了。

總結

  1. 經過transitioncss實現不錯的動畫。其中,transition組件的name決定了編寫css的兩個關鍵
    類名爲[name]-enter-active[name]-leave-active
  2. 經過Vue.extend繼承一個組件的構造函數(不知道怎麼說合適,就先這樣說),而後經過這個構造函數,即可以
    實現組件相關屬性的自定義(使用場景:js調用組件)
  3. js調用組件時,爲了維持組件的動畫效果能夠先document.body.appendChild 而後Vue.nextTick(() => instance.visible = true)

到此,簡單的Vue組件開發就總結完了,我寫的相關代碼在地址,歡迎指正批評,求star...

相關文章
相關標籤/搜索