Vue.prototype詳解及使用方式
我們可能會(huì)在很多組件里用到數(shù)據(jù)/實(shí)用工具,但是不想污染全局作用域。
這種情況下,可以通過(guò)在原型上定義它們使其在每個(gè) Vue 的實(shí)例中可用。
1. 基本示例
在main.js中添加一個(gè)變量到 Vue.prototype
Vue.prototype.$appName = 'My App'
這樣 $appName 就在所有的 Vue 實(shí)例中可用了,甚至在實(shí)例被創(chuàng)建之前就可以
beforeCreate: function () { console.log(this.$appName) }
控制臺(tái)會(huì)打印出 My App
2. 為實(shí)例prototype設(shè)置作用域
為什么 appName 要以 $ 開(kāi)頭?
$
是在 Vue 所有實(shí)例中都可用的 property
的一個(gè)簡(jiǎn)單約定
。
這樣做會(huì)避免和已被定義的數(shù)據(jù)、方法、計(jì)算屬性產(chǎn)生沖突。
如果我們?cè)O(shè)置:
Vue.prototype.appName = 'My App'
export default { data(){ return{ appName:'組件實(shí)例中的appName' } }, beforeCreate: function () { console.log(this.appName) }, created: function () { console.log(this.appName) }, } </script>
日志中會(huì)先出現(xiàn) “My App”,然后出現(xiàn) “組件實(shí)例中的appName”,因?yàn)?this.appName 在實(shí)例被創(chuàng)建之后被 data 覆寫了。
我們通過(guò) $ 為實(shí)例 property 設(shè)置作用域來(lái)避免這種事情發(fā)生。
3. 注冊(cè)和使用全局變量
每個(gè)組件都是一個(gè)vue實(shí)例,Vue.prototype加一個(gè)變量,只是給每個(gè)組件加了一個(gè)屬性,這個(gè)屬性的值并不具有全局性。
比如以下例子:
Vue.prototype.$appName = 'main'
給所有組件注冊(cè)了一個(gè)屬性 $appName,賦予初始值 'main' ,所有組件都可以用 this.$appName 訪問(wèn)此變量;
如果組件中沒(méi)有賦值,初始值都是'main'
app.vue
<template> <div id="app"> 主組件name-》{{this.$appName}} <p>{{newName}}</p> <button @click="changeName">更改name</button> <button @click="$router.push('/cs')">跳轉(zhuǎn)</button> <hr> <router-view></router-view> </div> </template>
<script> export default { data(){ return{ newName:'' } }, methods:{ changeName(){ this.$appName = "changeName" this.newName=this.$appName } } } </script>
ce.vue
<template> <div class="ce"> 跳轉(zhuǎn)頁(yè)面name-》{{this.$appName}} </div> </template>
在app.vue中點(diǎn)擊更改name,$appName值已發(fā)生改變,但cs.vue頁(yè)面的值沒(méi)有發(fā)生變化
如果要實(shí)現(xiàn)全局變量的功能,需要把屬性變?yōu)橐妙愋?/p>
Vue.prototype.$appName = { name: 'main' }
使用 this.$appName.name 改變和引用相應(yīng)的值
app.vue
<template> <div id="app"> 主組件name-》{{this.$appName.name}} <p>{{newName}}</p> <button @click="changeName">更改name</button> <button @click="$router.push('/cs')">跳轉(zhuǎn)</button> <hr> <router-view></router-view> </div> </template>
<script> export default { data(){ return{ newName:'' } }, methods:{ changeName(){ this.$appName.name = "changeName" this.newName=this.$appName.name } } } </script>
cs.vue
<template> <div class="ce"> 跳轉(zhuǎn)頁(yè)面name-》{{this.$appName.name}} </div> </template>
在app.vue中點(diǎn)擊更改name,$appName值已發(fā)生改變,cs.vue頁(yè)面的值也發(fā)生了變化
4. 原型方法的上下文
在 JavaScript 中一個(gè)原型的方法會(huì)獲得該實(shí)例的上下文,也就是說(shuō)可以使用 this 訪問(wèn):數(shù)據(jù)、計(jì)算屬性、方法或其它任何定義在實(shí)例上的東西。
讓我們將其用在一個(gè)名為 $reverseText 的方法上:
// main.js Vue.prototype.$reverseText = function (propertyName) { this[propertyName] = this[propertyName] .split('') .reverse() .join('') }
<script> export default { data() { return{ message: 'Hello' } }, created() { console.log(this.message) // => "Hello" this.$reverseText('message') console.log(this.message) // => "olleH" } } </script>
5. 應(yīng)用示例
引入bus
const bus = new Vue() Vue.prototype.$bus = bus
this.$bus.$emit("fun",'A組件傳來(lái)的值')
axios…
6.Vue.prototype中的api
Vue.prototype是Vue.js框架中一個(gè)重要的原型對(duì)象,通過(guò)它可以在全局范圍內(nèi)定義和共享Vue實(shí)例方法、指令、過(guò)濾器等。
在Vue.prototype對(duì)象上定義的屬性和方法,會(huì)被掛載到所有Vue實(shí)例的原型鏈上,從而可以在組件中通過(guò)this訪問(wèn)。
一些常見(jiàn)的Vue.prototype中的API包括:
$emit(eventName[, ...args])
:觸發(fā)當(dāng)前實(shí)例上的事件??梢酝ㄟ^(guò)該方法向父組件或同級(jí)組件傳遞數(shù)據(jù)。$on(eventName, callback)
:監(jiān)聽(tīng)當(dāng)前實(shí)例上的事件??梢酝ㄟ^(guò)該方法在組件間傳遞數(shù)據(jù)。$nextTick(callback)
:在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)。常用于更新后立即操作 DOM。$watch(exprOrFn, callback[, options])
:監(jiān)聽(tīng)一個(gè)表達(dá)式或計(jì)算屬性的變化,并在回調(diào)函數(shù)中處理變化。$set(target, key, value)
:在一個(gè)已有的響應(yīng)式對(duì)象上添加一個(gè)屬性,并確保這個(gè)新屬性同樣是響應(yīng)式的,可以通過(guò)該方法解決對(duì)象添加新屬性時(shí)無(wú)法響應(yīng)式更新的問(wèn)題。$delete(target, key)
:刪除一個(gè)對(duì)象的屬性,可以通過(guò)該方法解決對(duì)象刪除屬性時(shí)無(wú)法響應(yīng)式更新的問(wèn)題。$refs
:一個(gè)對(duì)象,持有所有注冊(cè)過(guò) ref 的子組件。$el
:當(dāng)前組件的根 DOM 元素。$options
:當(dāng)前實(shí)例的初始化選項(xiàng)對(duì)象,包括組件的各種選項(xiàng)。
我們可以解析某個(gè)api源碼
7.$nextTick源碼
$nextTick是Vue.js框架中一個(gè)常用的異步更新方法,用于在下一次DOM更新循環(huán)結(jié)束后執(zhí)行回調(diào)函數(shù)。
其源碼如下:
Vue.prototype.$nextTick = function(fn) { return nextTick(fn, this) } // _nextTickId存儲(chǔ)下一個(gè)tick的id號(hào) let _nextTickId = 0 // _callbacks存儲(chǔ)回調(diào)函數(shù) let _callbacks = [] // _pending存儲(chǔ)是否正在執(zhí)行 let _pending = false // nextTick函數(shù) function nextTick(fn, ctx) { let id, callback callback = () => { // 如果傳入了fn,則執(zhí)行回調(diào)函數(shù) if (fn) { try { fn.call(ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } else if (callback) { callback.id = null // 如果沒(méi)有傳入fn,但存在回調(diào)函數(shù),則從_callbacks中移除該回調(diào)函數(shù) let index = _callbacks.indexOf(callback) if (index > -1) { _callbacks.splice(index, 1) } } } // 每次nextTick都會(huì)將該回調(diào)函數(shù)推入_callbacks中,等待執(zhí)行 _callbacks.push(callback) if (!_pending) { _pending = true // 使用微任務(wù)將回調(diào)函數(shù)異步執(zhí)行 if (typeof Promise !== 'undefined') { id = Promise.resolve().then(flushCallbacks) } else if (typeof MutationObserver !== 'undefined') { let observer = new MutationObserver(flushCallbacks) let textNode = document.createTextNode(String(_nextTickId)) observer.observe(textNode, { characterData: true }) id = () => { textNode.data = String(++_nextTickId) } } else if (typeof setImmediate !== 'undefined') { id = setImmediate(flushCallbacks) } else { id = setTimeout(flushCallbacks, 0) } } // 返回id,方便使用者手動(dòng)取消nextTick if (!fn && typeof Promise !== 'undefined') { return id } } // flushCallbacks函數(shù),用于執(zhí)行_callbacks中的所有回調(diào)函數(shù) function flushCallbacks() { _pending = false const copies = _callbacks.slice(0) _callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } }
$nextTick方法首先將回調(diào)函數(shù)推入_callbacks數(shù)組中,并使用一個(gè)_pending變量記錄是否有回調(diào)函數(shù)正在執(zhí)行。
如果_pending為false,則說(shuō)明當(dāng)前沒(méi)有回調(diào)函數(shù)正在執(zhí)行,需要異步執(zhí)行flushCallbacks函數(shù),從而依次執(zhí)行_callbacks數(shù)組中的所有回調(diào)函數(shù)。
在異步執(zhí)行時(shí),$nextTick方法會(huì)優(yōu)先使用Promise的微任務(wù)方式執(zhí)行回調(diào)函數(shù),如果瀏覽器不支持Promise,則會(huì)嘗試使用MutationObserver、setImmediate和setTimeout等方式執(zhí)行。
當(dāng)傳入的回調(diào)函數(shù)為空時(shí),$nextTick方法會(huì)返回一個(gè)id,方便使用者手動(dòng)取消nextTick。
需要注意的是,$nextTick方法只會(huì)在組件實(shí)例的更新周期內(nèi)生效,如果需要在Vue.js框架初始化后立即執(zhí)行回調(diào)函數(shù),可以使用Vue.nextTick()全局方法。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue3切換路由時(shí)頁(yè)面空白問(wèn)題解決辦法
在使用Vue3時(shí),有時(shí)頁(yè)面修改后會(huì)出現(xiàn)空白,這篇文章主要介紹了vue3切換路由時(shí)頁(yè)面空白問(wèn)題解決辦法,文中介紹的步驟可以有效解決頁(yè)面空白問(wèn)題,需要的朋友可以參考下2024-09-09vue3自定義指令自動(dòng)獲取節(jié)點(diǎn)的width和height代碼示例
這篇文章主要介紹了如何使用ResizeObserver監(jiān)聽(tīng)組件的寬度和高度,并將其封裝成一個(gè)指令以便全局或局部使用,ResizeObserver可以監(jiān)聽(tīng)元素的多個(gè)尺寸屬性,如top、bottom、left等,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-11-11