Vue-cli 3.5 结合TSX使用踩坑旅

// 期待Vue3.0版本对TS以及TSX的大力支持
其实挺想期待的,但是vue3目前为止核心重点还是捞住老用户,对ts的优化是一点一点的减少。。心累
// 后续再出对TS + Webpack + Vue3.0 的结合使用
后面有空想办法给vue3加层壳让其更能与ts良好的结合吧

最近项目重构,准备将所有固件升级,顺便引进TS来对项目的规范和代码提示的优化进行提升。之前写React项目的时候对JSX新式语法糖和TypeScript类型声明以及代码提示这块的喜爱还是比较高的,所以就想着在Vue项目中也能尝试以同样的方式进行开发,之前由于项目较老,很多坑陷入了死循环,所以干脆重新搭建新的环境进行测试。

环境准备:

1.安装vue-cli 3.5

npm install -g @vue/cli

2.使用脚手架创建新项目(可以查看官网教程)

vue create app

运行后会进入项目首次初始化,第一段会提示你选择所需要的插件(上下移动,空格选择),我选择的是Babel、TypeScript、Router、Vuex、Css Pre-processors、Linter几项

image

选择好了过后回车,然后一路默认(具体安装每一步的含义可以复制下来翻译一下就能明白,这里先不赘述),到样式那里,我选择的是Less,语法检查需要选择TSLint,然年就静等安装完成。

3.初次运行默认项目

安装完成过后,需要对我们的产物进行验证,将工作区切换到刚才创建的项目之下,也就是 xxx/app,然后运行npm run serve,出现下面字样的话就代表你成功了,

image

