面對面用Vue造一個Toast輪子(包含測試用例)

先上效果圖...

toast.gif

toast.png

Toast需求:

  • 彈出Toast自動關(guān)閉
  • 多少(N)秒后自動關(guān)閉
  • 彈出Toast用戶可點擊關(guān)閉
  • 用戶點擊關(guān)閉后回調(diào)(fn)
  • 保證只有一個Toast彈出赘那,不會同時出現(xiàn)兩個飞苇。

用法:

import Vue from 'vue'
import plugin from './plugin/index'
Vue.use(plugin)

this.$toast('操作成功!!帝牡!')

Github:歡迎Star


這里是分割線


開始面對面挥转,看代碼...

不管在哪里都可以直接使用this.$toast,具體如何實現(xiàn)锥咸??细移? 請看Vue官方文檔

1搏予、main.js

Vue.prototype.$toast = function () {
  console.log('我是蘇宋霖');
}

2、App.vue

<template>
  <div id="app">
    <button @click="xxx">點我</button>
  </div>
</template>
  export default {
    name: 'app',
    methods: {
      xxx() {
        this.$toast()
      },
    }
}

點擊按鈕控制臺是不是打印出了我是蘇宋霖弧轧,做到這里你已經(jīng)成功一半了??

clickToast.gif

但是這樣并不是我們想要的雪侥,使用插件形式install,讓用戶主動去使用精绎。

繼續(xù)改造?

新建plugin/index.js

export default {
  install(Vue,options){
    Vue.prototype.$toast = function(message){
      console.log(message);
    }
  }
}

main.js

import plugin from './plugin/index'
Vue.use(plugin)

使用

this.$toast('我是蘇宋霖')

控制一樣打印出我是蘇宋霖, 說明你距離成功不遠了 (這句話跟高中老師一樣速缨,經(jīng)常對我們學生說前腳已經(jīng)跨進北大的校門了,后來我們畢業(yè)了才知道北大是可以隨便進出代乃,哪怕登記一下就好)

Vue.use 會自動阻止多次注冊相同插件旬牲,屆時即使多次調(diào)用也只會注冊一次該插件。

繼續(xù)改造??

新建components/Toast.vue

<template>
  <div>
      <slot></slot>  
  </div>
</template>
<script>
export default {
  name:'Toast'  
}
</script>

在引入Toast.vue之前有個問題如何在js使用vue實例 搁吓?原茅?

1、方應(yīng)杭的Vue 動態(tài)創(chuàng)建實例
2堕仔、滴滴的cube-ui專門為這個場景實現(xiàn)了一個create-api, 可以將任意自定義組件制作成調(diào)用時動態(tài)創(chuàng)建的插件

plugin/index.js 引入Toast.vue

import Toast from '@/components/Toast.vue'
export default {
  install(Vue,options){
    Vue.prototype.$toast = function(message){
      let Constructor = Vue.extend(Toast)
      let toast = new Constructor()
      toast.$mount()
      document.body.appendChild(toast.$el)  //添加到頁面中
    }
  }
}

通過??代碼可以實現(xiàn)動態(tài)創(chuàng)建實例(別用原生js實現(xiàn)如: let div = document.createElement("div"); document.body.appendChild(div)员咽,這樣無法使用到vue的各種生命周期及Api)

appendChildToast.gif
繼續(xù)改造???

Toast.vue 文件不變,index.js通過插槽傳值給Toast.vue
問題:如果在js中使用插槽傳值爸ぁ贝室??仿吞? 我的天
看文檔渲染函數(shù) & JSX
this.$slots.default // 子節(jié)點數(shù)組 注意這里接收的是數(shù)組 數(shù)組 數(shù)組

import Toast from '@/components/Toast.vue'
export default {
  install(Vue,options){
    Vue.prototype.$toast = function(message){
      let Constructor = Vue.extend(Toast)
      let toast = new Constructor()
      toast.$slots.default = [message] //slots必須要放在mount之前
      toast.$mount()
      document.body.appendChild(toast.$el)
    }
  }
}
slots.gif

添加簡單樣式

<style lang="scss" scoped>
 $font-size:14px;
  $toast-height:40px;
  $toast-bg:rgba(0, 0, 0, 0.75);
  .toast {
    font-size: $font-size;
    line-height: 1.8;
    height: $toast-height;
    position: fixed;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    color: white;
    background: $toast-bg;
    border-radius: 4px;
    box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.50);
    padding: 0 16px;
  }
