• vue + typescript 进阶篇


    vue + typescript 进阶篇

    本文是继 Vue + TypeScript 新项目起手式 之后的进阶+踩坑配置,所以推荐先行阅读前文

    完整阅读完之后,基本可以顺利在新项目中使用vue + typescript 了

    另外特别注意!!!

    不推荐在已有项目上强加 typescript, 因ts写法的组件跟之前的组件不兼容,若上的话需要修改之前写的组件

    配置完整版可参考 vue-typescript-starter,若没配置出来,也可以对照修改配置

    直接进入正题:

    概览

    • ts 支持 render jsx 写法

    • ts 支持 es6 / es67

    • 配置 vuex

    • vue 识别全局方法/变量

    • 支持 mixin

    • 支持 ProvidePlugin 的全局变量,比如 lodash_

    支持 render jsx 写法

    这里一共分两步

    1. 首先得先让 vue 支持 jsx 写法

    2. 再让 vue 中的 ts 支持 jsx 写法

    让 vue 支持 jsx

    按照官方做法,安装Babel 插件

    图片描述

    安装依赖

    npm install
      babel-plugin-syntax-jsx
      babel-plugin-transform-vue-jsx
      babel-helper-vue-jsx-merge-props
      babel-preset-es2015
      --save-dev

    .babelrc中添加:

    {
      "plugins": ["transform-vue-jsx"]
    }

    之后就可以这些写render,如下图:

    图片描述

    让 ts 支持 jsx

    首先配置 webpack
    找到./build/webpack.base.conf.js

    • 找到resolve.extensions 里面加上.tsx 后缀

     resolve: {
        extensions: ['.js', '.vue', '.json', '.ts', '.tsx']
      }
    • 找到module.rules 修改webpack对.tsx .ts 的解析

      module: {
        rules: [
          {
            test: /.(js|vue)$/,
            loader: 'eslint-loader',
            enforce: 'pre',
            include: [resolve('src'), resolve('test')],
            options: {
              formatter: require('eslint-friendly-formatter')
            }
          },
            // 从这里复制下面的代码就可以了
            // 如果之前按照起手式配置的同学,请替换配置
          {
            test: /.tsx?$/,
            exclude: /node_modules/,
            enforce: 'pre',
            loader: 'tslint-loader'
          },
          {
            test: /.vue$/,
            loader: 'vue-loader',
            options: Object.assign(vueLoaderConfig, {
              loaders: {
                ts: "ts-loader",
                tsx: "babel-loader!ts-loader"
              }
            })
          },
          {
            test: /.tsx?$/,
            exclude: /node_modules/,
            use: [
              "babel-loader",
              {
                loader: "ts-loader",
                options: { appendTsxSuffixTo: [/.vue$/] }
              }
            ]
          },
          // 复制截止
          {
            test: /.js$/,
            loader: 'babel-loader',
            include: [resolve('src'), resolve('test')]
          },

    上面的配置,主要意思是 vue 文件识别ts/tsx代码的时候,先过一遍ts-loader,在过一遍babel-loader,我知道这听起来有点蠢,但是jsx不能不要对吧?

    然后在 tsconfig.json中,添加对jsx的支持

    "compilerOptions": {
        "jsx": "preserve"
        }

    之后就可以顺利在.vue单文件中的tsjsx代码了,如下图所示:

    图片描述

    敲黑板,这里又有重点,使用 jsx 写法的话, 一定要使用 .tsx,不要用.ts了,切记!!!

    支持es6 / es7

    在 tsconfig.json中,添加对es6 / es7的支持,更多的配置请见tsconfig - 编译选项

        "lib": [
          "dom",
          "es5",
          "es6",
          "es7",
          "es2015.promise"
        ]

    图片描述

    不然的话,连Object.assign 这种最基本的函数也会在ts中报错,真的令人难过

    配置 vuex

    这里就比较简单了

    # 安装依赖
    npm i vuex vuex-class --save
    • vuex:在 vue 中集中管理应用状态

    • vuex-class :在 vue-class-component 写法中 绑定 vuex

    Store的配置跟原来一模一样,引用的时候有一点区别,下面的例子介绍了用法,应该一看便知,这里我不做赘述

    import Vue from 'vue'
    import Component from 'vue-class-component'
    import {
      State,
      Getter,
      Action,
      Mutation,
      namespace
    } from 'vuex-class'
    
    const ModuleGetter = namespace('path/to/module', Getter)
    
    @Component
    export class MyComp extends Vue {
      @State('foo') stateFoo
      @State(state => state.bar) stateBar
      @Getter('foo') getterFoo
      @Action('foo') actionFoo
      @Mutation('foo') mutationFoo
      @ModuleGetter('foo') moduleGetterFoo
    
      // If the argument is omitted, use the property name
      // for each state/getter/action/mutation type
      @State foo
      @Getter bar
      @Action baz
      @Mutation qux
    
      created () {
        this.stateFoo // -> store.state.foo
        this.stateBar // -> store.state.bar
        this.getterFoo // -> store.getters.foo
        this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true })
        this.mutationFoo({ value: true }) // -> store.commit('foo', { value: true })
        this.moduleGetterFoo // -> store.getters['path/to/module/foo']
      }
    }

    让 vue 识别全局方法/变量

    在项目中使用 ui 组件是很正常的操作

    比如使用 Element-uI 的 meesage,用法如下图:

      this.$message({
        message: '恭喜你,这是一条成功消息',
        type: 'success'
      })

    但是在配置了 typescript之后

    图片描述

    那是因为 $message属性,并没有在 vue实例中声明

    解决办法也非常简单,那我们就声明一下呗

    在之前文章中创建的 src/vue-shim.d.ts文件中,增加如下代码:

    // 声明全局方法
    declare module 'vue/types/vue' {
      interface Vue {
        $Message: any,
        $Modal: any
      }
    }

    这样,之后再使用this.$message()的话就不会报错了

    支持 mixin

    我在vue-property-decorator里里外外找了好几圈,缺没有找到mixin这个修饰器

     // 如果全局mixin,那也太蠢了
     Vue.mixin( mixin )

    找非常多的 ts + vue 项目,但是没有找到我理想的mixin的方式,
    那么就自己进行探索咯,下图是我自己使用的目前最佳mixin方式:

    声明了一个mixin组件,如下图:

    图片描述

    其实就是我在mixin中声明了声明属性 / 方法,那么我就在vue实例中声明这个属性 / 方法

    使用方式如下图:

    图片描述

    支持 ProvidePlugin 的全局变量,比如 lodash 的 _

    如果我们在项目中有使用 jquery,lodash 这样的工具库的时候,肯定不希望在所有用到的地方都import _ from ‘lodash’
    @types/lodash

    那我们就来配置一下:

    首先还是在webpack.base.conf.js 中添加一个插件、并把这个 vendor拉出来

     entry: {
        app: './src/main.ts',
        vendor: [
          "lodash"
        ]
      }
    
      plugins: [
        new webpack.ProvidePlugin({
          _: 'lodash'
        })
      ]

    上面的意思是,当模块使用这些变量的时候wepback会自动加载

    然后,你需要告诉eslint这个 _ 是全局的

    .eslintrc.js中添加

     globals: {
        _: true
      },

    接下来,你还需要告诉ts这个 _ 是全局的

    vue-shim.d.ts

    declare global {
      const _: typeof lodash
    }

    如果没有上面这段声明,但是在 ts 中使用的话,会报如下的错误:

    图片描述

    这个问题Consider allowing access to UMD globals from modules · Issue #10178 · Microsoft/TypeScript · GitHub

    有一个很简单的解释,就是害怕你全局声明的_ 跟 import _ from 'lodash' 的行为不一致,这样的话,之后会留下隐患

    到这里,本文的配置就到此结束

    最后

    本文的这些配置都是在新项目开发中,一步步用血汗踩出来的

    目测已经涵盖了大部分的使用问题,如果有其他的意见或建议的话,欢迎在本文下面评论~~

    再发一次,配置完整版可参考 vue-typescript-starter,若没配置出来,也可以对照修改配置

    在刚上typescript的时候,我是拒绝的,嫌弃每个地方都要声明类型,不然就走不下去,但是如果让你们做以下一个选择题:

    • 在编译时发现问题

    • 还是运行时发现问题

    我会毫不犹豫选择前者,这是ts强类型带给我最大的亮点

    参考链接/推荐阅读

  • 相关阅读:
    硬件04:反馈与触发器
    硬件03:二进制减法器
    硬件02:二进制加法器
    ASP.NET MVC 表单提交多层子级实体集合数据到控制器中
    微信全局获取并缓存Accesstoken的值
    MySQL 中文显示乱码
    HTML5 Canvas绘图详解 drawImage() 方法 有图有真相!
    [原创]超强C#图片上传,加水印,自动生成缩略图源代码
    微信公共服务平台开发(.Net 的实现)5-------解决access_token过期的问题 .
    2015-10-19深圳面试
  • 原文地址:https://www.cnblogs.com/ygunoil/p/12133526.html
Copyright © 2020-2023  润新知