Vue.prototype詳解及使用方式
我們可能會在很多組件里用到數(shù)據(jù)/實用工具,但是不想污染全局作用域。
這種情況下,可以通過在原型上定義它們使其在每個 Vue 的實例中可用。
1. 基本示例
在main.js中添加一個變量到 Vue.prototype
Vue.prototype.$appName = 'My App'
這樣 $appName 就在所有的 Vue 實例中可用了,甚至在實例被創(chuàng)建之前就可以
beforeCreate: function () {
console.log(this.$appName)
}
控制臺會打印出 My App
2. 為實例prototype設置作用域
為什么 appName 要以 $ 開頭?
$ 是在 Vue 所有實例中都可用的 property 的一個簡單約定。
這樣做會避免和已被定義的數(shù)據(jù)、方法、計算屬性產(chǎn)生沖突。
如果我們設置:
Vue.prototype.appName = 'My App'
export default {
data(){
return{
appName:'組件實例中的appName'
}
},
beforeCreate: function () {
console.log(this.appName)
},
created: function () {
console.log(this.appName)
},
}
</script>
日志中會先出現(xiàn) “My App”,然后出現(xiàn) “組件實例中的appName”,因為 this.appName 在實例被創(chuàng)建之后被 data 覆寫了。
我們通過 $ 為實例 property 設置作用域來避免這種事情發(fā)生。
3. 注冊和使用全局變量
每個組件都是一個vue實例,Vue.prototype加一個變量,只是給每個組件加了一個屬性,這個屬性的值并不具有全局性。
比如以下例子:
Vue.prototype.$appName = 'main'
給所有組件注冊了一個屬性 $appName,賦予初始值 'main' ,所有組件都可以用 this.$appName 訪問此變量;
如果組件中沒有賦值,初始值都是'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)頁面name-》{{this.$appName}}
</div>
</template>
在app.vue中點擊更改name,$appName值已發(fā)生改變,但cs.vue頁面的值沒有發(fā)生變化

如果要實現(xiàn)全局變量的功能,需要把屬性變?yōu)橐妙愋?/p>
Vue.prototype.$appName = { name: 'main' }使用 this.$appName.name 改變和引用相應的值
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)頁面name-》{{this.$appName.name}}
</div>
</template>

在app.vue中點擊更改name,$appName值已發(fā)生改變,cs.vue頁面的值也發(fā)生了變化
4. 原型方法的上下文
在 JavaScript 中一個原型的方法會獲得該實例的上下文,也就是說可以使用 this 訪問:數(shù)據(jù)、計算屬性、方法或其它任何定義在實例上的東西。
讓我們將其用在一個名為 $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. 應用示例
引入bus
const bus = new Vue() Vue.prototype.$bus = bus
this.$bus.$emit("fun",'A組件傳來的值')axios…
6.Vue.prototype中的api
Vue.prototype是Vue.js框架中一個重要的原型對象,通過它可以在全局范圍內(nèi)定義和共享Vue實例方法、指令、過濾器等。
在Vue.prototype對象上定義的屬性和方法,會被掛載到所有Vue實例的原型鏈上,從而可以在組件中通過this訪問。
一些常見的Vue.prototype中的API包括:
$emit(eventName[, ...args]):觸發(fā)當前實例上的事件??梢酝ㄟ^該方法向父組件或同級組件傳遞數(shù)據(jù)。$on(eventName, callback):監(jiān)聽當前實例上的事件??梢酝ㄟ^該方法在組件間傳遞數(shù)據(jù)。$nextTick(callback):在下次 DOM 更新循環(huán)結束之后執(zhí)行延遲回調(diào)。常用于更新后立即操作 DOM。$watch(exprOrFn, callback[, options]):監(jiān)聽一個表達式或計算屬性的變化,并在回調(diào)函數(shù)中處理變化。$set(target, key, value):在一個已有的響應式對象上添加一個屬性,并確保這個新屬性同樣是響應式的,可以通過該方法解決對象添加新屬性時無法響應式更新的問題。$delete(target, key):刪除一個對象的屬性,可以通過該方法解決對象刪除屬性時無法響應式更新的問題。$refs:一個對象,持有所有注冊過 ref 的子組件。$el:當前組件的根 DOM 元素。$options:當前實例的初始化選項對象,包括組件的各種選項。
我們可以解析某個api源碼
7.$nextTick源碼
$nextTick是Vue.js框架中一個常用的異步更新方法,用于在下一次DOM更新循環(huán)結束后執(zhí)行回調(diào)函數(shù)。
其源碼如下:
Vue.prototype.$nextTick = function(fn) {
return nextTick(fn, this)
}
// _nextTickId存儲下一個tick的id號
let _nextTickId = 0
// _callbacks存儲回調(diào)函數(shù)
let _callbacks = []
// _pending存儲是否正在執(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
// 如果沒有傳入fn,但存在回調(diào)函數(shù),則從_callbacks中移除該回調(diào)函數(shù)
let index = _callbacks.indexOf(callback)
if (index > -1) {
_callbacks.splice(index, 1)
}
}
}
// 每次nextTick都會將該回調(diào)函數(shù)推入_callbacks中,等待執(zhí)行
_callbacks.push(callback)
if (!_pending) {
_pending = true
// 使用微任務將回調(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,方便使用者手動取消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ù)組中,并使用一個_pending變量記錄是否有回調(diào)函數(shù)正在執(zhí)行。
如果_pending為false,則說明當前沒有回調(diào)函數(shù)正在執(zhí)行,需要異步執(zhí)行flushCallbacks函數(shù),從而依次執(zhí)行_callbacks數(shù)組中的所有回調(diào)函數(shù)。
在異步執(zhí)行時,$nextTick方法會優(yōu)先使用Promise的微任務方式執(zhí)行回調(diào)函數(shù),如果瀏覽器不支持Promise,則會嘗試使用MutationObserver、setImmediate和setTimeout等方式執(zhí)行。
當傳入的回調(diào)函數(shù)為空時,$nextTick方法會返回一個id,方便使用者手動取消nextTick。
需要注意的是,$nextTick方法只會在組件實例的更新周期內(nèi)生效,如果需要在Vue.js框架初始化后立即執(zhí)行回調(diào)函數(shù),可以使用Vue.nextTick()全局方法。
總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
vue3自定義指令自動獲取節(jié)點的width和height代碼示例
這篇文章主要介紹了如何使用ResizeObserver監(jiān)聽組件的寬度和高度,并將其封裝成一個指令以便全局或局部使用,ResizeObserver可以監(jiān)聽元素的多個尺寸屬性,如top、bottom、left等,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-11-11