4.创建一个tsx文件测试一下(如果想在*.vue文件中进行,可以将vue文件中的script改为

在src某目录下创建一个demo.tsx文件,里面使用类组件的导出一个vue组件,代码如下:


import { Component, Vue } from 'vue-property-decorator';

@Component

export default class App extends Vue {

  protected render() {

    return 
helloword
; } }

将main.ts导入的./App.vue改为./demo,这是保存后查看首页应该就成了如下所示的样子

image

好,证明tsx文件可以生效了,生效之后,就需要测试下使用tsx文件是否能够完整替代.vue文件了,我列了如下检查点:

image

第一步,测试下v-model是否能被支持,将demo.tsx改造后代码如下:


import { Component, Vue } from 'vue-property-decorator';

@Component

export default class App extends Vue {

  public value = '';

  protected render() {

    return (

      
{this.value}
); } }

然后到页面上在输入框输入内容,右边就会跟着发生响应,这证明v-model是被支持的,v-on同理,这里赘述。

第二步,验证watch、computed、dataObserve、methods等特性

watch需要使用到vue-property-decorator中的Watch方法,代码如下:


import { Component, Vue, Watch } from 'vue-property-decorator';

@Component

export default class App extends Vue {

  public value = '';

  public msg = '';

  @Watch('value')

  protected valueWatch(newV: any, oldV: any) {

    this.msg = `监听到属性value发生变化,新的值为:${newV}`;

  }

  protected render() {

    return (

      
{this.msg}
); } }

保存后到页面上看,输入值后右侧文字会跟随输入而改变,证明watch是OK的。

computed的使用方法是get name(){},代码如下:


import { Component, Vue, Watch } from 'vue-property-decorator';

@Component

export default class App extends Vue {

  public value = '';

  public msg = '';

  public get valueLength() {

    return this.value.length;

  }

  @Watch('value')

  protected valueWatch(newV: any, oldV: any) {

    this.msg = `监听到属性value发生变化,新的值为:${newV}`;

  }

  protected render() {

    return (

      
{this.valueLength}
); } }

保存后在输入框输入时右侧则会打印出相应的长度,证明computed特性是被支持的。

methods的用法是直接在class中声明一个函数,声明后等同于放在methods中的方法,但要特别注意的是,methods的方法要与vue自带的特性方法名要区分开,如果你声明一个方法为created(){}或者是mounted之类的,其函数实际上是在组件的生命周期中被调用的函数,例如:


import { Component, Vue, Watch } from 'vue-property-decorator';

@Component

export default class App extends Vue {

  public value = '';

  public msg = '';

  public get valueLength() {

    return this.value.length;

  }

  public created() {

    console.log('我在组件创建时被调用');

  }

  public handleClick() {

    console.log('我被点了');

  }

  @Watch('value')

  protected valueWatch(newV: any, oldV: any) {

    this.msg = `监听到属性value发生变化,新的值为:${newV}`;

  }

  protected render() {

    return (

      
{this.valueLength}
); } }

使用外部引入样式文件,在项目中,如果需要使用css module的话,需要将文件名声明为 .module.less /.module.css的格式,表示使用css module,如果不想写的话可以在vue.config.js中配置cssmodules为true来解决(参见:传送门),这里先不修改配置文件,创建一个文件名为test.module.less,在demo.tsx中引入,并测试其css module和普通css穿透的效果,需要注意的是,在*.vue文件中,css穿透一般是使用>>>或者/deep/来实现的,但是在样式文件中,应该遵循loader的处理方式,例如less,需要使用:global(.className)的方式来实现,代码如下

demo.tsx


import { Component, Vue, Watch } from 'vue-property-decorator';

import style from './test.module.less';

@Component

export default class App extends Vue {

  public value = '';

  public msg = '';

  public get valueLength() {

    return this.value.length;

  }

  public created() {

    console.log('我在组件创建时被调用');

  }

  public handleClick() {

    console.log('我被点了');

  }

  @Watch('value')

  protected valueWatch(newV: any, oldV: any) {

    this.msg = `监听到属性value发生变化,新的值为:${newV}`;

  }

  protected render() {

    return (

      
{this.valueLength}
); } }

test.module.less


.class1 {

    color: blue;

    :global(.class2) {

        background: red;

    }

}

保存后可以看到文字变成了蓝色,按钮变成了红色

image

需要注意的是,如果你导入less的时候被提示找不到模块xxx.less,的话,你需要在项目中声明下对less模块的支持,在项目中找到或创建shims-vue.d.ts文件,添加内容:


declare module "*.less" {

  const less: any;

  export default less;

}

再切换回去的话就没有错误提示了。这个错误提示是tslint检查的,虽然不影响使用,但是看着报错也挺不舒服的是吧。

再验证下props传值和ref的功能,在同级目录新建一个组件,xxx.tsx,内容如下:


import { Component, Vue, Prop } from 'vue-property-decorator';

@Component

export default class App extends Vue {

  @Prop({ required: false })

  public msg?: string;

  protected render() {

    return {this.msg};

  }

}

再在demo.tsx中引入组件,内容修改后如下:


import { Component, Vue, Watch } from 'vue-property-decorator';

import style from './test.module.less';

import Xxx from './xxx';

@Component

export default class App extends Vue {

  public value = '';

  public msg = '';

  public get valueLength() {

    return this.value.length;

  }

  public created() {

    console.log('我在组件创建时被调用');

  }

  public handleClick() {

    console.log('我被点了');

  }

  @Watch('value')

  protected valueWatch(newV: any, oldV: any) {

    this.msg = `监听到属性value发生变化,新的值为:${newV}`;

  }

  protected render() {

    return (

      
{this.valueLength}
); } }

保存后查看页面,可以看到渲染出了组件的内容,证明组件传值是可以正常工作的

image

但是此时可能会遇到一个tslint的错误提示,Type '{ msg: string; }' is not assignable to type 'ComponentOptions, DefaultMethods, DefaultComputed, PropsDefinition>, Record>',说你的key在组件上根本找不到,这个就很蛋疼了,如果把传值的方式改为 的话,报错就会消失,这是因为vue官方设定的属性中就有props这个属性值,具体文件位置在 node_modules/vue/types/options 的ComponentOptions中可以看到,如果直接修改源码的话可以添加支持任意属性,但是这种方式显然不够完美,那么如何做呢?实际上应该是在项目的声明文件中,将对应的interface接口扩展一下就OK了,修改或创建shims-tsx.d.ts文件,在其中添加如下内容:


declare module "vue/types/options" {

  interface ComponentOptions {

    [propName: string]: any;

    ref?: string;

  }

}

ref我也添加进去了,原因是为了方便代码提示,这样的话,我在JSX代码中,输入r就会出现ref的提示了

image

如果需要添加v-model或者是v-on之类的,可以添加为vModel驼峰的方式来声明,在JSX中,他们是兼容的,并且,如果是段斜杠的方式声明的话,vscode不会有代码提示。

以上就是本次踩坑之旅的全部内容,没写过文档,整理的有点乱.

你可能感兴趣的:(Vue-cli 3.5 结合TSX使用踩坑旅)