u-button.vue 19 KB

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