使用TypeScript以及React语法编写vue组件

337 阅读3分钟

最近学习vue的使用,自己不大喜欢用脚手架搭建项目,又热衷于TypeScript 和 React 刚好 又想体验一下webpack4就自己整了这么一个混合型的简单模板.分离css,压缩,dev map 定位==

后续准备加入 服务器渲染 nuxt ui框架 == 有啥建议啥的欢迎一起探讨。

没有写过文章 语文也不及格 排版什么的还请各位大佬见谅勿喷

Git地址:传送门

先讲讲Webpack4的一些配置

跟以前有些不一样

  1. 提取公共的js模块不用需要使用 内置的 CommonsChunkPlugin 插件 而是多了一个基础配置项 optimizatio
  2. 启用UglifyJsPlugin压缩只需要配置mode 不在需要引入 UglifyJsPlugin 插件
  3. webpack4编译使用 awesome-typescript-loader 编译 ts 热更新的时候会报错,改成 ts-loader

optimization 配置如下

  // webpack 4删除了CommonsChunkPlugin,以支持两个新选项(optimization.splitChunks和optimization.runtimeChunk)
  // https://gist.github.com/sokra/1522d586b8e5c0f5072d7565c2bee693
  optimization: {
            splitChunks: {
                cacheGroups: {
                    commons: {
                        test: /[\\/]node_modules[\\/]/,
                        name: "vendors",
                        chunks: "all"
                    }
                }
            }
        },

mode 配置如下

   // 打包模式 development。启用NamedModulesPlugin。 production。启用UglifyJsPlugin,ModuleConcatenationPlugin和NoEmitOnErrorsPlugin。
   mode: evn.Generative ? 'production' : 'development',

加载配置

vue common 加入到wepback中

    resolve: {
            extensions: [".ts", ".tsx", ".js", '.vue', ".json"],
            // https://github.com/vuejs-templates/webpack/issues/215
            alias: {
                'vue$': 'vue/dist/vue.common.js',
            }
        },

ts,tsx,vue的加载配置

 {
                    // vue 配置文档 https://vue-loader.vuejs.org/zh-cn/configurations/pre-processors.html
                    test: /\.vue$/, loader: 'vue-loader',
                    include: srcPath,
                    options: {
                        loaders: {
                            ts: 'ts-loader',              //编译 vue script 中的 ts
                            tsx: 'babel-loader!ts-loader',//编译 vue script 中的 tsx
                            css: styleCss.extract({       //提取css
                                use: cssOptions.use,
                                fallback: 'vue-style-loader'
                            })
                        }
                    }
                },
                //ts 直接编译 
                { test: /\.ts$/, include: srcPath, loader: 'ts-loader' },
                // vue jsx   https://github.com/vuejs/babel-plugin-transform-vue-jsx
                // 编译顺序  tsx>es6>babel,vue-jsx>js 
                { test: /\.tsx$/, include: srcPath, loader: 'babel-loader!ts-loader' },

tsx 的处理配置

tsconfig.json 文件配置

  1. jsx 配置成 preserve 这样 ts编译保留jsx语法交给babel 处理
 "jsx": "preserve", 
  1. babel 需要下载 transform-vue-jsx 插件 以及依赖插件 我是在 package.json 中配置的插件 看这里
"babel": {
    "presets": [
      "env"
    ],
    "plugins": [
      "transform-vue-jsx"
    ]
  },
  1. 加入 tsx 加载器 编译顺序 tsx>es6>babel,vue-jsx>js
   { test: /\.tsx$/, include: srcPath, loader: 'babel-loader!ts-loader' },

组件类型 完整代码可以 获取源码查看 传送门

class 模板文件类型 components>class>test1.ts

import Vue from 'vue'
import Component from 'vue-class-component'
import template from './template.html'
// @Component 修饰符注明了此类为一个 Vue 组件
@Component({
  // 所有的组件选项都可以放在这里
  template
})
export default class extends Vue {
  // 初始数据可以直接声明为实例的属性
  message = '获取数据!'
  list: { id: number, name: string, age: number }[] = [];
  loading = false;
  // 组件方法也可以直接声明为实例的方法
  onClick() {
    ...
  }

}

tsx 类型 components>jsx>test.tsx

import Vue from 'vue'
import Component from 'vue-class-component'
import "./style.css"
// @Component 修饰符注明了此类为一个 Vue 组件
@Component({})
export default class extends Vue {
  message = "JSX 组件";
  conut = 0;
  click(e) {
    this.conut++;
    console.log(e);
  }
  sync(prop, value) {
    this[prop] = value
  }
  list: { id: number, name: string, age: number }[] = [];
  loading = false;
  // 组件方法也可以直接声明为实例的方法
  getList() {
    this.loading = true;
    setTimeout(() => {
      const list = [{
        id: Math.floor(Math.random() * 10000),
        name: "Name" + Math.floor(Math.random() * 100),
        age: Math.floor(Math.random() * 100),
      }, {
        id: Math.floor(Math.random() * 10000),
        name: "Name" + Math.floor(Math.random() * 100),
        age: Math.floor(Math.random() * 100),
      }, {
        id: Math.floor(Math.random() * 10000),
        name: "Name" + Math.floor(Math.random() * 100),
        age: Math.floor(Math.random() * 100),
      },];
      this.list = [...this.list, ...list];
      this.loading = false;
    }, 1500);
  }
  render(h) {
    return (
      <div class="aaaaaaa">
        <p>{this.message}</p>
        <input type="text" value={this.conut} on-input={(e) => this.sync('conut', e.target.value)} />
        <button onClick={this.click}>Add {this.conut}</button>
        <span>{this.message}</span> world!

        <div>
          <table style="border: 1px solid red;width: 300px">
            <tr style="border: 1px solid red">
              <td>id</td>
              <td>name</td>
              <td>age</td>
            </tr>
            {/* 数据 */}
            {this.list.map(t => <tr  >
              <td style="border: 1px solid red">{t.id}</td>
              <td style="border: 1px solid red">{t.name}</td>
              <td style="border: 1px solid red">{t.age}</td>
            </tr>)}
            {/* loading */}
            {this.loading ? <tr >
              <td colspan="3" style="text-align: center;color: red">Loading...</td>
            </tr> : null}
          </table>
          <button on-click={this.getList}>获取数据</button>
        </div>
      </div>
    )
  }
}

vue 类型文件就用不说了。

文件结构

效果 (没有引入ui框架)

这里还有一个以前学习 react+mobx+rxjs+electron 的项目 是个仿网易云的播放器 传送门