React Native支持Tailwind CSS 语法
一、前沿背景
回想下我们平时按照官方的规范进行书写样式是什么样?
是像下面这样:
js
const MyComponent = () => {
return (
<View>
<Text style={{ fontSize: 20 }}>开发者演示专用</Text>
</View>
)
}
上面类似写法,我们会发现当样式很复杂的情况下,文件结构会变的很臃肿,而且在一定程度上降低开发效率。
那 Tailwind CSS
语法是什么?
形如下面class语法,通过语义化符号代替一系列css样式
w-24表示width:24px;
h-24表示height:24px;
p-8表示padding: 8px;
.......
html
<figure class="md:flex bg-slate-100 rounded-xl p-8 dark:bg-slate-800">
<img class="w-24 h-24 rounded-full mx-auto" src="/sarah-dayan.jpg" alt="" width="384" height="512">
<div class="pt-6 text-center space-y-4">
<blockquote>
<p class="text-lg font-medium">
React Native支持Tailwind CSS 语法
</p>
</blockquote>
<div class="text-sky-500 dark:text-sky-400">
Sarah
</div>
<div class="text-slate-700 dark:text-slate-500">
Staff
</div>
</div>
</figure>
-
Tailwind CSS是一个实用优先(utility-first)的CSS框架,它与传统的CSS框架如Bootstrap、Element UI等有所不同。
-
Tailwind CSS的核心理念是提供一套完整的、最小单位的工具类CSS,开发者可以直接在HTML中组合这些工具类来快速构建页面,而无需编写自定义的CSS。
-
使用Tailwind CSS,开发者可以直接在HTML中使用诸如"p-4"、"bg-white"、"flex"等语义化的工具类,这些类会被自动转换为对应的CSS属性。这种方式比传统的CSS编写更加直观和高效。
-
Tailwind CSS还提供了对响应式设计的良好支持,开发者可以在工具类中添加前缀如"sm:"、"md:"等,来针对不同屏幕尺寸设置不同的样式。这比传统的媒体查询写法更加简单。
-
Tailwind CSS还支持诸如hover、focus等状态类,以及深色模式等特性,使得样式的编写和维护更加方便。
总的来说,Tailwind CSS是一个新型的CSS框架,它通过提供大量的工具类来帮助开发者快速构建页面,同时也提供了良好的响应式支持和状态管理能力。它与传统的CSS框架有所不同,但能够大幅提高前端开发的效率。在web端,已经有了很成熟的使用,可以在这里看看官网说明,参考具体属性对应的简便写法:https://www.tailwindcss.cn/
遗憾的是官方并没有对React Native的支持。在React Native中使用Tailwind CSS并不是直接支持的方式,因为Tailwind CSS是一个针对Web开发的CSS框架,而React Native是用于原生移动应用开发的框架,两者并不直接兼容。就如开头的展示在React Native中,通常会使用内联样式或StyleSheet来定义组件的样式,而不是像Web开发中那样使用类名。
那我们想要实现这种写法该怎么办?
二、引入使用
其实从原理上讲,我们可以通过自己去制定一些映射语义化的规则,首先通过将整体的字符串分割出很多语义化小块,然后再一一映射出react-native 风格 style 的对象即可。
js
// 封装方法
const getTailWindCss = (styleString) => {
const styles = {};
const fieldMap = {
w: 'width',
h: 'height',
p: 'padding'
}
const tailWindCssLists = (styleString).split(' ');
console.log('tailWindCssLists', tailWindCssLists)
tailWindCssLists.forEach(item => {
const [field, value] = item.split('-');
styles[fieldMap[field]] = Number(value);
});
return styles;
}
// 实际调用
const tailWindCss = 'w-24 h-24 p-8';
const formatStyles = getTailWindCss(tailWindCss);
console.log('formatStyles', formatStyles)
这样,我们就实现了这种Tailwind Css
语义化的写法,但是如果我们自己做起来还是比较麻烦的;
继续探索全球程序员交友平台Github,最终发现了twrnc
。
可以使用twrnc
三方库支持语法,TailwindCSS + React Native的一个简单,用TypeScript编写的富有表现力的API实现。
Github地址:https://github.com/jaredh159/tailwind-react-native-classnames
集成到项目中之后,我们就能够像下面这样进行基础的使用:
js
import { View, Text } from 'react-native';
import tw from 'twrnc';
const MyComponent = () => (
<View style={tw`p-4 android:pt-2 bg-white dark:bg-black`}>
<Text style={tw`text-md text-black dark:text-white`}>Hello World</Text>
</View>
);
- 完全支持所有原生 RN 样式和 Tailwind 对应项:(视图、布局、图像、阴影和文本)。
- 与 Tailwind CSS v3 和 v2 兼容
- 基于 classnames 包 API 的灵活条件样式
- vw 和 vh 单位支持: h-screen min-w-screen w-[25vw] 等
- 暗模式支持: bg-white dark:bg-black
- 媒体查询支持:( w-48 lg:w-64 min-w-[600px]:flex-wrap )
- 设备方向前缀支持: portrait:flex-col landscape:flex-row
- 支持 tailwind.config.js 完整配置
- 支持平台处理,平台前缀: android:mt-4 ios:mt-2
等等...
三、原理深究
- tw`xxxx`到底做了什么事情?
首先我们回顾下es6里边的模版字符串语法
js
`string text`
`string text line 1
string text line 2`
`string text ${expression} string text`
tagFunction`string text ${expression} string text`
大家平时有没有用过第四种模版字符串,通过一个方法的函数调用模版字符串
下面这个是一个调用结果
带标签的模板是模板字面量的一种更高级的形式,它允许你使用函数解析模板字面量。标签函数的第一个参数包含一个字符串数组,其余的参数与表达式相关。你可以用标签函数对这些参数执行任何操作,并返回被操作过的字符串(或者,也可返回完全不同的内容)。用作标签的函数名没有限制。
从这里我们能够看到tw语法就是一个常规的模版字符串。
到这里我们其实可以基本去猜测下,tw其实只是将我们传入的字符串转换成了react-native中原生的样式,也就是我们最开始验证的猜想的转换方法getTailWindCss
:
我们也可以看看验证下tw执行后的返回值:
打印tw执行结果: console.log('tw style result', twflex justify-center items-center bg-[#eee] h-1 w-4
)
能够看到返回值如下:
这个返回值就是react-native原生的样式书写规则
四、更多特性说明
- tw.style
不仅仅最开始及上面描述的的基础用法,tw 还能够支持通过API tw.style进行classnames
风格使用
js
// pass multiple args
tw.style('text-sm', 'bg-blue-100', 'flex-row mb-2');
// arrays of classnames work too
tw.style(['text-sm', 'bg-blue-100']);
// falsy stuff is ignored, so you can do conditionals like this
tw.style(isOpen && 'bg-blue-100');
// { [className]: boolean } style - key class only added if value is `true`
tw.style({
'bg-blue-100': isActive,
'text-red-500': invalid,
});
// or, combine tailwind classes with plain react-native style object:
tw.style('bg-blue-100', { resizeMode: `repeat` });
// mix and match input styles as much as you want
tw.style('bg-blue-100', ['flex-row'], { 'text-xs': true }, { fontSize: 9 });
如果需要一些tw不支持的样式,或者只是想执行一些自定义运行时逻辑,则可以将原始 RN 样式对象传递给 tw.style() ,它们将与从任何其他实用程序类生成的样式合并:
js
tw.style(`mt-1`, {
resizeMode: `repeat`,
width: `${progress}%`,
});
// -> { marginTop: 4, resizeMode: 'repeat', width: '32%' }
- tailwind.config.js自定义配置:
js
import { create } from 'twrnc';
const tw = create(require('../../../tailwind.config.js'));
export default tw;
js
// tailwind.config.js
module.exports = {
content: ['./src/**/*.{js,jsx,ts,tsx}'],
theme: {
fontFamily: {},
screens: {
sm: '380px',
md: '420px',
lg: '680px',
// or maybe name them after devices for `tablet:flex-row`
tablet: '1024px',
},
},
plugins: []
}
- useDeviceContext
默认情况下,如果您按照上述方式使用 useDeviceContext() ,您的应用将响应设备配色方案(在系统偏好设置中设置)中的环境变化。如果您希望使用某种应用内机制显式控制应用的配色方案,则需要稍微以不同的方式进行配置。 - useAppColorScheme
获取系统的主题色,然后进行自定义主色配置
五、Vscode配置提示自动完成
增加vscode配置项setting.json,输入tw`能够自动提示tailwind语法,快速开发,明显的效率提升。
json
"tailwindCSS.experimental.classRegex": [
"tw`([^`]*)",
["tw.style\\(([^)]*)\\)", "'([^']*)'"]
],
"tailwindCSS.classAttributes": [
"style"
],