new_button.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. import { View, Text } from '@tarojs/components'
  2. import './new_button.scss'
  3. import { rpxToPx, vibrate } from '@/utils/tools';
  4. import { useState } from 'react';
  5. import { IconMore } from '@/components/basic/Icons';
  6. import { MainColorType } from '@/context/themes/color';
  7. export enum NewButtonType {
  8. fill = 'fill', //主题实色
  9. alpha = 'alpha', //主题半透明
  10. alpha2 = 'alpha2',
  11. border = 'border', //主题边框
  12. gray = 'gray', //灰色半透明
  13. text = 'text', //纯文本
  14. link = 'link', //超链接(有可能带icon)
  15. label = 'label',
  16. more = 'more',
  17. img = 'image'
  18. }
  19. function hexToHSL(hex) {
  20. // 去掉井号,处理3位和6位16进制
  21. hex = hex.replace(/^#/, '');
  22. if (hex.length === 3) {
  23. hex = hex.split('').map(char => char + char).join('');
  24. }
  25. // 解析RGB
  26. const r = parseInt(hex.slice(0, 2), 16) / 255;
  27. const g = parseInt(hex.slice(2, 4), 16) / 255;
  28. const b = parseInt(hex.slice(4, 6), 16) / 255;
  29. // 计算最大和最小值
  30. const max = Math.max(r, g, b);
  31. const min = Math.min(r, g, b);
  32. let h, s, l = (max + min) / 2;
  33. // 计算亮度
  34. if (max === min) {
  35. h = s = 0; // achromatic
  36. } else {
  37. const d = max - min;
  38. s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
  39. switch (max) {
  40. case r:
  41. h = (g - b) / d + (g < b ? 6 : 0);
  42. break;
  43. case g:
  44. h = (b - r) / d + 2;
  45. break;
  46. case b:
  47. h = (r - g) / d + 4;
  48. break;
  49. }
  50. h /= 6;
  51. }
  52. // 转换为度和百分比
  53. h = Math.round(h * 360);
  54. s = Math.round(s * 100);
  55. l = Math.round(l * 100);
  56. return `hsl(${h}, ${s}%, ${l - 10}%)`;
  57. }
  58. export default function NewButton(props: {
  59. type: NewButtonType,
  60. color?: string,
  61. title?: string,
  62. children?: any,
  63. disable?: boolean,
  64. loading?: boolean,
  65. onClick?: any,
  66. width?: number,
  67. height?: number,
  68. fontSize?: number,
  69. bold?: boolean,
  70. fontNormal?: boolean,
  71. labelBorder?: boolean,
  72. btnStyle?: any,
  73. }) {
  74. const [isTouched, setIsTouched] = useState(false)
  75. const [noTouch, setNoTouch] = useState(false)
  76. let style = {}
  77. switch (props.type) {
  78. case NewButtonType.fill:
  79. style = {
  80. height: props.height ?? rpxToPx(72),
  81. width: props.width ?? rpxToPx(198),
  82. borderRadius: props.height ? props.height / 4 : rpxToPx(72 / 4),
  83. backgroundColor: isTouched ? hexToHSL(props.color) : props.disable ? '#B2B2B2' : props.color,
  84. color: '#fff',
  85. fontSize: props.fontSize ?? rpxToPx(30),
  86. fontWeight: props.fontNormal ? 'normal' : 'bold',//props.bold ? 'bold' : 'normal',
  87. display: 'flex',
  88. alignItems: 'center',
  89. justifyContent: 'center',
  90. opacity: props.disable ? 0.6 : 1,
  91. }
  92. break
  93. case NewButtonType.alpha:
  94. style = {
  95. height: props.height ?? rpxToPx(72),
  96. width: props.width ?? rpxToPx(198),
  97. borderRadius: props.height ? props.height / 4 : rpxToPx(72 / 4),
  98. backgroundColor: isTouched ? props.color + '40' : props.disable ? '#B2B2B240' : props.color + '1A',
  99. color: props.disable ? '#b2b2b2' : props.color,
  100. fontSize: props.fontSize ?? rpxToPx(30),
  101. fontWeight: props.fontNormal ? 'normal' : 'bold',//props.bold ? 'bold' : 'normal',
  102. display: 'flex',
  103. alignItems: 'center',
  104. justifyContent: 'center',
  105. opacity: props.disable ? 0.6 : 1,
  106. }
  107. break;
  108. case NewButtonType.alpha2:
  109. style = {
  110. height: props.height ?? rpxToPx(72),
  111. width: props.width ?? rpxToPx(198),
  112. borderRadius: props.height ? props.height / 4 : rpxToPx(72 / 4),
  113. backgroundColor: isTouched ? MainColorType.g02 + '4d' : MainColorType.g02 + '1a',
  114. color: props.disable ? '#b2b2b2' : props.color,
  115. fontSize: props.fontSize ?? rpxToPx(30),
  116. fontWeight: props.fontNormal ? 'normal' : 'bold',//props.bold ? 'bold' : 'normal',
  117. display: 'flex',
  118. alignItems: 'center',
  119. justifyContent: 'center',
  120. opacity: props.disable ? 0.6 : 1,
  121. }
  122. break;
  123. case NewButtonType.border:
  124. style = {
  125. height: props.height ?? rpxToPx(72),
  126. width: props.width ?? rpxToPx(198),
  127. borderWidth: rpxToPx(2),
  128. borderColor: props.disable ? '#B2B2B2' : props.color,
  129. borderStyle: 'solid',
  130. borderRadius: props.height ? props.height / 4 : rpxToPx(72 / 4),
  131. backgroundColor: isTouched ? props.color + '26' : 'transparent',
  132. color: props.disable ? '#b2b2b2' : props.color,
  133. fontSize: props.fontSize ?? rpxToPx(30),
  134. fontWeight: props.fontNormal ? 'normal' : 'bold',//props.bold ? 'bold' : 'normal',
  135. display: 'flex',
  136. alignItems: 'center',
  137. justifyContent: 'center',
  138. opacity: props.disable ? 0.6 : 1,
  139. boxSizing: 'border-box'
  140. }
  141. break;
  142. case NewButtonType.gray:
  143. style = {
  144. height: props.height ?? rpxToPx(72),
  145. minWidth: props.width ?? rpxToPx(198),
  146. paddingLeft: props.width ? 0 : 15,
  147. paddingRight: props.width ? 0 : 15,
  148. borderRadius: props.height ? props.height / 4 : rpxToPx(72 / 4),
  149. backgroundColor: isTouched ? '#b2b2b240' : '#b2b2b210',
  150. color: props.disable ? '#b2b2b2' : '#000000',
  151. fontSize: props.fontSize ?? rpxToPx(30),
  152. fontWeight: props.fontNormal ? 'normal' : 'bold',//props.bold ? 'bold' : 'normal',
  153. display: 'flex',
  154. alignItems: 'center',
  155. justifyContent: 'center',
  156. boxSizing: 'border-box',
  157. // opacity: props.disable ? 0.6 : 1,
  158. }
  159. // style = {
  160. // height: props.height ?? rpxToPx(72),
  161. // width: props.width ?? rpxToPx(198),
  162. // borderRadius: props.height ? props.height / 4 : rpxToPx(72 / 4),
  163. // backgroundColor: isTouched ? '#9999991A' : 'transparent',
  164. // color: props.disable ? '#999999' : '#999999',
  165. // fontSize: props.fontSize ?? rpxToPx(30),
  166. // display: 'flex',
  167. // alignItems: 'center',
  168. // justifyContent: 'center',
  169. // // opacity: props.disable ? 0.6 : 1,
  170. // }
  171. break
  172. case NewButtonType.text:
  173. style = {
  174. height: props.height ?? rpxToPx(72),
  175. width: props.width ?? rpxToPx(198),
  176. borderRadius: props.height ? props.height / 4 : rpxToPx(72 / 4),
  177. backgroundColor: props.disable ? '#B2B2B240' : isTouched ? '#B2B2B240' : '#B2B2B21A',
  178. color: props.disable ? '#b2b2b2' : '#000',
  179. fontSize: props.fontSize ?? rpxToPx(30),
  180. fontWeight: props.fontNormal ? 'normal' : 'bold',
  181. display: 'flex',
  182. alignItems: 'center',
  183. justifyContent: 'center',
  184. }
  185. break;
  186. case NewButtonType.link:
  187. style = {
  188. display: 'flex',
  189. alignItems: 'center',
  190. justifyContent: 'center',
  191. flexDirection: 'row',
  192. flex: 1,
  193. color: props.color?props.color:'#5C7099',
  194. fontSize: props.fontSize ? props.fontSize : rpxToPx(26),
  195. opacity: isTouched ? 0.4 : 1,
  196. }
  197. break
  198. case NewButtonType.label:
  199. style = {
  200. ...props.btnStyle,
  201. height: rpxToPx(64),
  202. borderRadius: rpxToPx(32),
  203. display: 'flex',
  204. flexDirection: 'row',
  205. alignItems: 'center',
  206. justifyContent: 'center',
  207. fontSize: rpxToPx(28),
  208. fontWeight: props.fontNormal ? 'normal' : 'bold',
  209. paddingLeft: rpxToPx(24),
  210. paddingRight: rpxToPx(24),
  211. boxSizing: 'border-box',
  212. backgroundColor: isTouched ? '#5C709940' : props.labelBorder ? 'transparent' : '#5C70991A',
  213. borderWidth: rpxToPx(2),
  214. borderColor: props.labelBorder ? '#5C709940' : 'transparent',
  215. borderStyle: 'solid',
  216. color: '#5C7099'
  217. }
  218. break
  219. case NewButtonType.more:
  220. return <View style={{
  221. ...props.btnStyle,
  222. width: rpxToPx(74),
  223. height: rpxToPx(44),
  224. display: 'flex',
  225. alignItems: 'center',
  226. justifyContent: 'center',
  227. borderRadius: rpxToPx(11),
  228. backgroundColor: isTouched ? MainColorType.g02 + '4d' : MainColorType.g02 + '1a'
  229. }}
  230. catchMove
  231. onClick={(e) => {
  232. if (process.env.TARO_ENV == 'weapp') {
  233. e.stopPropagation()
  234. }
  235. if (props.disable) {
  236. vibrate();
  237. return;
  238. }
  239. if (noTouch) return;
  240. props.onClick()
  241. setNoTouch(true)
  242. setTimeout(() => {
  243. setNoTouch(false)
  244. }, 500)
  245. }}
  246. onTouchStart={(e) => {
  247. if (process.env.TARO_ENV == 'weapp') {
  248. e.stopPropagation()
  249. }
  250. if (props.disable) return
  251. setIsTouched(true)
  252. }}
  253. onTouchEnd={(e) => {
  254. if (process.env.TARO_ENV == 'weapp') {
  255. e.stopPropagation()
  256. }
  257. setIsTouched(false)
  258. }}
  259. >
  260. <IconMore color={MainColorType.link} width={rpxToPx(34)} />
  261. </View>
  262. case NewButtonType.img:
  263. return <View style={{ opacity: isTouched ? 0.6 : 1, ...props.btnStyle, display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={(e) => {
  264. if (process.env.TARO_ENV == 'weapp') {
  265. e.stopPropagation()
  266. }
  267. if (props.disable) {
  268. vibrate();
  269. return;
  270. }
  271. if (noTouch) return;
  272. props.onClick()
  273. setNoTouch(true)
  274. setTimeout(() => {
  275. setNoTouch(false)
  276. }, 500)
  277. }}
  278. onTouchStart={(e) => {
  279. if (process.env.TARO_ENV == 'weapp') {
  280. e.stopPropagation()
  281. }
  282. if (props.disable) {
  283. return;
  284. }
  285. setIsTouched(true)
  286. }}
  287. onTouchEnd={(e) => {
  288. if (process.env.TARO_ENV == 'weapp') {
  289. e.stopPropagation()
  290. }
  291. setIsTouched(false)
  292. }}>
  293. {props.children}
  294. </View>
  295. }
  296. return <View
  297. style={{ ...style, ...props.btnStyle, display: 'flex', flexDirection: 'row', alignItems: 'center' }}
  298. catchMove
  299. onClick={(e) => {
  300. if (process.env.TARO_ENV == 'weapp') {
  301. e.stopPropagation()
  302. }
  303. if (props.disable) {
  304. vibrate();
  305. return;
  306. }
  307. if (noTouch) return;
  308. props.onClick()
  309. setNoTouch(true)
  310. setTimeout(() => {
  311. setNoTouch(false)
  312. }, 500)
  313. }}
  314. onTouchStart={(e) => {
  315. if (process.env.TARO_ENV == 'weapp') {
  316. e.stopPropagation()
  317. }
  318. if (props.disable) return
  319. setIsTouched(true)
  320. }}
  321. onTouchEnd={(e) => {
  322. if (process.env.TARO_ENV == 'weapp') {
  323. e.stopPropagation()
  324. }
  325. setIsTouched(false)
  326. }}
  327. >{props.children}{props.title}</View>
  328. }