网络编程
位置:首页>> 网络编程>> JavaScript>> 在Vue项目中使用Typescript的实现

在Vue项目中使用Typescript的实现

作者:BBQ只有番薯  发布时间:2024-04-26 17:39:57 

标签:Vue,使用,Typescript

3.0迟迟没有发布release版本,现阶段在Vue项目中使用Typescript需要花不小的精力在工程的配置上面。主要的工作是webpack对TS,TSX的处理,以及2.x版本下面使用class的形式书写Vue 组件的一些限制和注意事项。

Webpack 配置

配置webpack对TS,TSX的支持,以便于我们在Vue项目中使用Typescript和tsx。


module.exports = {
entry: './index.vue',
output: { filename: 'bundle.js' },
resolve: {
 extensions: ['.ts', '.tsx', '.vue', '.vuex']
},
module: {
 rules: [
  { test: /\.vue$/, loader: 'vue-loader',
   options: {
   loaders: {
    ts: 'ts-loader',
    tsx: 'babel-loader!ts-loader',
   }
   }
  },
  {
   test: /\.ts$/,
   loader: 'ts-loader',
   options: { appendTsSuffixTo: [/TS\.vue$/] }    },
  {
   test: /\.tsx$/,
   loader: 'babel-loader!ts-loader',
   options: {
    appendTsxSuffixTo: [/TSX\.vue$/]
   }
  }
 ]
}
}

在上面的配置中,vue文件中的TS内容将会使用ts-loader处理,而TSX内容将会按照ts-loader-->babel-loader的顺序处理。

appendTsSuffixTo/appendTsxSuffixTo 配置项的意思是说,从vue文件里面分离的script的ts,tsx(取决于<script lang="xxx"></script>)内容将会被加上ts或者tsx的后缀,然后交由ts-loader解析。

我在翻看了ts-loader上关于appendTsxSuffixTo的讨论发现,ts-loader貌似对文件后缀名称有很严格的限定,必须得是ts/tsx后缀,所以得在vue-loader extract <script>中内容后,给其加上ts/tsx的后缀名,这样ts-loader才会去处理这部分的内容。

ts-loader只对tsx做语法类型检查,真正的jsx-->render函数应该交由babel处理。

所以我们还需要使用plugin-transform-vue-jsx来将vue jsx转换为真正的render函数。


// babel.config.json
{
"presets": ["env"],
"plugins": ["transform-vue-jsx"]
}

同时,配置TS对tsx的处理为preserve,让其只对tsx做type类型检查。


// tsconfig.json
{
"compilerOptions": {
"jsx": "preserve",
}

使用vue cli 4.x

高版本的vue cli如4.x已经集成了vue + typescript的配置。选择use Typescript + Use class-style component syntax选项创建工程。

创建后的工程目录如下:

在Vue项目中使用Typescript的实现

在src根目录下,有两个shims.xx.d.ts的类型声明文件。


// shims.vue.d.ts
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}

// shims.jsx.d.ts
import Vue, { VNode } from "vue";
declare global {
namespace JSX {
 // tslint:disable no-empty-interface
 interface Element extends VNode {}
 // tslint:disable no-empty-interface
 interface ElementClass extends Vue {}
 interface IntrinsicElements {
  [elem: string]: any;
 }
}
}

它们是作什么用的呢?

shims.vue.d.ts给所有.vue文件导出的模块声明了类型为Vue,它可以帮助IDE判断.vue文件的类型。

shims.jsx.d.ts 为 JSX 语法的全局命名空间,这是因为基于值的元素会简单的在它所在的作用域里按标识符查找。当在 tsconfig 内开启了 jsx 语法支持后,其会自动识别对应的 .tsx 结尾的文件,(也就是Vue 单文件组件中<script lang="tsx"></script>的部分)可参考

官网 tsx

基本用法

在vue 2.x中使用class的方式书写vue组件需要依靠vue-property-decorator来对vue class做转换。


<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
export default class extends Vue {
@Prop({ default: 'default msg'}) private msg!: string;
name!: string;
show() {
 console.log("this.name", this.name);
}
}
</script>

导出的class是经过Vue.extend之后的VueComponent函数(理论上class就是一个Function)。

其最后的结果就像我们使用Vue.extend来扩展一个Vue组件一样。


// 创建构造器
var Profile = Vue.extend({
template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
data: function () {
 return {
  firstName: 'Walter',
  lastName: 'White',
  alias: 'Heisenberg'
 }
}
})

export default {
 components: {
   Profile
 }
}

注意上面的Profile组件并不是和我们平时一样写的Vue组件是一个plain object配置对象,它其实是一个VueComponent函数。

父组件实例化子组件的时候,会对传入的vue object 进行扩展,使用Vux.extend转换为组件函数。
如果components中的值本身是一个函数,就会省略这一步。这一点, 从Vue 源码中可以看出。


if (isObject(Ctor)) {
 Ctor = baseCtor.extend(Ctor)
}

上面的Ctor就是在components中传入的组件,对应于上面导出的Profile组件。

使用vuex

使用vuex-class中的装饰器来对类的属性做注解。


import Vue from 'vue'import Component from 'vue-class-component'import {
State,
Getter,
Action,
Mutation,
namespace
} from 'vuex-class'

const someModule = namespace('path/to/module')

@Component
export class MyComp extends Vue {
@State('foo') stateFoo
@State(state => state.bar) stateBar
@Getter('foo') getterFoo
@Action('foo') actionFoo
@Mutation('foo') mutationFoo
@someModule.Getter('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']
}
}

mixin

对于mixin,我们使用class的继承很容易实现类似功能。


import Vue from 'vue'
import { Component } from 'vue-property-decorator'
@Component
class DeployMixin extends Vue{
name: string;
deploy(){
 // do something
}
}
@Component
class Index extends DeployMixin{
constructor(){
 super()
}
sure(){
 this.deploy()
}
}

VS code jsx快捷键

设置 VS code中对emmet的支持


"emmet.includeLanguages": {
 "javascript": "html"
}

或者是


"emmet.includeLanguages": {
 "javascript": "javascriptreact"
}

来源:https://segmentfault.com/a/1190000021329918

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com