You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

578 lines
23 KiB

  1. <template>
  2. <!-- #ifndef APP-NVUE -->
  3. <button
  4. :hover-start-time="Number(hoverStartTime)"
  5. :hover-stay-time="Number(hoverStayTime)"
  6. :form-type="formType"
  7. :open-type="openType"
  8. :app-parameter="appParameter"
  9. :hover-stop-propagation="hoverStopPropagation"
  10. :send-message-title="sendMessageTitle"
  11. :send-message-path="sendMessagePath"
  12. :lang="lang"
  13. :data-name="dataName"
  14. :session-from="sessionFrom"
  15. :send-message-img="sendMessageImg"
  16. :show-message-card="showMessageCard"
  17. @getphonenumber="getphonenumber"
  18. @getuserinfo="getuserinfo"
  19. @error="error"
  20. @opensetting="opensetting"
  21. @launchapp="launchapp"
  22. @agreeprivacyauthorization="agreeprivacyauthorization"
  23. :hover-class="!disabled && !loading ? 'u-button--active' : ''"
  24. class="u-button u-reset-button"
  25. :style="[baseColor, addStyle(customStyle)]"
  26. @tap="clickHandler"
  27. :class="bemClass"
  28. >
  29. <template v-if="loading">
  30. <u-loading-icon
  31. :mode="loadingMode"
  32. :size="loadingSize * 1.15"
  33. :color="loadingColor"
  34. ></u-loading-icon>
  35. <text
  36. class="u-button__loading-text"
  37. :style="[{ fontSize: textSize + 'px' }]"
  38. >{{ loadingText || text }}</text
  39. >
  40. </template>
  41. <template v-else>
  42. <up-icon
  43. v-if="icon"
  44. :name="icon"
  45. :color="iconColorCom"
  46. :size="textSize * 1.35"
  47. :customStyle="{ marginRight: '2px' }"
  48. ></up-icon>
  49. <slot>
  50. <text
  51. class="u-button__text"
  52. :style="[{ fontSize: textSize + 'px' }]"
  53. >{{ text }}</text
  54. >
  55. </slot>
  56. </template>
  57. </button>
  58. <!-- #endif -->
  59. <!-- #ifdef APP-NVUE -->
  60. <view
  61. :hover-start-time="Number(hoverStartTime)"
  62. :hover-stay-time="Number(hoverStayTime)"
  63. class="u-button"
  64. :hover-class="
  65. !disabled && !loading && !color && (plain || type === 'info')
  66. ? 'u-button--active--plain'
  67. : !disabled && !loading && !plain
  68. ? 'u-button--active'
  69. : ''
  70. "
  71. @tap="clickHandler"
  72. :class="bemClass"
  73. :style="[baseColor, addStyle(customStyle)]"
  74. >
  75. <template v-if="loading">
  76. <u-loading-icon
  77. :mode="loadingMode"
  78. :size="loadingSize * 1.15"
  79. :color="loadingColor"
  80. ></u-loading-icon>
  81. <text
  82. class="u-button__loading-text"
  83. :style="[nvueTextStyle]"
  84. :class="[plain && `u-button__text--plain--${type}`]"
  85. >{{ loadingText || text }}</text
  86. >
  87. </template>
  88. <template v-else>
  89. <up-icon
  90. v-if="icon"
  91. :name="icon"
  92. :color="iconColorCom"
  93. :size="textSize * 1.35"
  94. ></up-icon>
  95. <text
  96. class="u-button__text"
  97. :style="[
  98. {
  99. marginLeft: icon ? '2px' : 0,
  100. },
  101. nvueTextStyle,
  102. ]"
  103. :class="[plain && `u-button__text--plain--${type}`]"
  104. >{{ text }}</text
  105. >
  106. </template>
  107. </view>
  108. <!-- #endif -->
  109. </template>
  110. <script lang="ts">
  111. import { buttonMixin } from "../../libs/mixin/button";
  112. import { openType } from "../../libs/mixin/openType";
  113. import { mpMixin } from '../../libs/mixin/mpMixin';
  114. import { mixin } from '../../libs/mixin/mixin';
  115. import { props } from "./props";
  116. import { addStyle } from '../../libs/function/index';
  117. import { throttle } from '../../libs/function/throttle';
  118. import { getThemeVar } from '../../libs/theme/runtime.js';
  119. /**
  120. * button 按钮
  121. * @description Button 按钮
  122. * @tutorial https://uview-plus.jiangruyi.com/components/button.html
  123. *
  124. * @property {Boolean} hairline 是否显示按钮的细边框 (默认 true )
  125. * @property {String} type 按钮的预置样式,info,primary,error,warning,success (默认 'info' )
  126. * @property {String} size 按钮尺寸,large,normal,mini (默认 normal)
  127. * @property {String} shape 按钮形状,circle(两边为半圆),square(带圆角) (默认 'square' )
  128. * @property {Boolean} plain 按钮是否镂空,背景色透明 (默认 false)
  129. * @property {Boolean} disabled 是否禁用 (默认 false)
  130. * @property {Boolean} loading 按钮名称前是否带 loading 图标(App-nvue 平台,在 ios 上为雪花,Android上为圆圈) (默认 false)
  131. * @property {String | Number} loadingText 加载中提示文字
  132. * @property {String} loadingMode 加载状态图标类型 (默认 'spinner' )
  133. * @property {String | Number} loadingSize 加载图标大小 (默认 15 )
  134. * @property {String} openType 开放能力,具体请看uniapp稳定关于button组件部分说明
  135. * @property {String} formType 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
  136. * @property {String} appParameter 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效 (注:只微信小程序、QQ小程序有效)
  137. * @property {Boolean} hoverStopPropagation 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效(默认 true )
  138. * @property {String} lang 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文(默认 en )
  139. * @property {String} sessionFrom 会话来源,openType="contact"时有效
  140. * @property {String} sendMessageTitle 会话内消息卡片标题,openType="contact"时有效
  141. * @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径,openType="contact"时有效
  142. * @property {String} sendMessageImg 会话内消息卡片图片,openType="contact"时有效
  143. * @property {Boolean} showMessageCard 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效(默认false)
  144. * @property {String} dataName 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
  145. * @property {String | Number} throttleTime 节流,一定时间内只能触发一次 (默认 0 )
  146. * @property {String | Number} hoverStartTime 按住后多久出现点击态,单位毫秒 (默认 0 )
  147. * @property {String | Number} hoverStayTime 手指松开后点击态保留时间,单位毫秒 (默认 200 )
  148. * @property {String | Number} text 按钮文字,之所以通过props传入,是因为slot传入的话(注:nvue中无法控制文字的样式)
  149. * @property {String} icon 按钮图标
  150. * @property {String} iconColor 按钮图标颜色
  151. * @property {String} color 按钮颜色,支持传入linear-gradient渐变色
  152. * @property {Object} customStyle 定义需要用到的外部样式
  153. *
  154. * @event {Function} click 非禁止并且非加载中,才能点击
  155. * @event {Function} getphonenumber open-type="getPhoneNumber"时有效
  156. * @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo
  157. * @event {Function} error 当使用开放能力时,发生错误的回调
  158. * @event {Function} opensetting 在打开授权设置页并关闭后回调
  159. * @event {Function} launchapp 打开 APP 成功的回调
  160. * @event {Function} agreeprivacyauthorization 用户同意隐私协议事件回调
  161. * @example <u-button>月落</u-button>
  162. */
  163. export default {
  164. name: "u-button",
  165. // #ifdef MP
  166. mixins: [mpMixin, mixin, buttonMixin, openType, props],
  167. // #endif
  168. // #ifndef MP
  169. mixins: [mpMixin, mixin, props],
  170. // #endif
  171. data() {
  172. return {};
  173. },
  174. computed: {
  175. // 生成bem风格的类名
  176. bemClass() {
  177. // this.bem为一个computed变量,在mixin中
  178. if (!this.color) {
  179. return this.bem(
  180. "button",
  181. ["type", "shape", "size"],
  182. ["disabled", "plain", "hairline"]
  183. );
  184. } else {
  185. // 由于nvue的原因,在有color参数时,不需要传入type,否则会生成type相关的类型,影响最终的样式
  186. return this.bem(
  187. "button",
  188. ["shape", "size"],
  189. ["disabled", "plain", "hairline"]
  190. );
  191. }
  192. },
  193. isDarkTheme() {
  194. return this.$u.theme && this.$u.theme.mode === 'dark';
  195. },
  196. nvueMainColor() {
  197. return this.resolveNvueColor(this.$u.color.mainColor, this.isDarkTheme ? '#f5f5f5' : '#303133');
  198. },
  199. nvueBorderColor() {
  200. return this.resolveNvueColor(this.$u.color.borderColor, this.isDarkTheme ? '#3a3a3c' : '#dadbde');
  201. },
  202. themeTypeColor() {
  203. const fallbackMap = {
  204. primary: '#3c9cff',
  205. success: '#5ac725',
  206. warning: '#f9ae3d',
  207. error: '#f56c6c',
  208. info: '#909399',
  209. };
  210. const type = fallbackMap[this.type] ? this.type : 'info';
  211. return this.resolveNvueColor(
  212. this.upThemeVar(`--up-${type}`, fallbackMap[type]),
  213. fallbackMap[type]
  214. );
  215. },
  216. nvueInfoBackgroundColor() {
  217. return this.upThemeVar(
  218. '--up-button-info-background-color',
  219. this.upThemeVar(
  220. '--up-card-bg-color',
  221. this.isDarkTheme ? '#1c1c1e' : '#ffffff'
  222. )
  223. );
  224. },
  225. nvuePlainBackgroundColor() {
  226. return this.upThemeVar(
  227. '--up-button-plain-background-color',
  228. this.upThemeVar(
  229. '--up-card-bg-color',
  230. this.isDarkTheme ? '#1c1c1e' : '#ffffff'
  231. )
  232. );
  233. },
  234. loadingColor() {
  235. if (this.plain) {
  236. // 如果有设置color值,则用color值,否则使用type主题颜色
  237. return this.color
  238. ? this.color
  239. : this.themeTypeColor;
  240. }
  241. if (this.type === "info") {
  242. return this.isDarkTheme ? "#9ca3af" : "#c9c9c9";
  243. }
  244. return "rgb(200, 200, 200)";
  245. },
  246. iconColorCom() {
  247. // 如果是镂空状态,设置了color就用color值,否则使用主题颜色,
  248. // up-icon的color能接受一个主题颜色的值
  249. if (this.iconColor) return this.iconColor;
  250. if (this.plain) {
  251. return this.color ? this.color : this.type;
  252. } else {
  253. return this.type === "info" ? this.nvueMainColor : "#ffffff";
  254. }
  255. },
  256. baseColor() {
  257. let style = {};
  258. if (this.color) {
  259. // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
  260. style.color = this.plain ? this.color : "white";
  261. if (!this.plain) {
  262. // 非镂空,背景色使用自定义的颜色
  263. style["background-color"] = this.color;
  264. }
  265. if (this.color.indexOf("gradient") !== -1) {
  266. // 如果自定义的颜色为渐变色,不显示边框,以及通过backgroundImage设置渐变色
  267. // weex文档说明可以写borderWidth的形式,为什么这里需要分开写?
  268. // 因为weex是阿里巴巴为了部门业绩考核而做的你懂的东西,所以需要这么写才有效
  269. style.borderTopWidth = 0;
  270. style.borderRightWidth = 0;
  271. style.borderBottomWidth = 0;
  272. style.borderLeftWidth = 0;
  273. if (!this.plain) {
  274. style.backgroundImage = this.color;
  275. }
  276. } else {
  277. // 非渐变色,则设置边框相关的属性
  278. style.borderColor = this.color;
  279. style.borderWidth = "1px";
  280. style.borderStyle = "solid";
  281. }
  282. return style;
  283. }
  284. // #ifdef APP-NVUE
  285. const typeColor = this.themeTypeColor;
  286. if (this.plain) {
  287. style.color = this.type === 'info' ? this.nvueMainColor : typeColor;
  288. style.backgroundColor = this.nvuePlainBackgroundColor;
  289. style.borderColor = this.type === 'info' ? this.nvueBorderColor : typeColor;
  290. style.borderWidth = this.hairline ? '0.5px' : '1px';
  291. style.borderStyle = 'solid';
  292. } else {
  293. style.borderWidth = this.hairline ? '0.5px' : '1px';
  294. style.borderStyle = 'solid';
  295. if (this.type === 'info') {
  296. style.color = this.nvueMainColor;
  297. style.backgroundColor = this.nvueInfoBackgroundColor;
  298. style.borderColor = this.nvueBorderColor;
  299. } else {
  300. style.color = '#ffffff';
  301. style.backgroundColor = typeColor;
  302. style.borderColor = typeColor;
  303. }
  304. }
  305. // #endif
  306. return style;
  307. },
  308. // nvue版本按钮的字体不会继承父组件的颜色,需要对每一个text组件进行单独的设置
  309. nvueTextStyle() {
  310. let style = {};
  311. // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
  312. if (this.type === "info") {
  313. style.color = this.nvueMainColor;
  314. }
  315. if (this.color) {
  316. style.color = this.plain ? this.color : "white";
  317. } else if (this.plain && this.type !== 'info') {
  318. style.color = this.themeTypeColor;
  319. }
  320. style.fontSize = this.textSize + "px";
  321. return style;
  322. },
  323. // 字体大小
  324. textSize() {
  325. let fontSize = 14,
  326. { size } = this;
  327. if (size === "large") fontSize = 16;
  328. if (size === "normal") fontSize = 14;
  329. if (size === "small") fontSize = 12;
  330. if (size === "mini") fontSize = 10;
  331. return fontSize;
  332. },
  333. },
  334. emits: ['click', 'getphonenumber', 'getuserinfo',
  335. 'error', 'opensetting', 'launchapp', 'agreeprivacyauthorization'],
  336. methods: {
  337. addStyle,
  338. resolveNvueColor(colorValue, fallbackColor) {
  339. if (typeof colorValue !== 'string') return fallbackColor;
  340. if (colorValue.indexOf('var(') > -1) return fallbackColor;
  341. return colorValue;
  342. },
  343. upThemeVar(varName, fallbackColor) {
  344. return getThemeVar(varName, fallbackColor, this.$u);
  345. },
  346. clickHandler(e: any) {
  347. // 非禁止并且非加载中,才能点击
  348. if (!this.disabled && !this.loading) {
  349. // 进行节流控制,每this.throttle毫秒内,只在开始处执行
  350. throttle(() => {
  351. this.$emit("click", e);
  352. }, this.throttleTime);
  353. }
  354. // 是否阻止事件传播
  355. this.stop && this.preventEvent(e)
  356. },
  357. // 下面为对接uniapp官方按钮开放能力事件回调的对接
  358. getphonenumber(res: any) {
  359. this.$emit("getphonenumber", res);
  360. },
  361. getuserinfo(res: any) {
  362. this.$emit("getuserinfo", res);
  363. },
  364. error(res: any) {
  365. this.$emit("error", res);
  366. },
  367. opensetting(res: any) {
  368. this.$emit("opensetting", res);
  369. },
  370. launchapp(res: any) {
  371. this.$emit("launchapp", res);
  372. },
  373. agreeprivacyauthorization(res) {
  374. this.$emit("agreeprivacyauthorization", res);
  375. },
  376. },
  377. };
  378. </script>
  379. <style lang="scss" scoped>
  380. /* #ifndef APP-NVUE */
  381. @import "./vue.scss";
  382. /* #endif */
  383. /* #ifdef APP-NVUE */
  384. @import "./nvue.scss";
  385. /* #endif */
  386. $u-button-u-button-height: 40px !default;
  387. $u-button-text-font-size: 15px !default;
  388. $u-button-loading-text-font-size: 15px !default;
  389. $u-button-loading-text-margin-left: 4px !default;
  390. $u-button-large-width: 100% !default;
  391. $u-button-large-height: 50px !default;
  392. $u-button-normal-padding: 0 12px !default;
  393. $u-button-large-padding: 0 15px !default;
  394. $u-button-normal-font-size: 14px !default;
  395. $u-button-small-min-width: 60px !default;
  396. $u-button-small-height: 30px !default;
  397. $u-button-small-padding: 0px 8px !default;
  398. $u-button-mini-padding: 0px 8px !default;
  399. $u-button-small-font-size: 12px !default;
  400. $u-button-mini-height: 22px !default;
  401. $u-button-mini-font-size: 10px !default;
  402. $u-button-mini-min-width: 50px !default;
  403. $u-button-disabled-opacity: 0.5 !default;
  404. $u-button-info-color: $u-main-color !default;
  405. $u-button-info-background-color: var(--up-button-info-background-color, var(--up-card-bg-color, #fff)) !default;
  406. $u-button-info-border-color: $u-border-color !default;
  407. $u-button-info-border-width: 1px !default;
  408. $u-button-info-border-style: solid !default;
  409. $u-button-success-color: #fff !default;
  410. $u-button-success-background-color: $u-success !default;
  411. $u-button-success-border-color: $u-button-success-background-color !default;
  412. $u-button-success-border-width: 1px !default;
  413. $u-button-success-border-style: solid !default;
  414. $u-button-primary-color: #fff !default;
  415. $u-button-primary-background-color: $u-primary !default;
  416. $u-button-primary-border-color: $u-button-primary-background-color !default;
  417. $u-button-primary-border-width: 1px !default;
  418. $u-button-primary-border-style: solid !default;
  419. $u-button-error-color: #fff !default;
  420. $u-button-error-background-color: $u-error !default;
  421. $u-button-error-border-color: $u-button-error-background-color !default;
  422. $u-button-error-border-width: 1px !default;
  423. $u-button-error-border-style: solid !default;
  424. $u-button-warning-color: #fff !default;
  425. $u-button-warning-background-color: $u-warning !default;
  426. $u-button-warning-border-color: $u-button-warning-background-color !default;
  427. $u-button-warning-border-width: 1px !default;
  428. $u-button-warning-border-style: solid !default;
  429. $u-button-block-width: 100% !default;
  430. $u-button-circle-border-top-right-radius: 100px !default;
  431. $u-button-circle-border-top-left-radius: 100px !default;
  432. $u-button-circle-border-bottom-left-radius: 100px !default;
  433. $u-button-circle-border-bottom-right-radius: 100px !default;
  434. $u-button-square-border-top-right-radius: 3px !default;
  435. $u-button-square-border-top-left-radius: 3px !default;
  436. $u-button-square-border-bottom-left-radius: 3px !default;
  437. $u-button-square-border-bottom-right-radius: 3px !default;
  438. $u-button-icon-min-width: 1em !default;
  439. $u-button-plain-background-color: var(--up-button-plain-background-color, var(--up-card-bg-color, #fff)) !default;
  440. $u-button-hairline-border-width: 0.5px !default;
  441. .u-button {
  442. height: $u-button-u-button-height;
  443. position: relative;
  444. align-items: center;
  445. justify-content: center;
  446. @include flex;
  447. /* #ifndef APP-NVUE */
  448. box-sizing: border-box;
  449. /* #endif */
  450. flex-direction: row;
  451. &__text {
  452. font-size: $u-button-text-font-size;
  453. }
  454. &__loading-text {
  455. font-size: $u-button-loading-text-font-size;
  456. margin-left: $u-button-loading-text-margin-left;
  457. }
  458. &--large {
  459. /* #ifndef APP-NVUE */
  460. width: $u-button-large-width;
  461. /* #endif */
  462. height: $u-button-large-height;
  463. padding: $u-button-large-padding;
  464. }
  465. &--normal {
  466. padding: $u-button-normal-padding;
  467. font-size: $u-button-normal-font-size;
  468. }
  469. &--small {
  470. /* #ifndef APP-NVUE */
  471. min-width: $u-button-small-min-width;
  472. /* #endif */
  473. height: $u-button-small-height;
  474. padding: $u-button-small-padding;
  475. font-size: $u-button-small-font-size;
  476. }
  477. &--mini {
  478. height: $u-button-mini-height;
  479. font-size: $u-button-mini-font-size;
  480. /* #ifndef APP-NVUE */
  481. min-width: $u-button-mini-min-width;
  482. /* #endif */
  483. padding: $u-button-mini-padding;
  484. }
  485. &--disabled {
  486. opacity: $u-button-disabled-opacity;
  487. }
  488. &--info {
  489. color: $u-button-info-color;
  490. background-color: $u-button-info-background-color;
  491. border-color: $u-button-info-border-color;
  492. border-width: $u-button-info-border-width;
  493. border-style: $u-button-info-border-style;
  494. }
  495. &--success {
  496. color: $u-button-success-color;
  497. background-color: $u-button-success-background-color;
  498. border-color: $u-button-success-border-color;
  499. border-width: $u-button-success-border-width;
  500. border-style: $u-button-success-border-style;
  501. }
  502. &--primary {
  503. color: $u-button-primary-color;
  504. background-color: $u-button-primary-background-color;
  505. border-color: $u-button-primary-border-color;
  506. border-width: $u-button-primary-border-width;
  507. border-style: $u-button-primary-border-style;
  508. }
  509. &--error {
  510. color: $u-button-error-color;
  511. background-color: $u-button-error-background-color;
  512. border-color: $u-button-error-border-color;
  513. border-width: $u-button-error-border-width;
  514. border-style: $u-button-error-border-style;
  515. }
  516. &--warning {
  517. color: $u-button-warning-color;
  518. background-color: $u-button-warning-background-color;
  519. border-color: $u-button-warning-border-color;
  520. border-width: $u-button-warning-border-width;
  521. border-style: $u-button-warning-border-style;
  522. }
  523. &--block {
  524. @include flex;
  525. width: $u-button-block-width;
  526. }
  527. &--circle {
  528. border-top-right-radius: $u-button-circle-border-top-right-radius;
  529. border-top-left-radius: $u-button-circle-border-top-left-radius;
  530. border-bottom-left-radius: $u-button-circle-border-bottom-left-radius;
  531. border-bottom-right-radius: $u-button-circle-border-bottom-right-radius;
  532. }
  533. &--square {
  534. border-bottom-left-radius: $u-button-square-border-top-right-radius;
  535. border-bottom-right-radius: $u-button-square-border-top-left-radius;
  536. border-top-left-radius: $u-button-square-border-bottom-left-radius;
  537. border-top-right-radius: $u-button-square-border-bottom-right-radius;
  538. }
  539. &__icon {
  540. /* #ifndef APP-NVUE */
  541. min-width: $u-button-icon-min-width;
  542. line-height: inherit !important;
  543. vertical-align: top;
  544. /* #endif */
  545. }
  546. &--plain {
  547. background-color: $u-button-plain-background-color;
  548. }
  549. &--hairline {
  550. border-width: $u-button-hairline-border-width !important;
  551. }
  552. }
  553. </style>