Vue3 + ts 项目引入UnoCSS,并实现主题切换

中文文档:https://unocss-cn.pages.dev/

一. Unocss基本使用

1. 安装

npm install -D unocss

2. vite.config.ts中安装插件

// vite.config.ts
import UnoCSS from 'unocss/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    UnoCSS(),
  ],
})

3. 创建 uno.config.ts 文件:

// uno.config.ts
import { defineConfig } from 'unocss'

export default defineConfig({
  // ...UnoCSS options
})

默认情况下,UnoCSS 将自动查找项目根目录中的 uno.config.{js,ts,mjs,mts}unocss.config.{js,ts,mjs,mts}。您也可以手动指定配置文件,例如在 Vite 中:

// vite.config.ts
import { defineConfig } from 'vite'
import UnoCSS from 'unocss/vite'

export default defineConfig({
  plugins: [
    UnoCSS({
      configFile: '../my-uno.config.ts',
    }),
  ],
})

4. 将 virtual:uno.css 添加到主入口文件:

// main.ts
import 'virtual:uno.css'

5. 基本使用

以上步骤完成后即可在项目中随意使用类名啦,具体类名及样式可在https://unocss-cn.pages.dev/interactive/中搜索。

例:

二. 配置(link)

1. 预设

默认预设:presetUno

// uno.config.ts
import { defineConfig } from 'unocss'
import presetUno from '@unocss/preset-uno'

export default defineConfig({
  presets: [
    presetUno(),
  ],
  // presets: [], // 禁用默认 preset
})

该预设试图提供一种常见的实用程序优先框架的超集,包括 Tailwind CSS、Windi CSS、Bootstrap、Tachyons 等。

例如,ml-3(Tailwind CSS)、ms-2(Bootstrap)、ma4(Tachyons)和 mt-10px(Windi CSS)都是有效的。

.ma4 { margin: 1rem; }
.ml-3 { margin-left: 0.75rem; }
.ms-2 { margin-inline-start: 0.5rem; }
.mt-10px { margin-top: 10px; }

2. 规则

规则定义了实用类和生成的 CSS。UnoCSS 有许多内置规则,但也允许轻松添加自定义规则。

// uno.config.ts
import { defineConfig } from 'unocss'
import presetUno from '@unocss/preset-uno'

export default defineConfig({
  rules: [
    // 注意:属性语法遵循 CSS 属性语法,例如 font-weight 而不是 fontWeight。如果属性名中有连字符 -,应该用引号括起来。
    ['font-bold', { 'font-weight': 700 }],
    [/^bd-(\d+)$/, ([, d]) => ({ border: `${d}px solid #ddd` })],
    [/^p-(\d+)$/, (match) => ({ padding: `${match[1]}px` })],
    // 使用主题
    // [
    //   /^text-(.*)$/,
    //   ([, c], { theme }) => {
    //     if (theme.colors[c]) return { color: theme.colors[c] };
    //   },
    // ],
  ],
})

例如:每当在用户代码中检测到 bd-1 时,将生成以下 CSS:

.bd-1 { border: 1px solid #ddd }

3. 快捷方式

快捷方式允许您将多个规则组合成单个简写。

// uno.config.ts
import { defineConfig } from 'unocss'
import presetUno from '@unocss/preset-uno'

export default defineConfig({
  shortcuts: [
    {
      btn: 'py-2 px-4 font-semibold rounded-lg shadow-md cursor-pointer',
    },
    // 动态快捷方式
    [/^btn-(.*)$/, ([, c]) => `bg-${c} text-#fff hover:bg-${c}/80 py-2 px-4 font-semibold rounded-lg shadow-md cursor-pointer`],
    // 使用主题
    // [
    //   /^badge-(.*)$/,
    //   ([, c], { theme }) => {
    //     if (theme.colors[c]) return `bg-${c}:10 text-${c} rounded`;
    //   },
    // ],
  ],
})

例如:每当在用户代码中检测到 btn-blue 时,将生成以下 CSS:

.btn-blue {
    cursor: pointer;
    border-radius: 0.5rem;
    --un-bg-opacity: 1;
    background-color: rgb(96 165 250 / var(--un-bg-opacity));
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
    padding-left: 1rem;
    padding-right: 1rem;
    --un-text-opacity: 1;
    color: rgb(255 255 255 / var(--un-text-opacity));
    font-weight: 600;
    --un-shadow: var(--un-shadow-inset) 0 4px 6px -1px var(--un-shadow-color, rgb(0 0 0 / 0.1)), var(--un-shadow-inset) 0 2px 4px -2px var(--un-shadow-color, rgb(0 0 0 / 0.1));
    box-shadow: var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);
}