</style>
繼續(xù)改造????

實現(xiàn)3s后自動關(guān)閉,

  props: {
    // 自動關(guān)閉
    autoClose: {
      type: Boolean,
      default: true
    },
    // 關(guān)閉時間
    autoCloseDelay: {
      type: Number,
      default: 3
    }
  },
  mounted() {
    if (this.autoClose) {
      setTimeout(() => {
        this.close();
      }, this.autoCloseDelay * 1000);
    }
  },
  methods: {
    close() {
      this.$el.remove(); //刪除
      this.$destroy(); //清除綁定的一些事件
    }
  }
autoClose.gif
繼續(xù)改造?????

彈出Toast用戶可點擊關(guān)閉

<template>
  <div class="toast">
    <slot></slot>
    <div class="line"></div>
    <span class="close" v-if="closeButton" @click="onClickclose">{{closeButton.text}}</span>
  </div>
</template>
<script>
export default {
  name: "Toast",
  props: {
  //點擊關(guān)閉
    closeButton: {
      type: Object,
      default() {
        return {
          text: "關(guān)閉",
          callback: undefined
        };
      }
    }
  },
 
  methods: {
    close() {
      this.$el.remove(); //刪除
      this.$destroy(); //清除綁定的一些事件
    },
    onClickclose() {
      this.close();
      if (this.closeButton && typeof this.closeButton.callback === "function") {
        this.closeButton.callback();
      }
    }
  }
};
</script>

plugin/index.js

import Toast from '@/components/Toast.vue'
export default {
  install(Vue,options){
    Vue.prototype.$toast = function(message,toaseOptions){
      let Constructor = Vue.extend(Toast)
      let toast = new Constructor({
        propsData:toaseOptions
      })
      toast.$slots.default = [message]
      toast.$mount()
      document.body.appendChild(toast.$el)
    }
  }
}

使用

    this.$toast('我是蘇宋霖',{
            closeButton:{
            text:'知道了',
            callback(){
              console.log('蘇宋霖點擊知道了');
            }
          }
        })
closeButton.gif

手動測試發(fā)現(xiàn)一個問題滑频,內(nèi)容過多的時候Toast并沒有變化,
關(guān)閉按鈕被擠壓
如下:


溢出.png

改造吧支持多行文字
使用js去給line添加高度,因為父元素的高度變成min-height唤冈。

//html 
 <div class="toast" ref="toast">
    <slot></slot>
    <div class="line" ref="line"></div>
    <span class="close" v-if="closeButton" @click="onClickclose">{{closeButton.text}}</span>
  </div>
//js
mounted(){
    this.updateStyle()
},
  methods: {
     updateStyle() {
        this.$nextTick(() => {
          this.$refs.line.style.height =
            `${this.$refs.toast.getBoundingClientRect().height}px`
        })
      },
}
//css 新增的
<style lang="scss" scoped>
$toast-min-height: 40px;
.toast {
  min-height: $toast-min-height;
  .close {
    flex-shrink: 0;
  }
}
</style>
改造后....png

繼續(xù)改造??????

Toast的位置
在.toast上加:class="toastClasses",通過props傳過來的屬性position 動態(tài)添加class

//html
 <div class="toast" ref="toast" :class="toastClasses">
    <slot></slot>
    <div class="line" ref="line"></div>
    <span class="close" v-if="closeButton" @click="onClickclose">{{closeButton.text}}</span>
  </div>

//js
props:{
    // 位置
    position: {
      type: String,
      default: "top",
      validator(value) {
        return ["top", "bottom", "middle"].indexOf(value) >= 0;
      }
    }
}

  computed: {
    toastClasses() {
      return {
        [`position-${this.position}`]: true
      };
    }
  },
//css
  &.position-top {
    top: 0;
    transform: translateX(-50%);
  }

  &.position-bottom {
    bottom: 0;
    transform: translateX(-50%);
  }
  &.position-middle {
    top: 50%;
    transform: translate(-50%, -50%);
  }

使用

<template>
  <div id="app">
    <button @click="xxx1">點擊 上</button>
    <button @click="xxx2">點擊 中</button>
    <button @click="xxx3">點擊 下</button>
  </div>
