成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

如何實(shí)現(xiàn)全屏遮罩(附Vue.extend和el-message源碼學(xué)習(xí))

malakashi / 2808人閱讀

摘要:如何優(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,完整的注釋代碼見此處

Vue.extend

這里再學(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

相關(guān)文章

  • 如何實(shí)現(xiàn)全屏遮罩Vue.extendel-message源碼學(xué)習(xí)

    摘要:如何優(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é)合自己的思路并閱讀了(...

    Zack 評(píng)論0 收藏0
  • 徹底搞懂elementUI指令與服務(wù)模式原理

    摘要:不甘做輪子的搬運(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...

    freewolf 評(píng)論0 收藏0
  • React組件庫封裝初探--Modal

    摘要:組件實(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...

    ybak 評(píng)論0 收藏0
  • React組件庫封裝初探--Modal

    摘要:組件實(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...

    codecraft 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

malakashi

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<