【uniapp】---- 在 HBuilderX 中使用 tailwindcss
1. 前言
接手了一个uniapp的微信小程序项目,因为在上一个 taro 的项目中使用的 tailwindcss,感觉比较方便,又不想动项目中原来的代码,因此就配置 tailwindcss,在新创建的子包中使用。
2. 分析
vue2 版本的 uni-app 内置的 webpack 版本为 4 , postcss 版本为 7, 所以还是只能使用 @tailwindcss/postcss7-compat 版本。
3. package.json
新建一个vue2 uni-app项目,然后我们 npm init -y 在项目根目录创建一个 package.json,并安装依赖。
3.1 添加依赖
perl
"autoprefixer": "9",
"postcss": "7",
"postcss-rem-to-responsive-pixel": "^5.1.3",
"tailwindcss": "npm:@tailwindcss/postcss7-compat",
"weapp-tailwindcss-webpack-plugin": "^1.6.8",
"webpack": "npm:webpack@webpack-4"
3.2 原项目配置结果

4. vue.config.js
在 vue.config.js 文件,注册 weapp-tailwindcss-webpack-plugin。
4.1 注册
arduino
// 为了 tailwindcss jit 开发时的热更新
if (process.env.NODE_ENV === "development") {
process.env.TAILWIND_MODE = "watch";
}
const {
UniAppWeappTailwindcssWebpackPluginV4,
} = require("weapp-tailwindcss-webpack-plugin");
/**
* @type {import('@vue/cli-service').ProjectOptions}
*/
const config = {
//....
configureWebpack: {
plugins: [new UniAppWeappTailwindcssWebpackPluginV4()],
},
//....
};
module.exports = config;
4.2 注册结果

5. tailwind.config.js
5.1 配置 tailwind.config.js
css
const path = require("path");
const resolve = (p) => {
return path.resolve(__dirname, p);
};
/** @type {import('@types/tailwindcss/tailwind-config').TailwindConfig} */
module.exports = {
mode: "jit",
purge: {
content: [
resolve("./index.html"),
resolve("./pages/**/*.{vue,js,ts,jsx,tsx,wxml}"),
],
},
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {},
plugins: [],
corePlugins: {
preflight: false,
},
};
content 也必须为绝对路径。
5.2 配置结果

6. postcss.config.js
6.1 配置 postcss.config.js
lua
const path = require("path");
module.exports = {
plugins: [
require("autoprefixer")({
remove: process.env.UNI_PLATFORM !== "h5",
}),
require("tailwindcss")({
config: path.resolve(__dirname, "./tailwind.config.js"),
}),
// rem 转 rpx
require("postcss-rem-to-responsive-pixel/postcss7")({
rootValue: 32,
propList: ["*"],
transformUnit: "rpx",
}),
],
};
这里特别注意,在声明所有路径时,必须声明为绝对路径!!! 因为 hbuilderx 有这样一个读取配置的策略:如果目标目录是相对路径,就会读取 '\HBuilderX\plugins\uniapp-cli' 目录下的文件,这直接导致配置找不到,导致项目无法启动。
6.2 配置结果

7. 引入 tailwindcss
在 App.vue 引入即可:
7.1 App.vue 引入 tailwindcss
xml
<style lang="scss">
/*每个页面公共css */
@import "tailwindcss/base";
@import "tailwindcss/utilities";
</style>
7.2 引入结果

8. 运行结果
8.1 测试代码

8.2 运行效果

