摘要:如何優(yōu)雅的動(dòng)態(tài)添加這里我們需要用到的實(shí)例化,首先我們來看的思路,貼一段源碼使用基礎(chǔ)構(gòu)造器,創(chuàng)建一個(gè)子類。因?yàn)樽鳛橐粋€(gè)的擴(kuò)展構(gòu)造器,所以基礎(chǔ)的功能還是需要保持一致,跟構(gòu)造器一樣在構(gòu)造函數(shù)中初始化。
[Vue]如何實(shí)現(xiàn)全屏遮罩(附Vue.extend和el-message源碼學(xué)習(xí))
在做個(gè)人項(xiàng)目的時(shí)候需要做一個(gè)類似于電子相冊(cè)瀏覽的控件,實(shí)現(xiàn)過程中首先要實(shí)現(xiàn)全局遮罩,結(jié)合自己的思路并閱讀了(餓了么)element-ui中el-message的實(shí)現(xiàn),來總結(jié)一下Vue中比較好的一種全局遮罩的實(shí)現(xiàn)方式。
調(diào)用遮罩的方式一般由兩種寫法:
1.(類似el-dialog的一種寫法)在html文件中寫好結(jié)構(gòu),控制元素的顯示與隱藏的實(shí)現(xiàn)遮罩。
。。。。。。。。。。
比如在上述結(jié)構(gòu)中,通過控制mask的顯示與隱藏來實(shí)現(xiàn)全局遮罩,mask的樣式如上,通過position:fixed定位脫離文檔流來實(shí)現(xiàn)占據(jù)全屏空間。可以適用于大部分場(chǎng)景。
但是,position:fixed有他自己的特性
position:fixed:
不為元素預(yù)留空間,而是通過指定元素相對(duì)于屏幕視口(viewport)的位置來指定元素位置。元素的位置在屏幕滾動(dòng)時(shí)不會(huì)改變。打印時(shí),元素會(huì)出現(xiàn)在的每頁的固定位置。fixed 屬性會(huì)創(chuàng)建新的層疊上下文。當(dāng)元素祖先的 transform 屬性非 none 時(shí),容器由視口改為該祖先。(引自MDN)
也就是說,如果父元素樣式中具有transform時(shí),不會(huì)做到全局遮罩哦。
在此我制作了2個(gè)demo.
正常全局遮罩
非正常全局遮罩(父元素container有transform)(chrome,firefox,edge打開)
非正常全局遮罩樣式:
2. 動(dòng)態(tài)添加(document.body.appendChild)非正常全局遮罩
this.$message.success("登錄成功")
第二種就像原生的alert一樣,如el-meaasge,通過命令的方式來調(diào)用。(雖然提示信息未全局遮罩,添加思路相同)
document.body.appendChild(mask);
在document.body動(dòng)態(tài)添加,以此來利用position:fixed來實(shí)現(xiàn),一般對(duì)body我們不會(huì)加上transform這種屬性,因此避免了上述問題,所以適用性更廣一些,element-ui也是這種思路。
Vue如何優(yōu)雅的動(dòng)態(tài)添加這里我們需要用到vue的實(shí)例化,首先我們來看element-ui的思路,貼一段源碼
let MessageConstructor = Vue.extend(Main);//使用基礎(chǔ) Vue 構(gòu)造器,創(chuàng)建一個(gè)“子類”。 let instance;//當(dāng)前message let instances = [];//正在顯示的所有message let seed = 1;//相當(dāng)于id,用于標(biāo)記message const Message = function (options) { if (Vue.prototype.$isServer) return;//當(dāng)前 Vue 實(shí)例是否運(yùn)行于服務(wù)器。 options = options || {}; if (typeof options === "string") { options = { message: options }; } let userOnClose = options.onClose; let id = "message_" + seed++; // 簡(jiǎn)單包裝一下 options.onClose = function () { Message.close(id, userOnClose);//關(guān)閉第id個(gè)message,并調(diào)用回調(diào) }; instance = new MessageConstructor({ data: options }); instance.id = id; if (isVNode(instance.message)) { instance.$slots.default = [instance.message];//html模板 TODO instance.message = null; } instance.vm = instance.$mount(); instance.vm.visible = true; document.body.appendChild(instance.vm.$el); instance.dom = instance.vm.$el; instance.dom.style.zIndex = PopupManager.nextZIndex();//統(tǒng)一管理 z-index instances.push(instance);//加入本實(shí)例 return instance.vm; }; ["success", "warning", "info", "error"].forEach(type => { Message[type] = options => { if (typeof options === "string") { options = { message: options }; } options.type = type; return Message(options); }; }); Message.close = function (id, userOnClose) { for (let i = 0, len = instances.length; i < len; i++) { if (id === instances[i].id) { if (typeof userOnClose === "function") { userOnClose(instances[i]); } instances.splice(i, 1);//從正在顯示的所有message中移除id這個(gè)message break; } } }; Message.closeAll = function () { for (let i = instances.length - 1; i >= 0; i--) { instances[i].close();// 關(guān)閉所有message } }; export default Message;
閱讀代碼我們可以知道,通過Vue.extend我們獲取到一個(gè)子類的構(gòu)造器。
在初始化并mount()(掛載)之后,將該message動(dòng)態(tài)的加載document.body()中。
this.$el.parentNode.removeChild(this.$el);//移除dom節(jié)點(diǎn)
注意,message關(guān)閉的時(shí)候會(huì)把我們添加的el移除哦。
若要了解main.vue,完整的注釋代碼見此處
這里再學(xué)習(xí)一些Vue.extend的知識(shí)。主要是我在染陌大神的注釋的基礎(chǔ)上加了一點(diǎn)點(diǎn)注釋,見染陌大神github
export function initExtend (Vue: GlobalAPI) { /** * Each instance constructor, including Vue, has a unique * cid. This enables us to create wrapped "child * constructors" for prototypal inheritance and cache them. */ /* 每個(gè)構(gòu)造函數(shù)實(shí)例(包括Vue本身)都會(huì)有一個(gè)唯一的cid 它為我們能夠創(chuàng)造繼承創(chuàng)建自構(gòu)造函數(shù)并進(jìn)行緩存創(chuàng)造了可能 */ Vue.cid = 0 let cid = 1 /** * Class inheritance */ /* 使用基礎(chǔ) Vue 構(gòu)造器,創(chuàng)建一個(gè)“子類”。 其實(shí)就是擴(kuò)展了基礎(chǔ)構(gòu)造器,形成了一個(gè)可復(fù)用的有指定父類組件功能的子構(gòu)造器。 參數(shù)是一個(gè)包含組件option的對(duì)象。 https://cn.vuejs.org/v2/api/#Vue-extend-options */ Vue.extend = function (extendOptions: Object): Function { extendOptions = extendOptions || {}//繼承 /*父類的構(gòu)造*/ const Super = this /*父類的cid*/ const SuperId = Super.cid const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {}) /*如果構(gòu)造函數(shù)中已經(jīng)存在了該cid,則代表已經(jīng)extend過了,直接返回*/ if (cachedCtors[SuperId]) { return cachedCtors[SuperId] } //組件name const name = extendOptions.name || Super.options.name if (process.env.NODE_ENV !== "production") { /*name只能包含字母與連字符*/ if (!/^[a-zA-Z][w-]*$/.test(name)) { warn( "Invalid component name: "" + name + "". Component names " + "can only contain alphanumeric characters and the hyphen, " + "and must start with a letter." ) } } /* Sub構(gòu)造函數(shù)其實(shí)就一個(gè)_init方法,這跟Vue的構(gòu)造方法是一致的,在_init中處理各種數(shù)據(jù)初始化、生命周期等。 因?yàn)镾ub作為一個(gè)Vue的擴(kuò)展構(gòu)造器,所以基礎(chǔ)的功能還是需要保持一致,跟Vue構(gòu)造器一樣在構(gòu)造函數(shù)中初始化_init。 */ const Sub = function VueComponent (options) { this._init(options)//和vue初始化相同,再次不再詳述 } /*繼承父類*///比如_init就從此繼承而來 Sub.prototype = Object.create(Super.prototype) /*構(gòu)造函數(shù)*/ Sub.prototype.constructor = Sub /*創(chuàng)建一個(gè)新的cid*/ Sub.cid = cid++ /*將父組件的option與子組件的合并到一起(Vue有一個(gè)cid為0的基類,即Vue本身,會(huì)將一些默認(rèn)初始化的option何入)*/ Sub.options = mergeOptions( Super.options, extendOptions ) /*es6語法,super為父類構(gòu)造*/ Sub["super"] = Super // For props and computed properties, we define the proxy getters on // the Vue instances at extension time, on the extended prototype. This // avoids Object.defineProperty calls for each instance created. /*在擴(kuò)展時(shí),我們將計(jì)算屬性以及props通過代理綁定在Vue實(shí)例上(也就是vm),這也避免了Object.defineProperty被每一個(gè)實(shí)例調(diào)用*/ if (Sub.options.props) { /*初始化props,將option中的_props代理到vm上*/ initProps(Sub) } if (Sub.options.computed) { /*處理計(jì)算屬性,給計(jì)算屬性設(shè)置defineProperty并綁定在vm上*/ initComputed(Sub) } // allow further extension/mixin/plugin usage /*加入extend、mixin以及use方法,允許將來繼續(xù)為該組件提供擴(kuò)展、混合或者插件*/ Sub.extend = Super.extend Sub.mixin = Super.mixin Sub.use = Super.use // create asset registers, so extended classes // can have their private assets too. /*使得Sub也會(huì)擁有父類的私有選項(xiàng)(directives、filters、components)*/ ASSET_TYPES.forEach(function (type) { Sub[type] = Super[type] }) // enable recursive self-lookup /*把組件自身也加入components中,為遞歸自身提供可能(遞歸組件也會(huì)查找components是否存在當(dāng)前組件,也就是自身)*/ if (name) { Sub.options.components[name] = Sub } // keep a reference to the super options at extension time. // later at instantiation we can check if Super"s options have // been updated. /*保存一個(gè)父類的options,此后我們可以用來檢測(cè)父類的options是否已經(jīng)被更新*///_init時(shí)檢查 Sub.superOptions = Super.options /*extendOptions存儲(chǔ)起來*/ Sub.extendOptions = extendOptions /*保存一份option,extend的作用是將Sub.options中的所有屬性放入{}中*/ Sub.sealedOptions = extend({}, Sub.options) // cache constructor /*緩存構(gòu)造函數(shù)(用cid),防止重復(fù)extend*/ cachedCtors[SuperId] = Sub return Sub } } /*初始化props,將option中的_props代理到vm上*/ function initProps (Comp) { const props = Comp.options.props for (const key in props) { proxy(Comp.prototype, `_props`, key) } } /*處理計(jì)算屬性,給計(jì)算屬性設(shè)置defineProperty并綁定在vm上*/ function initComputed (Comp) { const computed = Comp.options.computed for (const key in computed) { defineComputed(Comp.prototype, key, computed[key]) } }
染陌大神注釋很詳盡,Vue.extend主要是繼承父類的各種屬性來產(chǎn)生一個(gè)子類構(gòu)造器.詳細(xì)請(qǐng)看源碼。
demo最后展示一下demo吧,比較簡(jiǎn)陋,隨意看一下就好。
lightbox在線預(yù)覽
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/107741.html
摘要:如何優(yōu)雅的動(dòng)態(tài)添加這里我們需要用到的實(shí)例化,首先我們來看的思路,貼一段源碼使用基礎(chǔ)構(gòu)造器,創(chuàng)建一個(gè)子類。因?yàn)樽鳛橐粋€(gè)的擴(kuò)展構(gòu)造器,所以基礎(chǔ)的功能還是需要保持一致,跟構(gòu)造器一樣在構(gòu)造函數(shù)中初始化。 [Vue]如何實(shí)現(xiàn)全屏遮罩(附Vue.extend和el-message源碼學(xué)習(xí)) 在做個(gè)人項(xiàng)目的時(shí)候需要做一個(gè)類似于電子相冊(cè)瀏覽的控件,實(shí)現(xiàn)過程中首先要實(shí)現(xiàn)全局遮罩,結(jié)合自己的思路并閱讀了(...
摘要:不甘做輪子的搬運(yùn)工記錄一個(gè)實(shí)習(xí)菜鳥寫圖片預(yù)覽組件的艱辛道路很多組件中使用了指令模式和服務(wù)模式,比如以下以組件為例指令模式全屏覆蓋服務(wù)模式跟大多數(shù)萌新一樣,啥是服務(wù)先看看的目錄結(jié)構(gòu)打開目錄,找到其下目錄文件中有一大坨組件注冊(cè)信息重點(diǎn)找 不甘做輪子的搬運(yùn)工!??! 記錄一個(gè)實(shí)習(xí)菜鳥寫圖片預(yù)覽組件的艱辛道路~ elementUI很多組件中使用了指令模式和服務(wù)模式,比如:loading、mes...
摘要:組件實(shí)現(xiàn)基本簡(jiǎn)介類似于實(shí)現(xiàn)的組件,首先基本結(jié)構(gòu)分析遮罩層內(nèi)容包裝層主體內(nèi)容層,包含固定定位布局,全屏遮蓋顯示,所以內(nèi)容自定義實(shí)現(xiàn)功能目標(biāo)兩種調(diào)用方式一些內(nèi)容遮罩層和的顯示與否,單擊是否可關(guān)閉其他必備功能結(jié)構(gòu)布局攻克基本布局遮 Madal組件實(shí)現(xiàn)基本簡(jiǎn)介 showImg(https://segmentfault.com/img/bVbqhvl?w=1848&h=834); 類似于an...
摘要:組件實(shí)現(xiàn)基本簡(jiǎn)介類似于實(shí)現(xiàn)的組件,首先基本結(jié)構(gòu)分析遮罩層內(nèi)容包裝層主體內(nèi)容層,包含固定定位布局,全屏遮蓋顯示,所以內(nèi)容自定義實(shí)現(xiàn)功能目標(biāo)兩種調(diào)用方式一些內(nèi)容遮罩層和的顯示與否,單擊是否可關(guān)閉其他必備功能結(jié)構(gòu)布局攻克基本布局遮 Madal組件實(shí)現(xiàn)基本簡(jiǎn)介 showImg(https://segmentfault.com/img/bVbqhvl?w=1848&h=834); 類似于an...
閱讀 1717·2021-10-13 09:39
閱讀 2141·2021-09-07 10:20
閱讀 2731·2019-08-30 15:56
閱讀 2997·2019-08-30 15:56
閱讀 971·2019-08-30 15:55
閱讀 708·2019-08-30 15:46
閱讀 3532·2019-08-30 15:44
閱讀 2604·2019-08-30 11:15