在Vue项目中使用Typescript的实现


Posted in Javascript onDecember 19, 2019

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"
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
让JavaScript 轻松支持函数重载 (Part 1 - 设计)
Aug 04 Javascript
jquery鼠标停止移动事件
Dec 21 Javascript
JavaScript对IE操作的经典代码(推荐)
Mar 10 Javascript
jQuery学习笔记之jQuery原型属性和方法
Jun 09 Javascript
详解AngularJS中$http缓存以及处理多个$http请求的方法
Feb 06 Javascript
Angular Module声明和获取重载实例代码
Sep 14 Javascript
Vue方法与事件处理器详解
Dec 01 Javascript
详解使用Vue.Js结合Jquery Ajax加载数据的两种方式
Jan 10 Javascript
Angular.js实现多个checkbox只能选择一个的方法示例
Feb 24 Javascript
JavaScript mixin实现多继承的方法详解
Mar 30 Javascript
微信禁止下拉查看URL的处理方法
Sep 28 Javascript
浅析vue cli3 封装Svgicon组件正确姿势(推荐)
Apr 27 Javascript
JS数据类型STRING使用实例解析
Dec 18 #Javascript
JS精确判断数据类型代码实例
Dec 18 #Javascript
使用webpack/gulp构建TypeScript项目的方法示例
Dec 18 #Javascript
小程序简单两栏瀑布流效果的实现
Dec 18 #Javascript
js数据类型转换与流程控制操作实例分析
Dec 18 #Javascript
vue不操作dom实现图片轮播的示例代码
Dec 18 #Javascript
使用JS来动态操作css的几种方法
Dec 18 #Javascript
You might like
咖啡风味 世界咖啡主要分布分布 咖啡的生长要求
2021/03/06 新手入门
PHP var_dump遍历对象属性的函数与应用代码
2010/06/04 PHP
Zend Framework实现留言本分页功能(附demo源码下载)
2016/03/22 PHP
教你在header中隐藏php的版本信息
2016/08/10 PHP
php工具型代码之印章抠图
2018/07/18 PHP
gearman中任务的优先级和返回状态实例分析
2020/02/27 PHP
js模拟弹出效果代码修正版
2008/08/07 Javascript
JavaScript入门教程(7) History历史对象
2009/01/31 Javascript
Js 中debug方式
2010/02/07 Javascript
运用JQuery的toggle实现网页加载完成自动弹窗
2014/03/18 Javascript
jquery实现瀑布流效果分享
2014/03/26 Javascript
一个小例子解释如何来阻止Jquery事件冒泡
2014/07/17 Javascript
Bootstrap三种表单布局的使用方法
2016/06/21 Javascript
jquery轮播的实现方式 附完整实例
2016/07/28 Javascript
基于jQuery实现淡入淡出效果轮播图
2020/07/31 Javascript
总结AngularJS开发者最常犯的十个错误
2016/08/31 Javascript
jQuery实现的简单悬浮层功能完整实例
2017/01/23 Javascript
关于layui toolbar和template的结合使用方法
2019/09/19 Javascript
Layui动态生成select下拉选择框不显示的解决方法
2019/09/24 Javascript
[43:58]DOTA2-DPC中国联赛定级赛 LBZS vs SAG BO3第一场 1月8日
2021/03/11 DOTA
python使用urllib模块和pyquery实现阿里巴巴排名查询
2014/01/16 Python
python用来获得图片exif信息的库实例分析
2015/03/16 Python
详解Python进程间通信之命名管道
2017/08/28 Python
Python实现字典的遍历与排序功能示例
2017/12/23 Python
Django 项目通过加载不同env文件来区分不同环境
2020/02/17 Python
Python字符串格式化f-string多种功能实现
2020/05/07 Python
使用 django orm 写 exists 条件过滤实例
2020/05/20 Python
css3 flex实现div内容水平垂直居中的几种方法
2020/03/27 HTML / CSS
html5实现多文件的上传示例代码
2014/02/13 HTML / CSS
Vans(范斯)德国官网:美国南加州的原创极限运动潮牌
2017/05/02 全球购物
类和结构的区别
2012/08/15 面试题
构造方法和其他方法的区别
2016/04/26 面试题
学习考察心得体会
2014/09/04 职场文书
个人对照检查材料思想汇报
2014/09/26 职场文书
市场调研项目授权委托书范本
2014/10/04 职场文书
Redis官方可视化工具RedisInsight安装使用教程
2022/04/19 Redis