tn-button.vue 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <template>
  2. <button
  3. class="tn-btn-class tn-btn"
  4. :class="[
  5. buttonClass,
  6. backgroundColorClass,
  7. fontColorClass
  8. ]"
  9. :style="[buttonStyle]"
  10. hover-class="tn-hover"
  11. :loading="loading"
  12. :disabled="disabled"
  13. :form-type="formType"
  14. :open-type="openType"
  15. @getuserinfo="handleGetUserInfo"
  16. @getphonenumber="handleGetPhoneNumber"
  17. @contact="handleContact"
  18. @error="handleError"
  19. @tap="handleClick"
  20. >
  21. <slot></slot>
  22. </button>
  23. </template>
  24. <script>
  25. import componentsColorMixin from '../../libs/mixin/components_color.js'
  26. export default {
  27. mixins: [componentsColorMixin],
  28. name: "tn-button",
  29. // 解决再微信小程序种,自定义按钮无法触发bindsubmit
  30. behaviors: ['wx://form-field-button'],
  31. props: {
  32. // 按钮索引,用于区分多个按钮
  33. index: {
  34. type: [Number, String],
  35. default: 0
  36. },
  37. // 按钮形状 default 默认 round 圆角 icon 图标按钮
  38. shape: {
  39. type: String,
  40. default: 'default'
  41. },
  42. // 是否加阴影
  43. shadow: {
  44. type: Boolean,
  45. default: false
  46. },
  47. // 宽度 rpx或%
  48. width: {
  49. type: String,
  50. default: 'auto'
  51. },
  52. // 高度 rpx或%
  53. height: {
  54. type: String,
  55. default: ''
  56. },
  57. // 按钮的尺寸 sm lg
  58. size: {
  59. type: String,
  60. default: ''
  61. },
  62. // 字体是否加粗
  63. fontBold: {
  64. type: Boolean,
  65. default: false
  66. },
  67. padding: {
  68. type: String,
  69. default: '0 30rpx'
  70. },
  71. // 外边距 与css的margin参数用法相同
  72. margin: {
  73. type: String,
  74. default: ''
  75. },
  76. // 是否镂空
  77. plain: {
  78. type: Boolean,
  79. default: false
  80. },
  81. // 当plain=true时,是否显示边框
  82. border: {
  83. type: Boolean,
  84. default: true
  85. },
  86. // 当plain=true时,是否加粗显示边框
  87. borderBold: {
  88. type: Boolean,
  89. default: false
  90. },
  91. // 是否禁用
  92. disabled: {
  93. type: Boolean,
  94. default: false
  95. },
  96. // 是否显示加载图标
  97. loading: {
  98. type: Boolean,
  99. default: false
  100. },
  101. // 触发form表单的事件类型
  102. formType: {
  103. type: String,
  104. default: ''
  105. },
  106. // 开放能力
  107. openType: {
  108. type: String,
  109. default: ''
  110. },
  111. // 是否阻止重复点击(默认间隔是200ms)
  112. blockRepeatClick: {
  113. type: Boolean,
  114. default: false
  115. }
  116. },
  117. computed: {
  118. // 根据不同的参数动态生成class
  119. buttonClass() {
  120. let clazz = ''
  121. // 按钮形状
  122. switch (this.shape) {
  123. case 'icon':
  124. case 'round':
  125. clazz += ' tn-round'
  126. break
  127. }
  128. // 阴影
  129. if (this.shadow) {
  130. if (this.backgroundColorClass !== '' && this.backgroundColorClass.indexOf('tn-bg') != -1) {
  131. const color = this.backgroundColor.slice(this.backgroundColor.lastIndexOf('-') + 1)
  132. clazz += ` tn-shadow-${color}`
  133. } else {
  134. clazz += ' tn-shadow-blur'
  135. }
  136. }
  137. // 字体加粗
  138. if (this.fontBold) {
  139. clazz += ' tn-text-bold'
  140. }
  141. // 设置为镂空并且设置镂空便可才进行设置
  142. if (this.plain) {
  143. clazz += ' tn-btn--plain'
  144. if (this.border) {
  145. clazz += ' tn-border-solid'
  146. if (this.borderBold) {
  147. clazz += ' tn-bold-border'
  148. }
  149. if (this.backgroundColor !== '' && this.backgroundColor.includes('tn-bg')) {
  150. const color = this.backgroundColor.slice(this.backgroundColor.lastIndexOf('-') + 1)
  151. clazz += ` tn-border-${color}`
  152. }
  153. }
  154. }
  155. return clazz
  156. },
  157. // 按钮的样式
  158. buttonStyle() {
  159. let style = {}
  160. switch(this.size) {
  161. case 'sm':
  162. style.padding = '0 20rpx'
  163. style.fontSize = '22rpx'
  164. style.height = this.height || '48rpx'
  165. break
  166. case 'lg':
  167. style.padding = '0 40rpx'
  168. style.fontSize = '32rpx'
  169. style.height = this.height || '80rpx'
  170. break
  171. default :
  172. style.padding = '0 30rpx'
  173. style.fontSize = '28rpx'
  174. style.height = this.height || '64rpx'
  175. }
  176. // 是否手动设置了内边距
  177. if (this.padding) {
  178. style.padding = this.padding
  179. }
  180. // 是否手动设置外边距
  181. if (this.margin) {
  182. style.margin = this.margin
  183. }
  184. // 是否手动设置了字体大小
  185. if (this.fontSize) {
  186. style.fontSize = this.fontSize + this.fontUnit
  187. }
  188. style.width = this.shape === 'icon' ? style.height : this.width
  189. style.padding = this.shape === 'icon' ? '0' : style.padding
  190. if (this.fontColorStyle) {
  191. style.color = this.fontColorStyle
  192. }
  193. if (!this.backgroundColorClass) {
  194. if (this.plain) {
  195. style.borderColor = this.backgroundColorStyle || '#080808'
  196. } else {
  197. style.backgroundColor = this.backgroundColorStyle || '#FFFFFF'
  198. }
  199. }
  200. // 设置阴影
  201. if (this.shadow && !this.backgroundColorClass) {
  202. if (this.backgroundColorStyle.indexOf('#') != -1) {
  203. style.boxShadow = `6rpx 6rpx 8rpx ${(this.backgroundColorStyle || '#000000')}10`
  204. } else if (this.backgroundColorStyle.indexOf('rgb') != -1 || this.backgroundColorStyle.indexOf('rgba') != -1 || !this.backgroundColorStyle) {
  205. style.boxShadow = `6rpx 6rpx 8rpx ${(this.backgroundColorStyle || 'rgba(0, 0, 0, 0.1)')}`
  206. }
  207. }
  208. return style
  209. },
  210. },
  211. data() {
  212. return {
  213. // 上次点击的时间
  214. clickTime: 0,
  215. // 两次点击防抖的间隔时间
  216. clickIntervalTime: 200
  217. }
  218. },
  219. methods: {
  220. // 按钮点击事件
  221. handleClick() {
  222. if (this.disabled) {
  223. return
  224. }
  225. if (this.blockRepeatClick) {
  226. const nowTime = new Date().getTime()
  227. if (nowTime - this.clickTime <= this.clickIntervalTime) {
  228. return
  229. }
  230. this.clickTime = nowTime
  231. setTimeout(() => {
  232. this.clickTime = 0
  233. }, this.clickIntervalTime)
  234. }
  235. this.$emit('click', {
  236. index: Number(this.index)
  237. })
  238. // 兼容tap事件
  239. this.$emit('tap', {
  240. index: Number(this.index)
  241. })
  242. },
  243. handleGetUserInfo({ detail = {} } = {}) {
  244. this.$emit('getuserinfo', detail);
  245. },
  246. handleContact({ detail = {} } = {}) {
  247. this.$emit('contact', detail);
  248. },
  249. handleGetPhoneNumber({ detail = {} } = {}) {
  250. this.$emit('getphonenumber', detail);
  251. },
  252. handleError({ detail = {} } = {}) {
  253. this.$emit('error', detail);
  254. },
  255. }
  256. }
  257. </script>
  258. <style lang="scss" scoped>
  259. .tn-btn {
  260. position: relative;
  261. display: inline-flex;
  262. align-items: center;
  263. justify-content: center;
  264. box-sizing: border-box;
  265. line-height: 1;
  266. text-align: center;
  267. text-decoration: none;
  268. overflow: visible;
  269. transform: translate(0rpx, 0rpx);
  270. // background-color: $tn-mai
  271. border-radius: 12rpx;
  272. // color: $tn-font-color;
  273. margin: 0;
  274. &--plain {
  275. background-color: transparent !important;
  276. background-image: none;
  277. &.tn-round {
  278. border-radius: 1000rpx !important;
  279. }
  280. }
  281. }
  282. </style>