• 在 Vue 中使用 Typescript


    前言

      恕我直言,用 Typescript 写 Vue 真的很难受,Vue 对 ts 的支持一般,如非万不得已还是别在 Vue 里边用吧,不过听说 Vue3 会增强对 ts 的支持,正式登场之前还是期待一下吧嘻嘻。

      本篇不会过多讲述 ts 语法,着重记录下 在 Vue 中使用 ts 的方法以及踩坑经过。

      如果是使用 Vue Cli2 搭建的项目,要注意 webpack 版本可能与 ts-loader 版本不匹配,可以降低 ts-loader 版本到 3.0+ 或者 将 webpack升级到 4.0+ (本篇所用版本 webpack@3.6.0 + ts-loader@3.5.0)

    主要步骤

      1. 先要让 vue 项目可以识别 .ts 文件。安装关键依赖 npm i typescript ts-loader -D

      2. 在 webpack.base.config.js 中添加 ts-loader

    //resolve.extensions 里面加上.ts 后缀 之后引入.ts的时候可以不写后缀
    {
      test: /.tsx?$/,
      loader: 'ts-loader',
      exclude: /node_modules/,
      options: { 
        appendTsSuffixTo: [/.vue$/], //关键
      }
    }

      3. 在根目录建tsconfig.json文件 下面的配置仅供参考

    {
      "include": [
        "src/**/*"
      ],
      "exclude": [
        "node_modules"
      ],
      "compilerOptions": {
        "allowSyntheticDefaultImports": true,
        "experimentalDecorators": true,
        "allowJs": true,
        "module": "esnext",
        "target": "es5",
        "moduleResolution": "node",
        "isolatedModules": true,
        "lib": [
          "dom",
          "es5",
          "es2015.promise"
        ],
        "sourceMap": true,
        "pretty": true
      }
    }

      4. 接着需要确保在 vue 中可以正常使用 ts 。安装 vue-class-component(为vue组件提供修饰器) vue-property-decorator(更多的结合vue特性的修饰器) [ tslint tslint-loader tslint-config-standard(可选 约束.ts/.tsx代码格式)],这样就可以在 vue 文件中使用诸如 @Component、@Prop等装饰器了。注意:.vue 文件中的 script 标签要加上 lang="ts"。关于 装饰器的使用可以参看下这位大哥的文章:https://segmentfault.com/a/1190000019906321

    <template>
        <div class="count-down" v-html="countDown(endDate)">
        </div>
    </template>
    
    <script lang="ts">
    import { Component, Prop, Vue, Emit } from "vue-property-decorator"
    import moment from 'moment'
    
    @Component
    export default class CountDown extends Vue {
        @Prop() endDate!: string
        // 变量后加!是非空断言
    
        now: any = moment()
        mounted() {
            setInterval((): void =>{
                this.now = moment()
            },1000)
        }
        destroyed() {
            
        }
        get countDown(): object{
            return function(endDate: any): string {
                let m1: any = this.now
                let m2: any = moment(endDate)
                let du: any = moment.duration(m2 - m1, 'ms')
                let hours: number = du.get('hours')
                let mins: number = du.get('minutes')
                let ss: number = du.get('seconds')
                if(hours <= 0 && mins <= 0 && ss <= 0) {
                    // this.$emit('timeout')
                    this.timeout()
                    return "今日已结束"
                }else {
                    return `${this.PrefixInteger(hours,2)} <span style="font-size: 16px;">小时</span> ${this.PrefixInteger(mins,2)} <span style="font-size: 16px;">分钟</span><span style="color: #F56C6C;"> ${this.PrefixInteger(ss,2)} </span><span style="font-size: 16px;">秒</span>`
                }
            }
        }
    
        @Emit()
        timeout(){}
    
        
        //数字前补 0 
        // num传入的数字,n需要的字符长度
        PrefixInteger(num: number, n: number): string {
            return (Array(n).join('0') + num).slice(-n)
        }
    }
    </script>
    
    <style lang="less" scoped>
    //...
    </style>

      5. 将main.js 变成 main.ts 并且在 webpack.base.conf.js 修改入口为main.ts,这一步至关重要。

      6. 在 src 目录下新建文件 shims-vue.d.ts ,告诉 TypeScript *.vue 后缀的文件可以交给 vue 模块来处理,注意 在代码中导入 *.vue 文件的时候,需要写上 .vue 后缀,这里可以参考官网说明:增强类型以配合插件使用

    declare module "*.vue" {
        import Vue from "vue";
        export default Vue;
    }

    踩坑记录

      1. 报错如下,报错原因一是没有将入口文件改成 ts,二是 webpack.base.conf.js 中引入 ts-loader 错误,没有加上 options: { appendTsSuffixTo: [/.vue$/], }

    Module build failed: Error: Could not find source file: 'XXX/src/App.vue'.

      2. 全局属性报错 如 Vue.prototype.$msg = XXX,需要将全局属性在 .d.ts 文件中声明

    import Vue from "vue";
    import { AxiosInstance } from "axios";
    import { ElMessage } from "element-ui/types/message";
    
    declare module "*.vue" {
        export default Vue;
    }
    
    declare module 'vue/types/vue' {
        interface Vue {
            $http: AxiosInstance,
            $message: ElMessage
        }
    }

      3. 使用上面这种声明全局属性的方式又会带来新的问题,报错 import App from './App.vue'处,找不到 App.vue 这个模块,虽然不影响编译,但是这红色的波浪线就像老鼠屎,看着那叫一个难受呀。解决方法:将 shims-vue.d.ts 文件一分为二,将全局属性声明和 Vue 的声明分离;在 shims-vue.d.ts 文件同级目录下新建 vue.d.ts(名字不一定叫 vue,如 xxx.d.ts 也可以);关键是要将以下代码放在单独的 .d.ts 文件中

    declare module '*.vue' {
      import Vue from 'vue'
      export default Vue
    }
  • 相关阅读:
    常用正则表达式
    C语言的指针与二维数组
    【原创】datalist实现简单分页功能
    【原创】datalist的页脚访问和控制
    [原创]手动删除顽固病毒总结
    [zz]复杂指针解析
    极度郁闷的一次电脑维修经历
    武汉城市地铁规划图
    [转]objc_msgSend 的 ARM 汇编分析
    [转]Cydia and XCode Local App Testing
  • 原文地址:https://www.cnblogs.com/dongshenjun/p/13494322.html
Copyright © 2020-2023  润新知