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