我们可能会在很多组件里用到数据/实用工具,但是不想污染全局作用域。
这种情况下,可以通过在原型上定义它们使其在每个 vue 的实例中可用。
1. 基本示例
在main.js中添加一个变量到 vue.prototype
vue.prototype.$appname = 'my app'
这样 $appname 就在所有的 vue 实例中可用了,甚至在实例被创建之前就可以
beforecreate: function () {
console.log(this.$appname)
}
控制台会打印出 my app
2. 为实例prototype设置作用域
为什么 appname 要以 $ 开头?
$ 是在 vue 所有实例中都可用的 property 的一个简单约定。
这样做会避免和已被定义的数据、方法、计算属性产生冲突。
如果我们设置:
vue.prototype.appname = 'my app'
export default {
data(){
return{
appname:'组件实例中的appname'
}
},
beforecreate: function () {
console.log(this.appname)
},
created: function () {
console.log(this.appname)
},
}
</script>
日志中会先出现 “my app”,然后出现 “组件实例中的appname”,因为 this.appname 在实例被创建之后被 data 覆写了。
我们通过 $ 为实例 property 设置作用域来避免这种事情发生。
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')">跳转</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">
跳转页面name-》{{this.$appname}}
</div>
</template>
在app.vue中点击更改name,$appname值已发生改变,但cs.vue页面的值没有发生变化

如果要实现全局变量的功能,需要把属性变为引用类型
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')">跳转</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">
跳转页面name-》{{this.$appname.name}}
</div>
</template>

在app.vue中点击更改name,$appname值已发生改变,cs.vue页面的值也发生了变化
4. 原型方法的上下文
在 javascript 中一个原型的方法会获得该实例的上下文,也就是说可以使用 this 访问:数据、计算属性、方法或其它任何定义在实例上的东西。
让我们将其用在一个名为 $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框架中一个重要的原型对象,通过它可以在全局范围内定义和共享vue实例方法、指令、过滤器等。
在vue.prototype对象上定义的属性和方法,会被挂载到所有vue实例的原型链上,从而可以在组件中通过this访问。
一些常见的vue.prototype中的api包括:
$emit(eventname[, ...args]):触发当前实例上的事件。可以通过该方法向父组件或同级组件传递数据。$on(eventname, callback):监听当前实例上的事件。可以通过该方法在组件间传递数据。$nexttick(callback):在下次 dom 更新循环结束之后执行延迟回调。常用于更新后立即操作 dom。$watch(exprorfn, callback[, options]):监听一个表达式或计算属性的变化,并在回调函数中处理变化。$set(target, key, value):在一个已有的响应式对象上添加一个属性,并确保这个新属性同样是响应式的,可以通过该方法解决对象添加新属性时无法响应式更新的问题。$delete(target, key):删除一个对象的属性,可以通过该方法解决对象删除属性时无法响应式更新的问题。$refs:一个对象,持有所有注册过 ref 的子组件。$el:当前组件的根 dom 元素。$options:当前实例的初始化选项对象,包括组件的各种选项。
我们可以解析某个api源码
7.$nexttick源码
$nexttick是vue.js框架中一个常用的异步更新方法,用于在下一次dom更新循环结束后执行回调函数。
其源码如下:
vue.prototype.$nexttick = function(fn) {
return nexttick(fn, this)
}
// _nexttickid存储下一个tick的id号
let _nexttickid = 0
// _callbacks存储回调函数
let _callbacks = []
// _pending存储是否正在执行
let _pending = false
// nexttick函数
function nexttick(fn, ctx) {
let id, callback
callback = () => {
// 如果传入了fn,则执行回调函数
if (fn) {
try {
fn.call(ctx)
} catch (e) {
handleerror(e, ctx, 'nexttick')
}
} else if (callback) {
callback.id = null
// 如果没有传入fn,但存在回调函数,则从_callbacks中移除该回调函数
let index = _callbacks.indexof(callback)
if (index > -1) {
_callbacks.splice(index, 1)
}
}
}
// 每次nexttick都会将该回调函数推入_callbacks中,等待执行
_callbacks.push(callback)
if (!_pending) {
_pending = true
// 使用微任务将回调函数异步执行
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函数,用于执行_callbacks中的所有回调函数
function flushcallbacks() {
_pending = false
const copies = _callbacks.slice(0)
_callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
$nexttick方法首先将回调函数推入_callbacks数组中,并使用一个_pending变量记录是否有回调函数正在执行。
如果_pending为false,则说明当前没有回调函数正在执行,需要异步执行flushcallbacks函数,从而依次执行_callbacks数组中的所有回调函数。
在异步执行时,$nexttick方法会优先使用promise的微任务方式执行回调函数,如果浏览器不支持promise,则会尝试使用mutationobserver、setimmediate和settimeout等方式执行。
当传入的回调函数为空时,$nexttick方法会返回一个id,方便使用者手动取消nexttick。
需要注意的是,$nexttick方法只会在组件实例的更新周期内生效,如果需要在vue.js框架初始化后立即执行回调函数,可以使用vue.nexttick()全局方法。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论