造輪子-toast組件的實現(下)

1.解決 toast 中傳入 html 的問題,經過假的 slot 來實現css

// plugins.js
toast.$slots.default = [message]
// toast.vue
 <div v-html="$slots.default[0]"></div>
// 使用
created() {
    this.$toast('<p>我是<strong>hi</strong></p>',{})
},

2.在 toast 中加 html 是比較危險的一個動做,因此要加一個選項默認不開啓。html

// toast.vue
<slot v-if="!enableHtml"></slot>
<div v-else v-html="$slots.default[0]"></div>
// plugin.js,進行傳遞參數的改寫
propsData:toastOptions
// 使用
created() {
  this.$toast('<p>我是<strong>hi</strong></p><a href="http://qq.com">qq</a>',{
    enableHtml: false
  })
},

3.flex-shrink的使用,flex-shrink屬性定義了項目的縮小比例,默認爲1,即若是空間不足,該項目將縮小。vue

.item {
  flex-shrink: <number>; /* default 1 */
}

若是全部項目的flex-shrink屬性都爲1,當空間不足時,都將等比例縮小。若是一個項目的flex-shrink屬性爲0,其餘項目都爲1,則空間不足時,前者不縮小。若是數值越大,縮小比例越大。git

4.line的高度問題,若是高度寫了最小高度,那麼子元素的height%就不生效了。用js去操做line的高度。app

// toast.vue
<div class="toast" ref="wrapper">
    <div class="line" ref="line"></div>
</div>

mounted() {
  this.$nextTick(()=>{
    this.$refs.line.style.height = `${this.$refs.wrapper.getBoundingClientRect().height}px`
  })
}, // 這個計較太trick

debugger的技巧,若是眼睛觀察到的是0,可是打印出來不是0,可能就是異步的問題。異步

5.增長toast的位置。函數

// toast.vue
props: {
  position: {
    type: String,
    default: 'top',
    validator(value){
      return ['top', 'bottom', 'middle'].indexOf(value) >= 0
    }
  }
},
computed:{
  toastClasses(){
    return {
      [`position-${this.position}`]:true
    }
  }
}
// 使用
this.$toast('你的智商須要充值', {
  position: 'bottom'
})
// plugin.js
export default {
  install(Vue, options){
    Vue.prototype.$toast = function (message, toastOptions) {
      let Constructor = Vue.extend(Toast)
      let toast = new Constructor({
        propsData:toastOptions // 在這裏將position傳進去
      })
      toast.$slots.default = [message]
      toast.$mount()
      document.body.appendChild(toast.$el)
    }
  }
}

6.開始作若是已經有一個toast就把以前那個幹掉,再出現。flex

  1. 先寫一個函數
  2. 給函數取一個名字
  3. 把參數提出來
// plugin.js
import Toast from './toast'

let currentToast

export default {
  install(Vue, options){
    Vue.prototype.$toast = function (message, toastOptions) {
      if(currentToast){
        currentToast.close()
      }
      currentToast = createToast({Vue,message, propsData: toastOptions})
    }
  }
}

/* helpers */
function createToast ({Vue,message,propsData}){
  let Constructor = Vue.extend(Toast)
  let toast = new Constructor({propsData})
  toast.$slots.default = [message]
  toast.$mount()
  document.body.appendChild(toast.$el)
  return toast
}

7.實現動畫優化

  1. 聲明一個動畫,而後寫到類上面
@keyframes fade {
     0% {opacity: 0; transform: translateY(100%);}
     100% {opacity: 1;transform: translateY(0);}
   } 
   .toast {
     animation: fade 1s;
   }
  1. 這裏有個bug,咱們在實現一次的時候是有問題的,若是toast被關閉了,咱們不須要重複關閉,而咱們寫的是無論你以前的toast有沒有關閉,只要有值的咱們就關閉,那這樣就會出現一個問題,點了關閉currentToast仍是一個Toast並無把它變成null,因此要加上一個回調告訴外面,我被關了不要重複關我,代碼會多調一次close。
// toast.vue
  close() {
    this.$el.remove()
    this.$emit('close')
    this.$destroy()
  }
  // plugin.js
  export default {
    install(Vue, options){
      Vue.prototype.$toast = function (message, toastOptions) {
        if(currentToast){
          currentToast.close()
        }
        currentToast = createToast({Vue,message, propsData: toastOptions,onclose: ()=>{
            currentToast = null
          }
        }) // 加了這句話
      }
    }
  }

  /* helpers */
  function createToast ({Vue,message,propsData,onclose}){
    let Constructor = Vue.extend(Toast)
    let toast = new Constructor({propsData})
    toast.$slots.default = [message]
    toast.$mount()
    toast.$on('close',onclose) // 加了這句話
    document.body.appendChild(toast.$el)
    return toast
  }
  1. git相關的鉤上,不想管的不用鉤上
  2. 回憶bug是如何產生的,默認樣式是:transform:translateX(-50%),進入0%時候transform:translateY(100%),它們兩會覆蓋。有三個方案,解決。
    • 換一種方式去作居中,可是這種方法是最好的,很難想
    • 不要用css作動畫
    • 作兩個div外面一個居中,裏面一個作動畫
  3. 爲何不寫兩個動畫幀來控制居中,若是一段代碼要背下來,那麼必定是有問題的。
  4. 優化三種動畫,上下中是不同的,經過css進行優化。

本文由博客一文多發平臺 OpenWrite 發佈!動畫

相關文章
相關標籤/搜索