[Vue]怎樣完成全屏遮罩(附Vue.extend和el-message源碼進修)
在做個人項目的時刻須要做一個相似於电子相冊瀏覽的控件,完成過程當中起首要完成全局遮罩,連繫本身的思緒並瀏覽了(餓了么)element-ui中el-message的完成,來總結一下Vue中比較好的一種全局遮罩的完成體式格局。
挪用遮罩的體式格局
平常由兩種寫法:
1.(相似el-dialog的一種寫法)
在html文件中寫好組織,掌握元素的顯現與隱蔽的完成遮罩。
<div class="container">
<div class="mask">。。。。。。。。。。</div>
</div>
<style>
.mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, .5);
z-index: 999;
}
</style>
比方在上述組織中,經由過程掌握mask的顯現與隱蔽來完成全局遮罩,mask的款式如上,經由過程position:fixed定位離開文檔流來完成佔有全屏空間。可以適用於大部分場景。
然則,position:fixed有他本身的特徵
position:fixed:
不為元素預留空間,而是經由過程指定元素相對於屏幕視口(viewport)的位置來指定元素位置。元素的位置在屏幕轉動時不會轉變。打印時,元素會出如今的每頁的牢固位置。fixed 屬性會建立新的層疊上下文。當元素先人的 transform 屬性非 none 時,容器由視口改成該先人。(引自MDN)
也就是說,假如父元素款式中具有transform時,不會做到全局遮罩哦。
在此我製作了2個demo.
一般全局遮罩
非一般全局遮罩(父元素container有transform)(chrome,firefox,edge翻開)
非一般全局遮罩款式:
<div class="container">
<div class="mask"><h1>非一般全局遮罩</h1></div>
</div>
<style>
.container {
height: 111px;
transform: translateX(1px);
}
.mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, .5);
z-index: 999;
color: white;
}
</style>
2. 動態增加(document.body.appendChild)
this.$message.success('登錄勝利')
第二種就像原生的alert一樣,如el-meaasge,經由過程敕令的體式格局來挪用。(雖然提醒信息未全局遮罩,增加思緒雷同)
document.body.appendChild(mask);
在document.body動態增加,以此來應用position:fixed來完成,平常對body我們不會加上transform這類屬性,因而避免了上述問題,所以適用性更廣一些,element-ui也是這類思緒。
Vue怎樣文雅的動態增加
這裏我們須要用到vue的實例化,起首我們來看element-ui的思緒,貼一段源碼
let MessageConstructor = Vue.extend(Main);//運用基本 Vue 組織器,建立一個“子類”。
let instance;//當前message
let instances = [];//正在顯現的一切message
let seed = 1;//相當於id,用於標記message
const Message = function (options) {
if (Vue.prototype.$isServer) return;//當前 Vue 實例是不是運轉於服務器。
options = options || {};
if (typeof options === 'string') {
options = {
message: options
};
}
let userOnClose = options.onClose;
let id = 'message_' + seed++;
// 簡樸包裝一下
options.onClose = function () {
Message.close(id, userOnClose);//封閉第id個message,並挪用回調
};
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();//統一管理 z-index
instances.push(instance);//到場本實例
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這個message
break;
}
}
};
Message.closeAll = function () {
for (let i = instances.length - 1; i >= 0; i--) {
instances[i].close();// 封閉一切message
}
};
export default Message;
瀏覽代碼我們可以曉得,經由過程Vue.extend我們獲取到一個子類的組織器。
在初始化並mount()(掛載)以後,將該message動態的加載document.body()中。
this.$el.parentNode.removeChild(this.$el);//移除dom節點
注重,message封閉的時刻會把我們增加的el移除哦。
若要相識main.vue,完全的解釋代碼見此處
Vue.extend
這裏再進修一些Vue.extend的學問。主如果我在染陌大神的解釋的基本上加了一點點解釋,見染陌大神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.
*/
/*
每一個組織函數實例(包括Vue本身)都邑有一個唯一的cid
它為我們可以製造繼承建立自組織函數並舉行緩存製造了能夠
*/
Vue.cid = 0
let cid = 1
/**
* Class inheritance
*/
/*
運用基本 Vue 組織器,建立一個“子類”。
實在就是擴大了基本組織器,形成了一個可復用的有指定父類組件功用的子組織器。
參數是一個包括組件option的對象。 https://cn.vuejs.org/v2/api/#Vue-extend-options
*/
Vue.extend = function (extendOptions: Object): Function {
extendOptions = extendOptions || {}//繼承
/*父類的組織*/
const Super = this
/*父類的cid*/
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
/*假如組織函數中已存在了該cid,則代表已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組織函數實在就一個_init要領,這跟Vue的組織要領是一致的,在_init中處置懲罰種種數據初始化、生命周期等。
由於Sub作為一個Vue的擴大組織器,所以基本的功用照樣須要保持一致,跟Vue組織器一樣在組織函數中初始化_init。
*/
const Sub = function VueComponent (options) {
this._init(options)//和vue初始化雷同,再次不再詳述
}
/*繼承父類*///比方_init就今後繼承而來
Sub.prototype = Object.create(Super.prototype)
/*組織函數*/
Sub.prototype.constructor = Sub
/*建立一個新的cid*/
Sub.cid = cid++
/*將父組件的option與子組件的合併到一同(Vue有一個cid為0的基類,即Vue本身,會將一些默許初始化的option何入)*/
Sub.options = mergeOptions(
Super.options,
extendOptions
)
/*es6語法,super為父類組織*/
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.
/*在擴大時,我們將盤算屬性以及props經由過程代辦綁定在Vue實例上(也就是vm),這也避免了Object.defineProperty被每一個實例挪用*/
if (Sub.options.props) {
/*初始化props,將option中的_props代辦到vm上*/
initProps(Sub)
}
if (Sub.options.computed) {
/*處置懲罰盤算屬性,給盤算屬性設置defineProperty並綁定在vm上*/
initComputed(Sub)
}
// allow further extension/mixin/plugin usage
/*到場extend、mixin以及use要領,許可未來繼承為該組件供應擴大、夾雜或許插件*/
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也會具有父類的私有選項(directives、filters、components)*/
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type]
})
// enable recursive self-lookup
/*把組件本身也到場components中,為遞歸本身供應能夠(遞歸組件也會查找components是不是存在當前組件,也就是本身)*/
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.
/*保留一個父類的options,今後我們可以用來檢測父類的options是不是已被更新*///_init時搜檢
Sub.superOptions = Super.options
/*extendOptions存儲起來*/
Sub.extendOptions = extendOptions
/*保留一份option,extend的作用是將Sub.options中的一切屬性放入{}中*/
Sub.sealedOptions = extend({}, Sub.options)
// cache constructor
/*緩存組織函數(用cid),防備反覆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)
}
}
/*處置懲罰盤算屬性,給盤算屬性設置defineProperty並綁定在vm上*/
function initComputed (Comp) {
const computed = Comp.options.computed
for (const key in computed) {
defineComputed(Comp.prototype, key, computed[key])
}
}
染陌大神解釋很詳實,Vue.extend主如果繼承父類的種種屬性來發生一個子類組織器.細緻請看源碼。
demo
末了展現一下demo吧,比較大略,隨便看一下就好。
lightbox在線預覽