TSX 和 CSS module 语法 代替 模板 SFC template(使用 Vite 构建)

大纲链接 §

[toc]


1. Vue2.7+SFC template 写法概述


2. 对比 TSXCSS module 写法


3. 在项目中用到过的 SFC template 写法,尝试改写为 TSXCSS module


4. 在 Vue2.x 中使用 TSXCSS module


5. 在 Vue3.x 中使用 TSXCSS module


配置 scss 全局样式文件

  • 需要先配置别名

虽然 vite 原生支持 less/sass/scss/stylus,但是你必须手动安装他们的预处理器依赖

  • 安装依赖dart-sass,但包的名字为 sass
  • 不要安装为dart-sassdeprecated dart-sass@1.25.0: This package has been renamed to 'sass'.
1
2
# yarn add sass --dev
pnpm add sass -D

src/assets 下新增 style 文件夹,用于存放全局样式文件

  • 新建 src/assets/style/main.scss, 设置一个用于测试的颜色变量 :
1
$test-color: red;
  • 配置 vite.config.ts,让 vite 识别 scss 全局变量
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
...
css:{
    // 指定传递给 CSS 预处理器的选项
    preprocessorOptions:{
      scss:{
        additionalData:'@import "@/assets/style/main.scss";'
      }
    }
  },
...

在任意组件中使用,不需要任何引入可以直接使用全局scss定义的变量

1
2
3
.test{
  color: $test-color;
}

TS的相关配置

vue/cli项目中shimes-vue.d.ts 文件的作用

  • 为了typescript做的适配定义文件,因为.vue 文件不是一个常规的文件类型
  • ts 是不能理解 .vue 文件是干嘛的 加这个文件是是告诉 ts,.vue 文件是这种类型的。

vite项目中env.d.ts 文件的作用

  • 为了声明 在vite中使用env环境的配置 可以通过 import.meta.env.<变量名称来访问>

vue-tsctsc

  • tsc 只能验证 ts 代码类型
  • vue-tsc 可以验证 ts + Vue Template 中的类型(基于 Volar)

JSX支持

Vue 3 JSX 相关语法

使用tsx风格代替template模板方式,需要注意相应改变的地方:

  1. src/router/ 引入页面文件 .tsx 代替 .vue 文件
  2. src/main.ts 修改引入 App 文件 .tsx 代替 .vue文件

安装依赖插件

1
2
# yarn add @vitejs/plugin-vue-jsx -D
pnpm add @vitejs/plugin-vue-jsx -D

配置tsconfig.json,在.tsx文件里支持JSX

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
  "compilerOptions": {
    "target": "esnext",
    "useDefineForClassFields": true,
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",// 在.tsx文件里支持JSX
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "lib": [
      "esnext",
      "dom"
    ],
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  },
  "include": [
    "src/**/*.js",
    "src/**/*.ts",
    "src/**/*.d.ts",
    "src/**/*.tsx", // 在.tsx文件里支持JSX
    "src/**/*.jsx",
    "src/**/*.vue"
  ]
}

改造App.vueApp.tsx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
import HelloWorld from '@/components/HelloWorld.vue';
import {defineComponent} from 'vue';
import appClass from '@/styles/app.module.scss' // css modules
import logoImg from '@/assets/logo.png'; // static assets

// 用defineComponent定义组件且要导出
// noinspection JSXNamespaceValidation
export default defineComponent({
  render: () => (
    <>
      <img alt="Vue logo" src={logoImg}/>
      <HelloWorld msg="Hello Vue 3 + TypeScript + Vite"/>
      <router-link to="/">Go to Home</router-link>
      &nbsp;
      <router-link to="/about">Go to About</router-link>
      &nbsp;
      <router-view></router-view>
    </>
  ),
});
  • 运行命令pnpm dev查看效果

*.tsx文件中使用css modules

  • 只有在 *.tsx 文件中可以正常使用

配置vit.config.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import {defineConfig} from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path'; // @types/node
import vueJsx from '@vitejs/plugin-vue-jsx';
import ...

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),
    VueSetupExtend(),
    autoComponents({...}),
    AutoImport({...}),
  ],
  server: {...},
  resolve: {
    alias: {...},
  },
  css: {
    // 配置 css modules 的行为
    modules: {
      scopeBehaviour: 'local', // 作用域
      // generateScopedName: // 使用默认配置,
      localsConvention: 'camelCase', // 识别样式命名方式
    },
    preprocessorOptions: {
      scss: {
        additionalData: `...`,
      }
    }
  },
});

  • 定义一个 *.module.scss 或者 *.module.css 文件
    • 创建src/styles/app.module.scss
1
2
3
4
5
6
7
8
.app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
  • *.tsx 中引入使用
    • 改写App.tsx
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import HelloWorld from '@/components/HelloWorld.vue';
import {defineComponent} from 'vue';
import appClass from '@/styles/app.module.scss' // css modules
import logoImg from '@/assets/logo.png'; // static assets

// 用defineComponent定义组件且要导出
export default defineComponent({
  render: () => (
    <main class={appClass.app}>
      <img alt="Vue logo" src={logoImg}/>
      <HelloWorld msg="Hello Vue 3 + TypeScript + Vite"/>
      <router-link to="/">Go to Home</router-link>
      &nbsp;
      <router-link to="/about">Go to About</router-link>
      &nbsp;
      <router-view></router-view>
    </main>
  ),
});
  • 样式文件xxx.module.scss中定义类样式.yyy {...}
  • 引入到*.tsx文件后,在模板中使用<main class={xxx.yyy}>...</main>

如何优雅的在TSX语法中切换多个className

1
2
3
4
5
6
7
<div className={
    this.state.isHide?styles.hide+' ':''+
    this.state.isActive?styles.active+' ':''+
    this.state.isAlarm?styles.alarm+' ':''
    }>
    {...data}
</div>
  • 使用第三方包classnames
  • 安装pnpm add classnames
  • 引入import classname from 'classnames'

上述代码可替换为:

1
2
3
4
5
6
7
8
9
dataClass: {
    isHide: true,
    isActive: true,
    isAlarm: true
}

<div className={classname(dataClass)}>
    {...data}
</div>

或者使用数组

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// tsx
...
// multiClass
import classnames from 'classnames';

// CSS module
import basic from '@/styles/basic.module.scss';
import test1 from '@/styles/test1.module.scss';
import test2 from '@/styles/test2.module.scss';
const btnClass = [test1.test1, test2.test2]

export default defineComponent({
  name: 'BlogIndex',
  props: {},
  setup(/*props, ctx*/) {
    return {
    };
  },
  render() {
    return (
      <>
        <Button class={classnames(...btnClass, basic.blogBtn)}>
          博客首页
        </Button>
      </>
    );
  }

});

和普通样式写在一起

1
2
<section class={classNames([cssDetail.article, 'article'])}>
</section>

参考



参考文章

相关文章


  • 作者: Joel
  • 文章链接:
  • 版权声明
  • 非自由转载-非商用-非衍生-保持署名