zoukankan      html  css  js  c++  java
  • TypeScript开发Vue

    用TypeScript开发Vue——如何通过vue实例化对象访问实际ViewModel对象

    背景

    我个人很喜欢TypeScript也很喜欢Vue,但在两者共同使用的时候遇到一些问题。
    Vue的实例化对象代理了所有实际ViewModel对象,具体可参见官方文档
    http://vuejs.org.cn/guide/instance.html#属性与方法

    Vue的属性与方法:
    每个 Vue 实例都会代理其 data 对象里所有的属性

    实际上vue实例不仅仅是代理了data属性,还代理了methods属性、computed属性等,可以通过这篇文档 看到。那么怎么在TypeScript里面通过vue实例访问data属性和methods属性里面的变量是最大问题,否则就没办法使用TS的最大的作用——强类型检查。

    如下图可以看到:

    虽然实际上vm.xxcanghaiFn是可用的,但是过不了TypeScript的编辑检查,提示不在'xxcanghaiFn'不在'Vue'类型中。
    因为类型'Vue'中肯定只有内部方法,自然会报错,虽然我们可以通过<any>语法强制使语法检查失效,如下代码:

    var vm: any = new Vue({//vm变量增加any声明
        el: "#app",
        data: {
            xxcanghaiData: "xxcanghai"
        },
        methods: {
            xxcanghaiFn: function () { }
        }
    });
    
    
    vm.xxcanghaiFn//无编译器报错
    

    虽然没有编译器报错,但同时也无法再使用TS提供的智能补全,强类型检查等功能。这就跟直接写js没有任何区别了。

    解决方案

    1. 将data属性,以及methods等需要合并进vue类型的对象分开写
    2. 利用TypeScript的typeofdeclare关键字将类型合并声明。
    3. 最后new Vue时强制用<any>声明并赋值。

    如下代码:

    //核心声明,利用typeof将data和methods属性合并进Vue类型
    declare var VM: typeof vmData & typeof vmMethods & vuejs.Vue;
    var vmData = {
        xxcanghaiData: "xxcanghai"
    };
    var vmMethods = {
        xxcanghaiFn: () => { }
    }
    var vm: typeof VM = <any>new Vue({
        el: "#app",
        data: vmData,
        methods: <any>vmMethods
    });
    

    效果如下,既可以实现识别Vue内置函数及属性:

    也能实现识别我们自定义的data属性和methods属性中的值:

    关于Vue中的计算属性类型

    Vue中有一种特殊的ViewModel的属性——计算属性
    计算属性在使用ts的强类型的时候就会出错,代码如下:

    declare var VM: vuejs.Vue & typeof vmComputed;
    var vmComputed = {
        /**
         * 字符串计算属性
         */
        xxcanghaiCom: function () {
            return "xxcanghaiCom";
        }
    }
    var vm: typeof VM = <any>new Vue({
        el: "#app",
        computed: <any>vmComputed
    });
    

    计算属会被ts的类型系统识别为一个函数,而出现函数相关的方法,此时调用字符串方法自然会报错。如图:

    虽然计算属性实际上确实是一个函数,但是我们希望能够把计算属性拿来当一个字符串变量来使用。

    TypeScript的强制类型声明语法

    这里可以使用ts的强制类型声明语法 <TYPE>,来把指定类型强制声明为其他类型,如下:

    var a;
    (<string>a).charAt(0);//合法
    (<number>a).toFixed();//合法
    

    强制类型声明的局限性

    但是此语法也有局限性,即只能强制声明那些未知类型的变量,不能强制声明已知类型的变量,如下:

    var a = 0;
    (<string>a);//报错 Neither type 'number' nor type 'string' is assignable to the other.
    

    因为变量a已经可以被类型推断出为number类型了,遂不能再强制声明为string类型。

    计算属性类型的解决方案

    解决方案为 利用any类型中转来实现强制类型声明转换。
    在TypeScript中的any类型的规则为:

    1、任何类型都可以被转换为any类型。
    2、any 类型可以转换为任何类型。

    所以先将计算属性的函数,或是getter,setter的Object声明为any类型,再声明为你想实际使用的变量类型。如下:

    declare var VM: vuejs.Vue & typeof vmComputed;
    var vmComputed = {
        /**
         * 字符串计算属性
         */
        xxcanghaiCom: <string>(<any>function () {
            return "xxcanghaiCom";
        }),
        /**
         * getter和setter形式的字符串计算属性
         */
        xxcanghaiGetSet: <string>(<any>{
            get: function () {
                return vm.xxcanghaiCom;
            },
            set: function (newVal: string) {
                vm.xxcanghaiCom = newVal;
            }
        })
    }
    var vm: typeof VM = <any>new Vue({
        el: "#app",
        computed: <any>vmComputed
    });
    

    效果如下图,虽然xxcanghaiGetSet是object,但此处可以按照我们想要的string类型来使用。

    后记

    本文比较初级,因为刚刚开始接触Vue,因为之前用过Angular和Avalon,所以上手起来还算舒服,之前用Angular的时候就因为用TypeScript写非常难受,遂打算好好研究下TypeScript与Vue的协同工作的问题。
    写的比较匆忙,vue也还没有完全了解,遂文中有不对的地方欢迎指正。:-)

     

    如果您认为本文对得起您所阅读他所花的时间,欢迎点击右下角推荐。您的支持是我继续写作最大的动力,谢谢

    作者:小小沧海 

  • 相关阅读:
    一款新型的智能家居WiFi选择方案——SimpleWiFi在无线智能家居中的应用
    智能手机的工业控制应用方案——SimpleWiFi在工业控制领域应用
    一种单片机支持WiFi的应用——SimpleWiFi在单片机中的应用
    TI推出SimpleLink低能耗蓝牙CC2541
    SimpleWiFi模块评估板
    Android架构设计和软硬整合完整训练
    CentOS上解压ZIP乱码的解决办法
    更具体的描述JNI
    数据市中心全省中国mysql脚本
    几种方法枚举子集
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/5763228.html
Copyright © 2011-2022 走看看