造輪子-toast元件的實現(下)
阿新 • • 發佈:2020-01-27
1.解決 toast 中傳入 html 的問題,通過假的 slot 來實現
// 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 是比較危險的一個動作,所以要加一個選項預設不開啟。
// 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,即如果空間不足,該專案將縮小。
.item {
flex-shrink: <number>; /* default 1 */
}
如果所有專案的flex-shrink屬性都為1,當空間不足時,都將等比例縮小。如果一個專案的flex-shrink屬性為0,其他專案都為1,則空間不足時,前者不縮小。如果數值越大,縮小比例越大。
4.line的高度問題,如果高度寫了最小高度,那麼子元素的height%就不生效了。用js去操作line的高度。
// 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就把之前那個幹掉,再出現。
- 先寫一個函式
- 給函式取一個名字
- 把引數提出來
// 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.實現動畫
- 宣告一個動畫,然後寫到類上面
@keyframes fade {
0% {opacity: 0; transform: translateY(100%);}
100% {opacity: 1;transform: translateY(0);}
}
.toast {
animation: fade 1s;
}
- 這裡有個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
}
- git相關的鉤上,不想管的不用鉤上
- 回憶bug是如何產生的,預設樣式是:transform:translateX(-50%),進入0%時候transform:translateY(100%),它們兩會覆蓋。有三個方案,解決。
- 換一種方式去做居中,但是這種方法是最好的,很難想
- 不要用css做動畫
- 做兩個div外面一個居中,裡面一個做動畫
- 為什麼不寫兩個動畫幀來控制居中,如果一段程式碼要背下來,那麼一定是有問題的。
- 優化三種動畫,上下中是不一樣的,通過css進行優化。