vue脚手架 全局变量可以是变量吗,vue + typescript,定义全局变量或者方法

众所周知,在 vue中,如果想定义一个全局变量的方法很简单,直接在 vue的原型上挂载属性或者方法即可。

但是,加上了typescript之后, Vue.prototype.$xxx = xxx  这种挂载方式就不行了。无论在哪里都访问不了挂载的内容。Vue原型上也没有。那怎么办呢?

第一种方式(推荐):插件

官方文档在 TypeScript 支持 这一项中的  增强类型以配合插件使用表示了可以用插件的方式来定义全局变量,然后用 xxx.d.ts 这种文件来声明类型。

那就开始开发插件:官方开发插件说明

插件最重要的就是 install 方法。举个最简单的例子:

testInstall.ts

const protoInstall ={

install: (Vue:any,options:any)=>{

Vue.prototype.$install= function(){

console.log('install')

};

Vue.prototype.$testData= 'testData';

}

}

exportdefault protoInstall;

(1)不要说我Vue:any,options:any 这种写法,因为我不知道这两个的类型到底是什么ヾ(。 ̄□ ̄)ツ゜゜゜

main.ts

import hhInstall from './assets/js/testInstall';

Vue.use(hhInstall);

使用的时候:

f72cdfbe5d47581d4dbcebf91622a23b.png

结果:

c688e81d7b67da24fad4893a60f06e85.png

(1)可以看到,虽然报未找到该属性,或者该方法的错误,但是不影响结果。

(2)那怎么解决这个问题呢?这时就需要添加 声明文件了。

解决:

(1)在src 下新建一个 xxx.d.ts 文件  。我是在src下再新建一个type文件夹,然后再把刚才的声明文件放到 这文件夹中,方便管理。

(2)xxx 名称可以随便写,反正我写的 vue-prototype.d.ts  更清晰一点。

vue-prototype.d.ts

declare module "vue/types/vue"{

interface Vue {

$testData:string;

$install:Function;

}

}

保存后,如果未生效,再重新启动一下项目就行。然后就有类型提示了。以后如果还需要添加全局属性或者方法,在插件里面挂载之后,声明文件里面再添加类型说明。

11815745203592b6d4847baf7cb79569.png

不过我有不明白的地方:

(1) 官方文档说,确保在声明补充的类型之前导入 'vue'。我的声明文件 vue.prototype.d.ts 并未导入vue,但是没问题。为什么呢?难道是我用vue-cli3 脚手架搭建的项目,shims-vue.d.ts 这个文件已经导入就不用了吗?

(2) 这种 xxx.d.ts 文件,vue内部是怎么识别的?又是怎么处理的呢?

第二种方法:mixin混入

由于是想全局定义属性和方法,那么mixin也能实现。比如:

main.ts

const vueMixins ={

data(){return{

$testData:'mixin testData',

}

},

methods:{

$install:function(){

console.log('mixin install')

}

}

}

Vue.mixin(vueMixins)

使用:

afba07c3d36fd75557472c73aac9166b.png

结果:

86a3fc439248ffbc0164adecf67eb89b.png

可以看到,定义的属性 $testData 是undefined。而去看vue实例,发现挂载到 $data 里面的。但是为什么访问不了,而只有 通过  this.$data.$testData 来访问?这个我也不太清楚

a4a0ceff4808c2b142f0b13fa985a058.png

158558c558d8e8e1396796f79980fd25.png

相同的,出现属性不存在的问题,还是要添加 声明文件来说明一下。

用这种方式,如果定义一个构造函数在data里面,后面的方法都没提示。不太方便。

最后贴上我自己的全局事件总线代码,就是为了不想用的时候还要引入,才知道了 typescript 不能直接定义全局变量的问题ヾ(゚∀゚ゞ)。

如果不想全局引入,那就不搞成插件的方式就行了,直接export default class xxx。

代码比较垃圾,轻喷。

assets/js/eventBus.js

409741c71b82244e42a8dc34c45aa6f2.png

b8caf6a7f0ff94ebebc445bcc752de79.png

/**

* @desc 全局事件总栈

* @author 赵建军*/

/**

* 事件信息接口*/interface EventItem {

name:string;

fun:Function;

}/**

* 判断是否存在已经绑定的事件接口*/interface JudgeStatus{

status:boolean;

index:number

}

export class EventBusHandler{

private EventArr:EventItem[]=[];

private static _instance: EventBusHandler;

public static get instance(): EventBusHandler {if (!EventBusHandler._instance) {

EventBusHandler._instance= newEventBusHandler();

}returnEventBusHandler._instance;

}/**

* 判断是否已经存在注册的事件

* @param eventName 事件名*/private judgeHadEventAlready(eventName: string):JudgeStatus{

let status= false;

let pos= -1;this.EventArr.forEach((val,index) =>{if(val.name ===eventName){

status= true;

pos=index;

}

})return{

status:status,

index: pos

}

}/**

* 事件监听

* @param eventName 事件名

* @param func 回调函数*/public on(eventName: string, func: Function) {

const statusTarget= this.judgeHadEventAlready(eventName);//如果未监听过则添加进去

if (!statusTarget.status) {this.EventArr.push({

name:eventName,

fun:func

})

}

}/**

* 事件触发

* @param eventName 事件名

* @param arg 传入的参数。如果想传多个参数,可把 arg:any 换成 ...arg:any[]*/public emit(eventName: string, arg:any) {

const statusTarget= this.judgeHadEventAlready(eventName);if(statusTarget.status){

const func= this.EventArr[statusTarget.index].fun;this.EventArr[statusTarget.index].fun =func;

func(arg);

}else{

console.warn('暂未监听:'+eventName+ '事件');

}

}/**

* 事件移除

* @param eventName

* @param func*/public remove(eventName: string) {

const statusTarget= this.judgeHadEventAlready(eventName);if(statusTarget.status){this.EventArr.splice(statusTarget.index,1);

}else{

console.warn('未监听:'+eventName+ '事件');

}

}

}

const EventBusFunc={

install: (Vue:any,options:object)=>{

Vue.prototype.$eventBus=EventBusHandler.instance;

}

}

exportdefault EventBusFunc;

View Code

声明文件:

import {EventBusHandler} from '@/assets/js/eventBus';

declare module"vue/types/vue"{

interface Vue {

$eventBus:EventBusHandler;

}

}

main.ts 引入:

import EventBus from './assets/js/eventBus';

Vue.use(EventBus);

使用:

this.$eventBus.on('func',() =>{})this.$eventBus.emit('func','1111')this.$eventBus.remove('func')

果然还是实践出真知,网上的大部分答案都不靠谱 (⊙﹏⊙)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值