设计模式在vue中的应用(五)
前言
目錄整理:
設計模式在vue中的應用(一)
設計模式在vue中的應用(二)
設計模式在vue中的應用(三)
設計模式在vue中的應用(四)
設計模式在vue中的應用(五)
設計模式在vue中的應用(六)
為什么要寫這些文章呢。正如設計模式(Design Pattern)是一套被反復使用、多數人知曉的、經過分類的、代碼設計經驗的總結(來自百度百科)一樣,也是想通過分享一些工作中的積累與大家探討設計模式的魅力所在。
在這個系列文章中為了輔助說明引入的應用場景都是工作中真實的應用場景,當然無法覆蓋全面,但以此類推也覆蓋到了常見的業務場景
這一篇要講的可能和之前有點區別,前面幾篇要達到我們的目的不得不造出很多對象(組件),而本文的主角是讓我們減少對象——享元模式。
定義(來自網絡):
享元模式使用共享技術實現相同或者相似對象的重用。也就是說實現相同或者相似對象的代碼共享。
使用場景(來自百度百科):
如果一個應用程序使用了大量的對象,而這些對象造成了很大的存儲開銷的時候就可以考慮是否可以使用享元模式。
一、需求
截圖來自iView官方文檔(Message組件)
Message組件相信大家不會陌生,不知道大家有沒有親自實現過
二、需求分析
Message組件有以下幾個特點:
- 交互方式一樣
- 有三種類型:success、warning、error,對應三種不用的頁面效果:提示icon、背景樣式、字體樣式
- 接收一段提示文字
可以知道:
交互方式——彈出、隱藏,由共享對象所擁有
提示icon、背景樣式、字體樣式提供接口可配置
使用api統一
三、設計實現
常規使用方式this.$Message.success()、this.$Message.warning()、this.$Message.error()所以我們需要以vue插件的形式擴展vue的prototype
//Message.js 偽代碼 export default {install (Vue) {// 擴展Vue的`prototype`Vue.prototype.$Message = {success (text) {// 通常我們可能如下操作,每次new一個新的組件對象const Dialog = new Vue({...})document.body.appendChild(Dialog.$el)},warning (text) {// 同上,new一個新的組件對象const Dialog = new Vue({...})document.body.appendChild(Dialog.$el)},error (text) {// 同上,new一個新的組件對象const Dialog = new Vue({...})document.body.appendChild(Dialog.$el)}}} } 復制代碼如上例子所示每次使用Message組件都需new一個Dialog出來,下面我們使用享元模式的思想達到減少組件對象的目的
//Message.js 偽代碼 export default {install (Vue) {// 在使用插件Vue.use(Message)時實例化一個Dialog組件對象const Dialog = new Vue({data () {return {icon: '',fontStyle: '',backgroundStyle: '',text: ''}}...})// 擴展Vue的`prototype`Vue.prototype.$Message = {success (text) {// 改變Dialog的data.xx的值觸發Dialog的更新Dialog.icon = successIconDialog.fontStyle = successFontStyleDialog.backgroundStyle = successBackgroundStyleDialog.text = text// 獲取Dialog的最新DOM添加到body標簽中document.body.appendChild(Dialog.$el)},warning (text) {// 同上...document.body.appendChild(Dialog.$el)},error (text) {// 同上...document.body.appendChild(Dialog.$el)}}} } 復制代碼四、結果
都說做事是結果導向的,現在看看我們的設計得到了什么結果
Dialog只會在項目初始化時被new一次,每次使用Message組件通過改變Dialog的狀態獲取組件DOM,其實很容易知道new一個組件的成本要比一個組件的更新成本高很多
與常規的實現方案相比缺點是就算沒使用也會執行new Dialog()并占用內存
五、附完整實現(示例)
如有bug還請見諒隨手寫的
import './index.scss'let zIndex = 2001;export default {install (Vue) {const Dialog = new Vue({data () {return {text: '這是一個提示',icon: 'icon-waiting',iconColor: '#308AFE',background: '#ddd'}},render (h) {zIndex++const selfStyle = {background: this.background,zIndex}return h('div',{class: 'm-message',style: selfStyle},[h('i', {style: {marginRight: '8px', color: this.iconColor},class: `iconfont ${this.icon}`}),this.text])}}).$mount()function appendDialog(message, icon, iconColor, bgColor, time = 3) {Dialog.text = messageDialog.icon = iconDialog.iconColor = iconColorDialog.background = bgColorlet timer = ''let element = document.createElement('div')Dialog.$nextTick(() => {element = Dialog.$el.cloneNode(true)document.body.appendChild(element)})if(time > 0) {timer = setTimeout(() => {element.classList.add('outer')setTimeout(() => {document.body.removeChild(element)}, 500);clearTimeout(timer)}, time * 1000);}}Vue.prototype.$message = {tips (message, time) {appendDialog(message, 'icon-waiting', '#308AFE', '#ADD8F7', time)},warning(message, time) {appendDialog(message, 'icon-warn', '#FFAF0D', '#FCCCA7', time)},success(message, time) {appendDialog(message, 'icon-success', '#36B37E', '#A7E1C4', time)},error(message, time) {appendDialog(message, 'icon-error', '#E95B5B', '#FFF4F4', time)},destory() {document.querySelectorAll('.m-message').forEach(ele => ele.remove())}}} } 復制代碼六、總結
回想一下在講解講享元模式時大多會例舉的一個場景
有男女衣服各50套,現在要給這些衣服拍照怎么辦呢?土豪做法:new 100個模特對象一人穿一套慢慢拍,有錢任性(內存占有率高) 理性做法:new 一個男模特和一個女模特拍完一套換一套接著拍(暴露一個換衣服的接口),也沒差,主要是省錢(對象從100個減少為2個) 復制代碼熟悉設計模式同學的可能覺得這個場景不太好,我認同你的觀點,不過用來學習享元模式個人覺得還能接受。
Message組件的具體實現方案不拒絕也不推薦本文的方式(哈哈哈~)
更新:發現elemnet-ui的MessageBox組件就是類似的思路傳送門
本文實現同樣適用于react,為什么文章以vue做題?vue的template讓我們在理解一些概念的時候可能會有點不適應,而react的jsx可以看做就是在寫JavaScript對各種概念實現更靈活
友情提示:設計模式在vue中的應用應該會寫一個系列,喜歡的同學記得關注下
總結
以上是生活随笔為你收集整理的设计模式在vue中的应用(五)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu2121 Ice_cream's
- 下一篇: html5倒计时秒杀怎么做,vue 设