摘要:不甘做輪子的搬運(yùn)工記錄一個(gè)實(shí)習(xí)菜鳥寫圖片預(yù)覽組件的艱辛道路很多組件中使用了指令模式和服務(wù)模式,比如以下以組件為例指令模式全屏覆蓋服務(wù)模式跟大多數(shù)萌新一樣,啥是服務(wù)先看看的目錄結(jié)構(gòu)打開目錄,找到其下目錄文件中有一大坨組件注冊(cè)信息重點(diǎn)找
不甘做輪子的搬運(yùn)工?。。?/b>
記錄一個(gè)實(shí)習(xí)菜鳥寫圖片預(yù)覽組件的艱辛道路~
elementUI很多組件中使用了指令模式和服務(wù)模式,比如:loading、message...以下以loading組件為例: 指令模式:
服務(wù)模式:全屏覆蓋
const loading = this.$loading({ lock: true, text: "Loading", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)" });跟大多數(shù)萌新一樣,啥是服務(wù)?!
先看看elmentUI的目錄結(jié)構(gòu):
打開node_modules目錄,找到其下elementUI目錄:
element-uisrcindex.js文件中有一大坨組件注冊(cè)信息,重點(diǎn)找到我們要找的loading...
// ... // directive 指令裝載 Vue.use(Loading.directive) // prototype 服務(wù)裝載 Vue.prototype.$loading = Loading.service // ...
Vue.use() 這個(gè)指令是 Vue 用來(lái)安裝插件的,如果傳入的參數(shù)是一個(gè)對(duì)象,則該對(duì)象要提供一個(gè) install 方法,如果是一個(gè)函數(shù),則該函數(shù)被視為 install 方法,在 install 方法調(diào)用時(shí),會(huì)將 Vue 作為參數(shù)傳入。
開始叭!先看看loading/index.js文件中是什么鬼?
//引入指令文件和服務(wù)文件,directive為指令模式文件,index.js為服務(wù)模式文件 import directive from "./src/directive"; import service from "./src/index"; export default { //install方法注冊(cè)組件,不在贅述install的用法,star-pic-list圖片預(yù)覽組件文章中已經(jīng)介紹過 install(Vue) { Vue.use(directive); //在vue的原型對(duì)象上注冊(cè)一個(gè)$loading的對(duì)象,這個(gè)$loading非常眼熟,看上面服務(wù)模式的使用,用到了this.$loading,源頭找到了 Vue.prototype.$loading = service; }, //引入的directive文件 directive, //引入的index.js文件 service };v-loading 指令解析
篇幅太長(zhǎng),其中我們只取 fullscreen 修飾詞。
// 引入 .vue 文件 import Vue from "vue" // 引入loading.vue基礎(chǔ)文件,里面包含的是組件的基礎(chǔ)結(jié)構(gòu),如html結(jié)構(gòu),loading顯示的頁(yè)面結(jié)構(gòu)都在這里面 import Loading from "./loading.vue" // 后面重點(diǎn)講解extend()構(gòu)造器 // Vue.extend() 是vue構(gòu)造器,它返回的是一個(gè)擴(kuò)展實(shí)例構(gòu)造器,也就是預(yù)設(shè)了部分選項(xiàng)的Vue實(shí)例構(gòu)造器, // mask字面意思是面具,掩飾,可以猜出來(lái),這個(gè)通過Vue.extend(Loading)返回構(gòu)造器應(yīng)該是用于我們loading加載時(shí)的遮罩層用的 // loading就是預(yù)設(shè)選項(xiàng),就像vue示例中,有components,name,data,methods...好像有點(diǎn)明白了 const Mask = Vue.extend(Loading) const loadingDirective = {} // 還記得 Vue.use() 的使用方法么?若傳入的是對(duì)象,該對(duì)象需要一個(gè) install 屬性 loadingDirective.install = Vue => { // toggleLoading 方法看名字就是切換loading顯示和隱藏的嘛~ const toggleLoading = (el, binding) => { // 若綁定值為 truthy 則插入 loading 元素 // binding 值是一個(gè)對(duì)象,有指令名、指令的綁定值、modifiers修飾符對(duì)象等等等等,具體的可以去了解自定義指令相關(guān)內(nèi)容 if (binding.value) { //binding.value是綁定的指令值 if (binding.modifiers.fullscreen) { 還記得我們插入的指令嗎?:v-loading.fullscreen="true" , .fullscreen就是修飾符 insertDom(document.body, el, binding) //insertDom看名字就知道是插入新的元素 } // visible 是loading.vue data里面定義的值 } else { el.instance.visible = false } } const insertDom = (parent, el, binding) => { // loading 設(shè)為可見 el.instance.visible = true // appendChild 添加的元素若為同一個(gè),則不會(huì)重復(fù)添加 parent.appendChild(el.mask) } // 在此注冊(cè) directive 指令 Vue.directive("loading", { bind: function(el, binding, vnode) { // 創(chuàng)建一個(gè)子組件,這里和 new Vue(options) 類似 // 返回一個(gè)組件實(shí)例 const mask = new Mask({ el: document.createElement("div"), // 有些人看到這里會(huì)迷惑,為什么這個(gè) data 不按照 Vue 官方建議傳函數(shù)進(jìn)去呢? // 其實(shí)這里兩者皆可 // 稍微做一點(diǎn)延展好了,在 Vue 源碼里面,data 是延遲求值的 // 貼一點(diǎn) Vue 源碼上來(lái) // return function mergedInstanceDataFn() { // let instanceData = typeof childVal === "function" // ? childVal.call(vm, vm) // : childVal; // let defaultData = typeof parentVal === "function" // ? parentVal.call(vm, vm) // : parentVal; // if (instanceData) { // return mergeData(instanceData, defaultData) // } else { // return defaultData // } // } // instanceData 就是我們現(xiàn)在傳入的 data: {} // defaultData 就是我們 loading.vue 里面的 data() {} // 看了這段代碼應(yīng)該就不難理解為什么可以傳對(duì)象進(jìn)去了 data: { fullscreen: !!binding.modifiers.fullscreen } }) // 將創(chuàng)建的子類掛載到 el 上 // 在 directive 的文檔中建議 // 應(yīng)該保證除了 el 之外其他參數(shù)(binding、vnode)都是只讀的 el.instance = mask // 掛載 dom // bind 只會(huì)調(diào)用一次,在bind 的時(shí)候給 el.mask 賦值,因此el.mask 所指的為同一個(gè) dom 元素 el.mask = mask.$el // 若 binding 的值為 truthy 運(yùn)行 toogleLoading binding.value && toggleLoading(el, binding) }, update: function(el, binding) { // 若舊不等于新值得時(shí)候(一般都是由 true 切換為 false 的時(shí)候) if (binding.oldValue !== binding.value) { // 切換顯示或消失 toggleLoading(el, binding) } }, unbind: function(el, binding) { // 當(dāng)組件 unbind 的時(shí)候,執(zhí)行組件銷毀 el.instance && el.instance.$destroy() } }) } export default loadingDirective
關(guān)于extend()更多內(nèi)容請(qǐng)參考這里,非常通熟易懂!loading服務(wù)方式調(diào)用原理
直接看源碼:
import Vue from "vue" import loadingVue from "./loading.vue" // 和指令模式一樣,創(chuàng)建實(shí)例構(gòu)造器 const LoadingConstructor = Vue.extend(loadingVue) // 定義變量,若使用的是全屏 loading 那就要保證全局的 loading 只有一個(gè) let fullscreenLoading // 這里可以看到和指令模式不同的地方 // 在調(diào)用了 close 之后就會(huì)移除該元素并銷毀組件 LoadingConstructor.prototype.close = function() { setTimeout(() => { if (this.$el && this.$el.parentNode) { this.$el.parentNode.removeChild(this.$el) } this.$destroy() }, 3000) } const Loading = (options = {}) => { // 若調(diào)用 loading 的時(shí)候傳入了 fullscreen 并且 fullscreenLoading 不為 falsy // fullscreenLoading 只會(huì)在下面賦值,并且指向了 loading 實(shí)例 if (options.fullscreen && fullscreenLoading) { return fullscreenLoading } // 這里就不用說(shuō)了吧,和指令中是一樣的 let instance = new LoadingConstructor({ el: document.createElement("div"), data: options }) let parent = document.body // 直接添加元素 parent.appendChild(instance.$el) // 將其設(shè)置為可見 // 另外,寫到這里的時(shí)候我查閱了相關(guān)的資料 // 自己以前一直理解 nextTick 是在 dom 元素更新完畢之后再執(zhí)行回調(diào) // 但是發(fā)現(xiàn)可能并不是這么回事,后續(xù)我會(huì)繼續(xù)研究 // 如果干貨足夠的話我會(huì)寫一篇關(guān)于 nextTick ui-render microtask macrotask 的文章 Vue.nextTick(() => { instance.visible = true }) // 若傳入了 fullscreen 參數(shù),則將實(shí)例存儲(chǔ) if (options.fullscreen) { fullscreenLoading = instance } // 返回實(shí)例,方便之后能夠調(diào)用原型上的 close() 方法 return instance } export default Loading現(xiàn)學(xué)現(xiàn)用-寫一個(gè)點(diǎn)擊圖片預(yù)覽的組件試試看 目錄結(jié)構(gòu):
directive.js是指令模式文件,index.js是服務(wù)模式文件,star-pic-preview.vue是基礎(chǔ)單文件,包含了基礎(chǔ)的html結(jié)構(gòu)
先看指令模式:使用:
我直接使用了指令,并沒有傳參,因?yàn)楣δ芎?jiǎn)單,默認(rèn)參數(shù)就是false
效果:
點(diǎn)擊出現(xiàn)遮罩層,圖片居中顯示預(yù)覽
服務(wù)模式:使用:
methods: { // 服務(wù)方式 openImagePreview2(e) { // 如果只傳圖片 this.$picPreview(e.target.src); //如果傳復(fù)雜對(duì)象,可以配置遮罩層的背景顏色等... // this.$picPreview({ // background: "rgba(0, 0, 0, 0.7)", // imageUrl: e.target.src, // }); }, }
效果如上
源碼請(qǐng)參考github地址: 源碼地址文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/109223.html
摘要:此時(shí),就出現(xiàn)了線程不安全問題了。因?yàn)榈某跏贾禃?huì)是因此,重排序是有可能導(dǎo)致線程安全問題的。真的能完全保證一個(gè)變量的線程安全嗎我們通過上面的講解,發(fā)現(xiàn)關(guān)鍵字還是挺有用的,不但能夠保證變量的可見性,還能保證代碼的有序性。 對(duì)于volatile這個(gè)關(guān)鍵字,相信很多朋友都聽說(shuō)過,甚至使用過,這個(gè)關(guān)鍵字雖然字面上理解起來(lái)比較簡(jiǎn)單,但是要用好起來(lái)卻不是一件容易的事。 這篇文章將從多個(gè)方面來(lái)講解vol...
摘要:徹底搞懂執(zhí)行機(jī)制首先我們大家都了解的是,是一門單線程語(yǔ)言,所以我們就可以得出是按照語(yǔ)句順序執(zhí)行的首先看這個(gè)顯然大家都知道結(jié)果,依次輸出,然而換一種這個(gè)時(shí)候再看代碼的順序執(zhí)行,輸出,,,。不過即使主線程為空,也是達(dá)不到的,根據(jù)標(biāo)準(zhǔn),最低是。 徹底搞懂JavaScript執(zhí)行機(jī)制 首先我們大家都了解的是,JavaScript 是一門單線程語(yǔ)言,所以我們就可以得出: JavaScript 是...
摘要:阻塞當(dāng)進(jìn)行讀寫時(shí),線程是阻塞的狀態(tài)。當(dāng)任何一個(gè)收到數(shù)據(jù)后,中斷程序?qū)酒疬M(jìn)程。接收數(shù)據(jù)當(dāng)收到數(shù)據(jù)后,中斷程序會(huì)給的就緒列表添加引用。當(dāng)接收到數(shù)據(jù),中斷程序一方面修改,另一方面喚醒等待隊(duì)列中的進(jìn)程,進(jìn)程再次進(jìn)入運(yùn)行狀態(tài)如下圖。 本篇文章目的在于基本概念和原理的解釋,不會(huì)貼過多的使用代碼。 什么是NIO Java NIO (New IO)是 Java 的另一個(gè) IO API (來(lái)自 jav...
摘要:對(duì)應(yīng)于上述的,等。匹配到的子字符串在原字符串中的偏移量。插入當(dāng)前匹配的子串右邊的內(nèi)容。 javascript這門語(yǔ)言一直就像一位帶著面紗的美女,總是看不清,摸不透,一直專注服務(wù)器端,也從來(lái)沒有特別重視過,直到最近幾年,javascript越來(lái)越重要,越來(lái)越通用。最近和前端走的比較近,借此機(jī)會(huì),好好鞏固一下相關(guān)知識(shí)點(diǎn)。 1.初識(shí)replace 在js中有兩個(gè)replace函數(shù) 一個(gè)是lo...
摘要:這正是我們想要的太棒了毫不意外的,這種繼承的方式被稱為構(gòu)造函數(shù)繼承,在中是一種關(guān)鍵的實(shí)現(xiàn)的繼承方法,相信你已經(jīng)很好的掌握了。 你應(yīng)該知道,JavaScript是一門基于原型鏈的語(yǔ)言,而我們今天的主題 -- 繼承就和原型鏈這一概念息息相關(guān)。甚至可以說(shuō),所謂的原型鏈就是一條繼承鏈。有些困惑了嗎?接著看下去吧。 一、構(gòu)造函數(shù),原型屬性與實(shí)例對(duì)象 要搞清楚如何在JavaScript中實(shí)現(xiàn)繼承,...
閱讀 2376·2023-04-25 20:07
閱讀 3311·2021-11-25 09:43
閱讀 3671·2021-11-16 11:44
閱讀 2537·2021-11-08 13:14
閱讀 3185·2021-10-19 11:46
閱讀 902·2021-09-28 09:36
閱讀 2997·2021-09-22 10:56
閱讀 2382·2021-09-10 10:51