9. 总结
- 由于这是接手的一个比较老的项目,使用的是 vue2,所以这里是按照 vue2版本配置的 tailwindcss。
- 参考 在 HBuilderX 中使用 tailwindcss。
- 如果只到这里的话,就是转载了大佬的文章,必定我也没有写自己的东西,所以接下来就说说这么配置的还需要的优化。
10. 优化
- m-* 、p-、size- 等都不支持 [22rpx_30rpx] 这种拼接的值,这也就是导致在设置 border 这些的时候如果使用 tailwindcss 会比较麻烦,注意我这里说的是按照上边这样配置后出现的问题,不是说 tailwindcss 本身存在这种问题,因此为了解决这个问题,需要我们自己写一些 class。
- 就是限制显示多少行,需要单独安装插件,不能直接使用,tailwindcss-line-clamp,当然如果没有第一步的问题,那么我也就直接安装 tailwindcss-line-clamp 来解决问题,但是我这里第一步需要自己搞,所以就一起配置了。
11. 解决第一个问题
11.1 引入 tailwindcss/plugin
ini
const plugin = require('tailwindcss/plugin');
11.2 修改 plugins 配置
- 为了不和 size-* 冲突,因此此处同时设置宽高使用的是 wh-*;
- 由于 wh-[20rpx_50rpx] 中的单位 rpx 占位比较多,因此新增 value = value.split("").map(item =>
${item}rpx
).join(""); 逻辑,兼容 wh-[20_50] 的实现效果一样,当然这只是在我自己的项目中,可以这样缩写,比如设置边框,圆角我使用的是 b-* 、 bd-* ,但是不建议这么些,主要是意义不明确,不利于其他人使用,因此这里的设置基本都是为了方便我自己开发使用,你可以根据原理和自己的习惯来配置,方便更加快速的开发。
javascript
plugin(({ matchUtilities, theme }) => {
matchUtilities(
{
'wh': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
const [width, height] = value.split("_");
return { width, height: height || value }
},
'bb': (value) => {
value = value.replace(/_/g," ");
return {
"border-bottom": value
}
},
'b': (value) => {
value = value.replace(/_/g," ");
return {
"border": value
}
},
'bt': (value) => {
value = value.replace(/_/g," ");
return {
"border-top": value
}
},
'bd': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
value = value.replace(/_/g," ");
return {
"border-radius": value
}
},
'tc': (value) => {
const [size, color] = value.split("_");
return {
"font-size": size,
color
}
},
'rm': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
const margin = value.replace(/_/g," ");
return {margin}
},
'rp': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
const padding = value.replace(/_/g," ");
return {padding}
},
'fw': (value) => {
return {"font-weight": value}
},
},
{
values: theme('spacing'), // 使用 Tailwind 默认的 spacing 值
type: 'any', // 支持任意值
}
);
})
11.3 修改后的完整配置
javascript
const plugin = require('tailwindcss/plugin');
const path = require("path");
const resolve = (p) => {
return path.resolve(__dirname, p);
};
/** @type {import('@types/tailwindcss/tailwind-config').TailwindConfig} */
module.exports = {
mode: "jit",
purge: {
content: [
resolve("./index.html"),
resolve("./pages/**/*.{vue,js,ts,jsx,tsx,wxml}"),
],
},
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {},
plugins: [
plugin(({ matchUtilities, theme }) => {
matchUtilities(
{
'wh': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
const [width, height] = value.split("_");
return { width, height: height || value }
},
'bb': (value) => {
value = value.replace(/_/g," ");
return {
"border-bottom": value
}
},
'b': (value) => {
value = value.replace(/_/g," ");
return {
"border": value
}
},
'bt': (value) => {
value = value.replace(/_/g," ");
return {
"border-top": value
}
},
'bd': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
value = value.replace(/_/g," ");
return {
"border-radius": value
}
},
'tc': (value) => {
const [size, color] = value.split("_");
return {
"font-size": size,
color
}
},
'rm': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
const margin = value.replace(/_/g," ");
return {margin}
},
'rp': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
const padding = value.replace(/_/g," ");
return {padding}
},
'fw': (value) => {
return {"font-weight": value}
},
},
{
values: theme('spacing'), // 使用 Tailwind 默认的 spacing 值
type: 'any', // 支持任意值
}
);
})
],
corePlugins: {
preflight: false,
},
};
11.4 使用
css
<view class="bg-[#FFF0DF] tc-[24rpx_#EC8600] h-[42rpx] cc rp-[0_12] bd-[4] flex-none">招人</view>
11.5 效果

12. 解决限制行数
12.1 配置 theme
css
theme: {
extend: {
lineClamp: {
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
}
},
}
12.2 plugins 配置
注意:values 的配置,就是第一步中的 theme('lineClamp')!!!
javascript
plugin(({ matchUtilities, theme }) => {
matchUtilities({
'limit': (value) => {
return {
"overflow": "hidden",
"text-overflow": "ellipsis",
"display": "box",
"display": "-webkit-box",
"-webkit-line-clamp": `${value}`,
"-webkit-box-orient": "vertical"
}
}
},{
values: theme('lineClamp'), // 使用 Tailwind 默认的 spacing 值
type: 'any', // 支持任意值
});
})
12.3 两个问题的完整配置
javascript
const path = require("path");
const resolve = (p) => {
return path.resolve(__dirname, p);
};
const plugin = require('tailwindcss/plugin');
/** @type {import('@types/tailwindcss/tailwind-config').TailwindConfig} */
module.exports = {
mode: "jit",
purge: {
content: [
resolve("./index.html"),
resolve("./pages/**/*.{vue,js,ts,jsx,tsx,wxml}"),
],
},
darkMode: false, // or 'media' or 'class'
theme: {
extend: {
lineClamp: {
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
}
},
},
variants: {},
plugins: [
plugin(({ matchUtilities, theme }) => {
matchUtilities(
{
'wh': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
const [width, height] = value.split("_");
return { width, height: height || value }
},
'bb': (value) => {
value = value.replace(/_/g," ");
return {
"border-bottom": value
}
},
'b': (value) => {
value = value.replace(/_/g," ");
return {
"border": value
}
},
'bt': (value) => {
value = value.replace(/_/g," ");
return {
"border-top": value
}
},
'bd': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
value = value.replace(/_/g," ");
return {
"border-radius": value
}
},
'tc': (value) => {
const [size, color] = value.split("_");
return {
"font-size": size,
color
}
},
'rm': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
const margin = value.replace(/_/g," ");
return {margin}
},
'rp': (value) => {
if(!value.includes("rpx")){
value = value.split("_").map(item => `${item}rpx`).join("_");
}
const padding = value.replace(/_/g," ");
return {padding}
},
'fw': (value) => {
return {"font-weight": value}
},
},
{
values: theme('spacing'), // 使用 Tailwind 默认的 spacing 值
type: 'any', // 支持任意值
}
);
}),
plugin(({ matchUtilities, theme }) => {
matchUtilities({
'limit': (value) => {
return {
"overflow": "hidden",
"text-overflow": "ellipsis",
"display": "box",
"display": "-webkit-box",
"-webkit-line-clamp": `${value}`,
"-webkit-box-orient": "vertical"
}
},
},{
values: theme('lineClamp'), // 使用 Tailwind 默认的 spacing 值
type: 'any', // 支持任意值
});
}),
],
corePlugins: {
preflight: false,
},
};
12.4 效果

13. 总结
- 解决办法不一定是最好的,但是是我当前使用比较快的解决办法,也解决了我的问题;
- 真心不建议像我这么简写,除了我自己知道是干啥的,其他开发根本就看不懂,但是没办法,我又是比较懒的人,就将我常用的样式这么简化了,按照自己的需求来,特别是多人开发的大项目,千万不要我这么搞,我这个就我自己玩玩没事,也没人找我,你如果多人开发,小心项目经历拿砍刀来找你。