.btn-blue:hover {
    background-color: rgb(96 165 250 / 0.8);
}

4. 主题

// uno.config.ts
import { defineConfig } from 'unocss'
import presetUno from '@unocss/preset-uno'

export default defineConfig({
  theme: {
    colors: {
      myBg: {
        // class="bg-my-bg-1"
        1: '#CCFFFF',
        2: '#CCFFFF',
        3: '#99CCFF',
        4: '#3399CC',
      },
      myText: {
        // class="text-my-text-1"
        1: '#CCFFFF',
        3: '#99CCFF',
        2: '#003366',
      },
      myBorder: {
        // class="text-my-border-1"
        1: '#003366',
      },
    },
    // 当提供自定义 breakpoints 对象时,默认对象将被覆盖而不是合并。以下示例将只能使用 sm: md: lg:断点变体
    // 由于 uno 不支持不同单位大小的比较排序,请转换为相同单位。
    // breakpoints: {
    //   sm: '320px',
    //   md: `${40 * 16}px`,
    //   lg: '960px',
    // },
})
  <div class="bg-my-bg-2 p-40px">
    <span class="btn-primary" @click="count++">count is {{ count }}</span>
    <h1 class="bg-myBg-4 text-my-text-1">h1 h1 h1 h1 h1 h1 h1 h1 h1 h1 h1 h1</h1>
    <h2 class="mybd-my-border-1 text-my-text-2">h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2</h2>
    <span class="btn-my-bg-4">span 2</span>
  </div>

5. 转换器

指令转换器: transformerDirectives, 可以使用 @apply, theme() 在样式文件中更方便的使用自定义的主题色。

// uno.config.ts
import { defineConfig } from 'unocss'
import transformerDirectives from '@unocss/transformer-directives'

export default defineConfig({
  transformers: [
    transformerDirectives(),
  ],
})
html {
  background-color: theme('colors.myBg.1');
}

.btn-primary {
  @apply text-white bg-my-bg-3 cursor-pointer hover:bg-my-bg-3/80;
  //   --at-apply: 'text-white bg-my-bg-3 hover:bg-my-bg-3';  // css 写法
}

6. 白名单safelist

在使用转化器的 theme('colors.myBg.1'),发现colors.myBg.1没有生成对应的变量,所以样式不生效,但是在html, 或是css 中用到 XX-my-bg-1的类名时,变量则会生成。

由于 UnoCSS 在构建时使用静态提取工作,变量可能提取不到,所以使用safelist做特殊处理:

// uno.config.ts
import { defineConfig } from 'unocss'
import transformerDirectives from '@unocss/transformer-directives'

export default defineConfig({
  safelist: ['bg-myBg-1', 'bg-myBg-2'],
})

三. 主题切换

1. 安装

npm i -D unocss-preset-theme

2. 新建theme文件

export const myTheme = {
  default: {
    colors: {
      myBg: {
        1: '#eaf7f7',
        2: '#CCFFFF',
        3: '#99CCFF',
        4: '#3399CC',
      },
      myText: {
        1: '#CCFFFF',
        3: '#99CCFF',
        2: '#003366',
      },
      myBorder: {
        1: '#003366',
      },
    },
  },
  red: {
    colors: {
      myBg: {
        1: '#FFCCCC',
        2: '#FF9999',
        3: '#FF6666',
        4: '#FF0033',
      },
      myText: {
        1: '#FFCCCC',
        3: '#FF6666',
        2: '#FF0033',
      },
      myBorder: {
        1: '#FF0033',
      },
    },
  },
  yellow: {
    colors: {
      myBg: {
        1: '#FFFFCC',
        2: '#FFFF99',
        3: '#FFFF33',
        4: '#FFCC33',
      },
      myText: {
        1: '#FFFFCC',
        3: '#FFFF00',
        2: '#FF9900',
      },
      myBorder: {
        1: '#FF9900',
      },
    },
  },
};

export const safelist = () => {
  const arr: string[] = [];
  Object.keys(myTheme.default.colors).forEach((item) => arr.push(...Array.from({ length: 10 }, (_, i) => `bg-${item}-${i}`)));
  console.log(arr);

  return arr;
};

3. uno.config.ts引入presetTheme

presetTheme会自动生成对应主题的变量

    presetTheme<Theme>({
      theme: myTheme,
    }),

完整代码:

// uno.config.ts
import { defineConfig, transformerDirectives } from 'unocss';
import { presetUno } from 'unocss';
import type { Theme } from 'unocss/preset-uno';
import presetTheme from 'unocss-preset-theme';
import { myTheme, safelist } from './src/theme';

export default defineConfig({
  // 预设
  presets: [
    presetUno(),
    presetTheme<Theme>({
      theme: myTheme,
    }),
  ],
  // 快捷方式, 将多个规则组合成单个简写
  shortcuts: [
    {
      btn: 'py-2 px-4 font-semibold rounded-lg shadow-md cursor-pointer',
    },
    // 动态快捷方式
    [/^btn-(.*)$/, ([, c]) => `bg-${c} text-#fff hover:bg-${c}/80 py-2 px-4 font-semibold rounded-lg shadow-md cursor-pointer`],
    // 使用主题
    [
      /^mybd-(.*)$/,
      ([, c], { theme }) => {
        return `b-1 b-${c} b-dashed`;
      },
    ],
  ],
  // 自定义规则
  rules: [
    // 注意:属性语法遵循 CSS 属性语法,例如 font-weight 而不是 fontWeight。如果属性名中有连字符 -,应该用引号括起来。
    ['font-bold', { 'font-weight': 700 }],
    [/^bd-(\d+)$/, ([, d]) => ({ border: `${d}px solid #ddd` })],
    [/^p-(\d+)$/, (match) => ({ padding: `${match[1]}px` })],
  ],
  transformers: [
    transformerDirectives(),
  ],
  safelist: safelist() // 可以根据项目需要添加
});

4. App.vue添加主题切换

通过修改html的类名来实现主题切换,前面为了方便管理,我把uno.config.ts文件的主题配置给删掉了,全部移到了presetThemetheme属性里,默认在index.html文件的html元素上加了default类名。

// App.vue
<script setup lang="ts">
import { ref } from 'vue';
import HelloWorld from './components/HelloWorld.vue';

const radio = ref('default');

const onRadioChange = (e: string) => {
  document.documentElement.className = e;
};
</script>

<template>
  <el-radio-group v-model="radio" size="large" @change="onRadioChange">
    <el-radio-button label="default" value="default" />
    <el-radio-button label="red" value="red" />
    <el-radio-button label="yellow" value="yellow" />
  </el-radio-group>
  <div class="wrapper">
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
// index.html
<!DOCTYPE html>
<html lang="en" class="default">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue + TS</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

一个基本的主题切换功能到这就成功啦!!

引用\[1\]中的代码是使用Vue 3和BMapGL引入百度地图的示例。在Vue组件中,通过在`onMounted`钩子函数中初始化地图对象,并设置地图的中心点和缩放级别来实现地图的展示。需要注意的是,引入BMapGL时需要加上`window`,否则会报错。代码中还包括了设置地图样式和给地图容器设置宽高的部分。 引用\[2\]中的代码是使用Vue 3和Cesium引入三维地图的示例。在Vue组件中,通过在`onMounted`钩子函数中创建Cesium的Viewer对象,并将其绑定到指定的容器上。代码中还包括了引入Cesium的样式文件和给地图容器设置宽高的部分。 综上所述,如果你想在Vue 3 + TypeScript项目引入地图,可以根据具体的地图库选择相应的代码示例进行参考和使用。 #### 引用[.reference_title] - *1* [vue3+ts引入百度地图](https://blog.csdn.net/qq_41296021/article/details/124857647)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [基于Vue3+TS+Vite+Cesium创建项目](https://blog.csdn.net/qq_43066675/article/details/130118714)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值