</template>

<script>
  export default {
    name: 'app',
    methods: {
      xxx1(){
        this.xxx('top')
      },
      xxx2(){
         this.xxx('middle')
      },
      xxx3(){
         this.xxx('bottom')
      },
      xxx(position) {
        this.$toast('我是蘇宋霖我是蘇宋霖我是蘇宋霖我是蘇宋霖我是蘇宋霖我是蘇宋霖我是蘇宋霖',{
          position,
            closeButton:{
            text:'知道了',
            callback(){
              console.log('蘇宋霖點擊知道了');
            }
          }
        })
      },
    
    },
  }
</script>

position.gif

新問題:
用戶重復(fù)點擊Toast峡迷,會出現(xiàn)多個DOM??


重復(fù)DOM.gif

解決方案:
如果已經(jīng)有一個Toast绘搞,就把之前的給刪了
plugin/index.js

import Toast from '@/components/Toast.vue'

export default {
  install(Vue,options){
    let currentToast ;
    Vue.prototype.$toast = function(message,toaseOptions){
      if(currentToast){currentToast.close()}//如果有Toast就刪除上一個
      currentToast =  createToast({Vue,propsData:toaseOptions,message})
    }
  }
}

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

ps:樣式啥的請自行修改彤避。


輪子完畢!:幌健琉预! 接下來測試用例..

未完待續(xù)...

提示:

npm 配置淘寶源:npm config set registry https://registry.npm.taobao.org/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蒿褂,隨后出現(xiàn)的幾起案子圆米,更是在濱河造成了極大的恐慌,老刑警劉巖啄栓,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娄帖,死亡現(xiàn)場離奇詭異,居然都是意外死亡昙楚,警方通過查閱死者的電腦和手機近速,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堪旧,“玉大人数焊,你說我怎么就攤上這事∑槌。” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵遂蛀,是天一觀的道長谭跨。 經(jīng)常有香客問我,道長李滴,這世上最難降的妖魔是什么螃宙? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮所坯,結(jié)果婚禮上谆扎,老公的妹妹穿的比我還像新娘。我一直安慰自己芹助,他們只是感情好堂湖,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著状土,像睡著了一般无蜂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蒙谓,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天斥季,我揣著相機與錄音,去河邊找鬼。 笑死酣倾,一個胖子當著我的面吹牛舵揭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播躁锡,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼午绳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了稚铣?” 一聲冷哼從身側(cè)響起箱叁,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惕医,沒想到半個月后耕漱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡抬伺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年螟够,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峡钓。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡妓笙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出能岩,到底是詐尸還是另有隱情寞宫,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布拉鹃,位于F島的核電站辈赋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏膏燕。R本人自食惡果不足惜钥屈,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坝辫。 院中可真熱鬧篷就,春花似錦、人聲如沸近忙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽及舍。三九已至永品,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間击纬,已是汗流浹背鼎姐。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人炕桨。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓饭尝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親献宫。 傳聞我的和親對象是個殘疾皇子钥平,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容

  • ## 框架和庫的區(qū)別?> 框架(framework):一套完整的軟件設(shè)計架構(gòu)和**解決方案**。> > 庫(lib...
    Rui_bdad閱讀 2,917評論 1 4
  • 基于Vue的一些資料 內(nèi)容 UI組件 開發(fā)框架 實用庫 服務(wù)端 輔助工具 應(yīng)用實例 Demo示例 element★...
    嘗了又嘗閱讀 1,156評論 0 1
  • 響應(yīng)式布局的理解 響應(yīng)式開發(fā)目的是一套代碼可以在多種終端運行,適應(yīng)不同屏幕的大小,其原理是運用媒體查詢,在不同屏幕...
    懶貓_6500閱讀 790評論 0 0
  • 概要 64學時 3.5學分 章節(jié)安排 電子商務(wù)網(wǎng)站概況 HTML5+CSS3 JavaScript Node 電子...
    阿啊阿吖丁閱讀 9,223評論 0 3
  • vue-cli搭建項目 確保安裝了node與npm 再目標文件夾下打開終端 執(zhí)行cnpm i vue-cli -g...
    Akiko_秋子閱讀 3,243評論 1 22