在Vue项目中使用Typescript
<p>3.0迟迟没有发布release版本,现阶段在vue项目中使用Typescript需要花不小的精力在工程的配置上面。主要的工作是webpack对TS,TSX的处理,以及2.x版本下面使用class的形式书写vue 组件的一些限制和注意事项。</p><p> </p>
<h2 id="item-1">webpack 配置</h2>
<p>配置webpack对TS,TSX的支持,以便于我们在Vue项目中使用Typescript和tsx。</p>
<pre><code class="hljs javascript"><span class="hljs-built_in">module.exports = {
<span class="hljs-attr">entry: <span class="hljs-string">'./index.vue',
<span class="hljs-attr">output: { <span class="hljs-attr">filename: <span class="hljs-string">'bundle.<span class="hljs-string">js</span><span class="hljs-string">' },
<span class="hljs-attr">resolve: {
<span class="hljs-attr">extensions: [<span class="hljs-string">'.ts', <span class="hljs-string">'.tsx', <span class="hljs-string">'.vue', <span class="hljs-string">'.vuex']
},
<span class="hljs-attr">module: {
<span class="hljs-attr">rules: [
{ <span class="hljs-attr">test: <span class="hljs-regexp">/\.vue$/, <span class="hljs-attr">loader: <span class="hljs-string">'vue-loader',
<span class="hljs-attr">options: {
<span class="hljs-attr">loaders: {
<span class="hljs-attr">ts: <span class="hljs-string">'ts-loader',
<span class="hljs-attr">tsx: <span class="hljs-string">'babel-loader!ts-loader',
}
}
},
{
<span class="hljs-attr">test: <span class="hljs-regexp">/\.ts$/,
<span class="hljs-attr">loader: <span class="hljs-string">'ts-loader',
<span class="hljs-attr">options: { <span class="hljs-attr">appendTsSuffixTo: [<span class="hljs-regexp">/TS\.vue$/] } },
{
<span class="hljs-attr">test: <span class="hljs-regexp">/\.tsx$/,
<span class="hljs-attr">loader: <span class="hljs-string">'babel-loader!ts-loader',
<span class="hljs-attr">options: {
<span class="hljs-attr">appendTsxSuffixTo: [<span class="hljs-regexp">/TSX\.vue$/]
}
}
]
}
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>在上面的配置中,vue文件中的TS内容将会使用ts-loader处理,而TSX内容将会按照ts-loader-->babel-loader的顺序处理。</p>
<p>appendTsSuffixTo/appendTsxSuffixTo配置项的意思是说,从vue文件里面分离的script的ts,tsx(取决于<script lang="xxx"></script>)内容将会被加上ts或者tsx的后缀,然后交由ts-loader解析。</p>
<p>我在翻看了ts-loader上关于appendTsxSuffixTo的讨论发现,ts-loader貌似对文件后缀名称有很严格的限定,必须得是ts/tsx后缀,所以得在vue-loader extract <script>中内容后,给其加上ts/tsx的后缀名,这样ts-loader才会去处理这部分的内容。</p>
<p><strong>ts-loader只对tsx做语法类型检查,真正的jsx-->render函数应该交由babel处理。</strong></p>
<p>所以我们还需要使用plugin-transform-vue-jsx来将vue jsx转换为真正的render函数。</p>
<pre><code class="hljs php"><span class="hljs-comment">// babel.config.json
{
<span class="hljs-string">"presets": [<span class="hljs-string">"env"],
<span class="hljs-string">"plugins": [<span class="hljs-string">"transform-vue-jsx"]
}</span></span></span></span></span></code></pre>
<p>同时,配置TS对tsx的处理为preserve,让其只对tsx做type类型检查。</p>
<pre><code class="hljs php"><span class="hljs-comment">// tsconfig.json
{
<span class="hljs-string">"compilerOptions": {
<span class="hljs-string">"jsx": <span class="hljs-string">"preserve",
}</span></span></span></span></code></pre>
<p> </p>
<h2 id="item-2">使用vue cli 4.x</h2>
<p>高版本的vue cli如4.x已经集成了vue + typescript的配置。选择<strong>use Typescript</strong> + <strong>Use class-style component syntax</strong>选项创建工程。</p>
<p>创建后的工程目录如下:<br><img src="http://api.fly63.com/vue_blog/public/Uploads/20191218/5dfa3df31ae5d.jpg"></p>
<p>在src根目录下,有两个shims.xx.d.ts的类型声明文件。</p>
<pre><code class="hljs javascript"><span class="hljs-comment">//shims.vue.d.ts
declare <span class="hljs-built_in">module <span class="hljs-string">"*.vue" {
<span class="hljs-keyword">import Vue <span class="hljs-keyword">from <span class="hljs-string">"vue";
<span class="hljs-keyword">export <span class="hljs-keyword">default Vue;
}</span></span></span></span></span></span></span></span></code></pre>
<pre><code class="hljs php"><span class="hljs-comment">// shims.jsx.d.ts
import Vue, { VNode } from <span class="hljs-string">"vue";
<span class="hljs-keyword">declare <span class="hljs-keyword">global {
<span class="hljs-keyword">namespace <span class="hljs-title">JSX {
// <span class="hljs-title">tslint:<span class="hljs-title">disable <span class="hljs-title">no-<span class="hljs-title">empty-<span class="hljs-title">interface
<span class="hljs-title">interface <span class="hljs-title">Element <span class="hljs-title">extends <span class="hljs-title">VNode {}
// <span class="hljs-title">tslint:<span class="hljs-title">disable <span class="hljs-title">no-<span class="hljs-title">empty-<span class="hljs-title">interface
<span class="hljs-title">interface <span class="hljs-title">ElementClass <span class="hljs-title">extends <span class="hljs-title">Vue {}
<span class="hljs-title">interface <span class="hljs-title">IntrinsicElements {
[<span class="hljs-title">elem: <span class="hljs-title">string]: <span class="hljs-title">any;
}
}
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>它们是作什么用的呢?</p>
<p>shims.vue.d.ts给所有.vue文件导出的模块<strong>声明了类型为Vue</strong>,它可以帮助IDE判断.vue文件的类型。</p>
<p>shims.jsx.d.ts 为 JSX 语法的全局命名空间,这是因为基于值的元素会简单的在它所在的作用域里按标识符查找。当在 tsconfig 内开启了 jsx 语法支持后,其会自动识别对应的 .tsx 结尾的文件,(也就是Vue 单文件组件中<script lang="tsx"></script>的部分)可参考官网 tsx</p>
<p> </p>
<h2 id="item-3">基本用法</h2>
<p>在vue 2.x中使用class的方式书写vue组件需要依靠vue-property-decorator来对vue class做转换。</p>
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">script <span class="hljs-attr">lang=<span class="hljs-string">"ts"><span class="javascript">
<span class="hljs-keyword">import { Component, Prop, Vue } <span class="hljs-keyword">from <span class="hljs-string">"vue-property-decorator";
<span class="hljs-keyword">export <span class="hljs-keyword">default <span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-keyword">extends <span class="hljs-title">Vue {
@Prop({ <span class="hljs-attr">default: <span class="hljs-string">'default msg'}) private msg!: string;
name!: string;
show() {
<span class="hljs-built_in">console.log(<span class="hljs-string">"this.name", <span class="hljs-keyword">this.name);
}
}
<span class="hljs-tag"></<span class="hljs-name">script></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>导出的class是经过Vue.extend之后的VueComponent函数(理论上class就是一个Function)。</p>
<p>其最后的结果就像我们使用Vue.extend来扩展一个Vue组件一样。</p>
<pre><code class="hljs javascript"><span class="hljs-comment">// 创建构造器
<span class="hljs-keyword">var</span> Profile = Vue.extend({
<span class="hljs-attr">template: <span class="hljs-string">'<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
<span class="hljs-attr">data: <span class="hljs-function"><span class="hljs-keyword">function (<span class="hljs-params">) {
<span class="hljs-keyword">return {
<span class="hljs-attr">firstName: <span class="hljs-string">'Walter',
<span class="hljs-attr">lastName: <span class="hljs-string">'White',
<span class="hljs-attr">alias: <span class="hljs-string">'Heisenberg'
}
}
})
<span class="hljs-keyword">export <span class="hljs-keyword">default {
<span class="hljs-attr">components: {
Profile
}
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>注意上面的Profile组件并不是和我们平时一样写的Vue组件是一个plain object配置对象,它其实是一个VueComponent函数。</p>
<p>父组件实例化子组件的时候,会对传入的vue object 进行扩展,使用Vux.extend转换为组件函数。<br>如果components中的值本身是一个函数,就会省略这一步。这一点, 从Vue 源码中可以看出。</p>
<pre><code class="hljs nginx"><span class="hljs-attribute">if (isObject(Ctor)) {
<span class="hljs-attribute">Ctor = baseCtor.extend(Ctor)
}</span></span></code></pre>
<p>上面的Ctor就是在components中传入的组件,对应于上面导出的Profile组件。</p>
<p> </p>
<h2 id="item-4">使用vuex</h2>
<p>使用vuex-class中的装饰器来对类的属性做注解。</p>
<pre><code class="hljs javascript">
<span class="hljs-keyword">import Vue <span class="hljs-keyword">from <span class="hljs-string">'vue'<span class="hljs-keyword">import Component <span class="hljs-keyword">from <span class="hljs-string">'vue-class-component'<span class="hljs-keyword">import {
State,
Getter,
Action,
Mutation,
namespace
} <span class="hljs-keyword">from <span class="hljs-string">'vuex-class'
<span class="hljs-keyword">const</span> someModule = namespace(<span class="hljs-string">'path/to/module')
@Component
<span class="hljs-keyword">export <span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">MyComp <span class="hljs-keyword">extends <span class="hljs-title">Vue {
@State(<span class="hljs-string">'foo') stateFoo
@State(<span class="hljs-function"><span class="hljs-params">state => state.bar) stateBar
@Getter(<span class="hljs-string">'foo') getterFoo
@Action(<span class="hljs-string">'foo') actionFoo
@Mutation(<span class="hljs-string">'foo') mutationFoo
@someModule.Getter(<span class="hljs-string">'foo') moduleGetterFoo
<span class="hljs-comment">// If the argument is omitted, use the property name
<span class="hljs-comment">// for each state/getter/action/mutation type
@State foo
@Getter bar
@Action baz
@Mutation qux
created () {
<span class="hljs-keyword">this.stateFoo <span class="hljs-comment">// -> store.state.foo
<span class="hljs-keyword">this.stateBar <span class="hljs-comment">// -> store.state.bar
<span class="hljs-keyword">this.getterFoo <span class="hljs-comment">// -> store.getters.foo
<span class="hljs-keyword">this.actionFoo({ <span class="hljs-attr">value: <span class="hljs-literal">true }) <span class="hljs-comment">// -> store.dispatch('foo', { value: true })
<span class="hljs-keyword">this.mutationFoo({ <span class="hljs-attr">value: <span class="hljs-literal">true }) <span class="hljs-comment">// -> store.commit('foo', { value: true })
<span class="hljs-keyword">this.moduleGetterFoo <span class="hljs-comment">// -> store.getters['path/to/module/foo']
}
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p> </p>
<h2 id="item-5">mixin</h2>
<p>对于mixin,我们使用class的继承很容易实现类似功能。</p>
<pre><code class="hljs javascript"><span class="hljs-keyword">import Vue <span class="hljs-keyword">from <span class="hljs-string">'vue'
<span class="hljs-keyword">import { Component } <span class="hljs-keyword">from <span class="hljs-string">'vue-property-decorator'
@Component
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">DeployMixin <span class="hljs-keyword">extends <span class="hljs-title">Vue{
name: string;
deploy(){
<span class="hljs-comment">// do something
}
}
@Component
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">Index <span class="hljs-keyword">extends <span class="hljs-title">DeployMixin{
<span class="hljs-keyword">const</span><span class="hljs-keyword">ructor(){
<span class="hljs-keyword">super()
}
sure(){
<span class="hljs-keyword">this.deploy()
}
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p><span style="position: relative; left: -100000px">广州设计公司https://www.houdianzi.com</span> <span style="position: relative; left: -100000px">我的007办公资源网站https://www.wode007.com</span></p>
<h2 id="item-6">VS code jsx快捷键</h2>
<p>设置 VS code中对emmet的支持</p>
<pre><code class="hljs php"><span class="hljs-string">"emmet.includeLanguages": {
<span class="hljs-string">"<span class="hljs-string">JavaScript</span><span class="hljs-string">": <span class="hljs-string">"<span class="hljs-string">html</span><span class="hljs-string">"
}</span></span></span></span></span></code></pre>
<p>或者是</p>
<pre><code class="hljs php"><span class="hljs-string">"emmet.includeLanguages": {
<span class="hljs-string">"<span class="hljs-string">JavaScript</span><span class="hljs-string">": <span class="hljs-string">"javascript<span class="hljs-string">react</span><span class="hljs-string">"
}</span></span></span></span></span></code></pre><br><br>
来源:https://www.cnblogs.com/qianxiaox/p/13830974.html
頁:
[1]