tui-fab.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. <template>
  2. <view @touchmove.stop.prevent>
  3. <view class="tui-fab-box" :class="{'tui-fab-right':!left || (left && right)}"
  4. :style="{left:getLeft(),right:getRight(),bottom:bottom+'rpx'}">
  5. <view class="tui-fab-btn" :class="{'tui-visible':isOpen,'tui-fab-hidden':isHidden}">
  6. <view class="tui-fab-item-box" :class="{'tui-fab-item-left':left && !right && item.imgUrl}"
  7. v-for="(item,index) in btnList" :key="index" @tap.stop="handleClick(index)">
  8. <view :class="[left && !right?'tui-text-left':'tui-text-right']" v-if="item.imgUrl"
  9. :style="{fontSize:item.fontSize+'rpx',color:item.color}">{{item.text || ""}}</view>
  10. <view class="tui-fab-item"
  11. :style="{width:width+'rpx',height:height+'rpx',background:item.bgColor || bgColor,borderRadius:radius}">
  12. <view class="tui-fab-title" v-if="!item.imgUrl"
  13. :style="{fontSize:item.fontSize+'rpx',color:item.color}">{{item.text || ""}}</view>
  14. <image :src="item.imgUrl" class="tui-fab-img" v-else
  15. :style="{width:item.imgWidth+'rpx',height:item.imgHeight+'rpx'}"></image>
  16. </view>
  17. </view>
  18. </view>
  19. <view class="tui-fab-item" :class="{'tui-active':isOpen}"
  20. :style="{width:width+'rpx',height:height+'rpx',borderRadius:radius,background:bgColor,color:color}"
  21. @tap.stop="handleClick(-1)">
  22. <text class="tui-fab-icon tui-icon-plus" v-if="!custom"></text>
  23. <slot></slot>
  24. </view>
  25. </view>
  26. <view class="tui-fab-mask" :class="{'tui-visible':isOpen}" @tap="handleClickCancel"></view>
  27. </view>
  28. </template>
  29. <script>
  30. //拓展出来的按钮不应多于6个,否则违反了作为悬浮按钮的快速、高效的原则
  31. export default {
  32. name: "tuiFab",
  33. emits: ['click'],
  34. props: {
  35. //rpx 为0时值为auto
  36. left: {
  37. type: Number,
  38. default: 0
  39. },
  40. //rpx 当为0时且left不为0,值为auto
  41. right: {
  42. type: Number,
  43. default: 80
  44. },
  45. //rpx bottom值
  46. bottom: {
  47. type: Number,
  48. default: 100
  49. },
  50. //默认按钮 宽度 rpx
  51. width: {
  52. type: Number,
  53. default: 108
  54. },
  55. //默认按钮 高度 rpx
  56. height: {
  57. type: Number,
  58. default: 108
  59. },
  60. //圆角值
  61. radius: {
  62. type: String,
  63. default: "50%"
  64. },
  65. //默认按钮自定义内容[替换加号]
  66. custom: {
  67. type: Boolean,
  68. default: false
  69. },
  70. //默认按钮背景颜色
  71. bgColor: {
  72. type: String,
  73. default: "#5677fc"
  74. },
  75. //字体颜色
  76. color: {
  77. type: String,
  78. default: "#fff"
  79. },
  80. //拓展按钮
  81. // bgColor: "#5677fc",
  82. // //图标/图片地址
  83. // imgUrl: "/static/images/fab/fab_reward.png",
  84. // //图片高度 rpx
  85. // imgHeight: 60,
  86. // //图片宽度 rpx
  87. // imgWidth: 60,
  88. // //名称
  89. // text: "名称",
  90. // //字体大小
  91. // fontSize: 30,
  92. // //字体颜色
  93. // color: "#fff"
  94. btnList: {
  95. type: Array,
  96. default () {
  97. return []
  98. }
  99. },
  100. //点击遮罩 是否可关闭
  101. maskClosable: {
  102. type: Boolean,
  103. default: false
  104. }
  105. },
  106. data() {
  107. return {
  108. isOpen: false,
  109. isHidden: true,
  110. timer: null
  111. };
  112. },
  113. // #ifndef VUE3
  114. beforeDestroy() {
  115. clearTimeout(this.timer)
  116. this.timer = null
  117. },
  118. // #endif
  119. // #ifdef VUE3
  120. beforeUnmount() {
  121. clearTimeout(this.timer)
  122. this.timer = null
  123. },
  124. // #endif
  125. methods: {
  126. getLeft() {
  127. let val = "auto"
  128. if (this.left && !this.right) {
  129. val = this.left + 'rpx'
  130. }
  131. return val
  132. },
  133. getRight() {
  134. let val = this.right + 'rpx'
  135. if (this.left && !this.right) {
  136. val = "auto"
  137. }
  138. return val
  139. },
  140. handleClick: function(index) {
  141. this.isHidden = false
  142. clearTimeout(this.timer)
  143. if (index == -1 && this.btnList.length) {
  144. this.isOpen = !this.isOpen
  145. } else {
  146. this.$emit("click", {
  147. index: index
  148. })
  149. this.isOpen = false
  150. }
  151. if (!this.isOpen) {
  152. this.timer = setTimeout(() => {
  153. this.isHidden = true
  154. }, 200)
  155. }
  156. },
  157. handleClickCancel: function() {
  158. if (!this.maskClosable) return;
  159. this.isOpen = false
  160. }
  161. }
  162. }
  163. </script>
  164. <style scoped>
  165. @font-face {
  166. font-family: 'tuifab';
  167. src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAREAA0AAAAABnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAEKAAAABoAAAAciPExJUdERUYAAAQIAAAAHgAAAB4AKQAKT1MvMgAAAaAAAABCAAAAVjyBSAVjbWFwAAAB9AAAAD4AAAFCAA/pvmdhc3AAAAQAAAAACAAAAAj//wADZ2x5ZgAAAkAAAABRAAAAYFkYQQNoZWFkAAABMAAAADAAAAA2Fm5OF2hoZWEAAAFgAAAAHQAAACQH3QOFaG10eAAAAeQAAAAPAAAAEAwAAANsb2NhAAACNAAAAAoAAAAKADAAAG1heHAAAAGAAAAAHwAAACABDwAobmFtZQAAApQAAAFJAAACiCnmEVVwb3N0AAAD4AAAAB8AAAAx2XRuznjaY2BkYGAAYtGolt54fpuvDNwsDCBwc1krH5xm/t/I/J+5FsjlYGACiQIAGAEKZHjaY2BkYGBu+N/AEMPCAALM/xkYGVABCwBZ4wNrAAAAeNpjYGRgYGBhkGEA0QwMTEDMBYQMDP/BfAYAC4kBOAB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PhJ8JMzf8b2CIYW5gaAAKM4LkAN21DAEAAHjaY2GAABYIZgYAAIMAEAB42mNgYGBmgGAZBkYGELAB8hjBfBYGBSDNAoRA/jPh//8hpOQHqEoGRjYGGJOBkQlIMDGgAkaGYQ8AUSIHswAAAAAAAAAAAAAAMAAAeNpjYGRg/t/I/J+5lkGagYFRUVCPUYmNXVCRj1FETFxRUI7RyMxcUNGO0USN+fS/HEY5XTnGfznicnLijFPAHMYpYnJyjFvBlBgWBQBNJxKpAAAAeNp9kD1OAzEQhZ/zByQSQiCoXVEA2vyUKRMp9Ailo0g23pBo1155nUg5AS0VB6DlGByAGyDRcgpelkmTImvt6PObmeexAZzjGwr/3yXuhBWO8ShcwREy4Sr1F+Ea+V24jhY+hRvUf4SbuFUD4RYu1BsdVO2Eu5vSbcsKZxgIV3CKJ+Eq9ZVwjfwqXMcVPoQb1L+EmxjjV7iFa2WpDOFhMEFgnEFjig3jAjEcLJIyBtahOfRmEsxMTzd6ETubOBso71dilwMeaDnngCntPbdmvkon/mDLgdSYbh4FS7YpjS4idCgbXyyc1d2oc7D9nu22tNi/a4E1x+xRDWzU/D3bM9JIbAyvkJI18jK3pBJTj2hrrPG7ZynW814IiU68y/SIx5o0dTr3bmniwOLn8owcfbS5kj33qBw+Y1kIeb/dTsQgil2GP5PYcRkAAAB42mNgYoAALjDJyIAOWMCiTIxMbFmZiRmJ+QALXAKKAAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADAAMAAQAEAAAAAgAAAAB42mNgYGBkAIKrS9Q5QPTNZa18MBoAPbcFzgAA) format('woff');
  168. font-weight: normal;
  169. font-style: normal;
  170. }
  171. .tui-fab-icon {
  172. font-family: "tuifab" !important;
  173. font-style: normal;
  174. -webkit-font-smoothing: antialiased;
  175. -moz-osx-font-smoothing: grayscale;
  176. padding: 10rpx;
  177. }
  178. .tui-icon-plus:before {
  179. content: "\e613";
  180. }
  181. .tui-fab-box {
  182. display: flex;
  183. justify-content: center;
  184. flex-direction: column;
  185. position: fixed;
  186. z-index: 99997;
  187. }
  188. .tui-fab-right {
  189. align-items: flex-end;
  190. }
  191. .tui-fab-btn {
  192. transform: scale(0);
  193. transition: all 0.2s ease-in-out;
  194. opacity: 0;
  195. visibility: hidden;
  196. }
  197. .tui-fab-hidden {
  198. height: 0;
  199. width: 0;
  200. }
  201. .tui-fab-item-box {
  202. display: flex;
  203. align-items: center;
  204. justify-content: flex-end;
  205. padding-bottom: 40rpx;
  206. }
  207. .tui-fab-item-left {
  208. flex-flow: row-reverse;
  209. }
  210. .tui-fab-title {
  211. width: 90%;
  212. text-align: center;
  213. white-space: nowrap;
  214. overflow: hidden;
  215. text-overflow: ellipsis;
  216. }
  217. .tui-text-left {
  218. padding-left: 28rpx;
  219. }
  220. .tui-text-right {
  221. padding-right: 28rpx;
  222. }
  223. .tui-fab-img {
  224. display: block;
  225. }
  226. .tui-fab-item {
  227. display: flex;
  228. align-items: center;
  229. justify-content: center;
  230. box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1);
  231. transition: all 0.2s linear;
  232. }
  233. .tui-radius {
  234. border-radius: 50%;
  235. }
  236. .tui-active {
  237. transform: rotate(135deg);
  238. }
  239. .tui-fab-mask {
  240. position: fixed;
  241. top: 0;
  242. left: 0;
  243. right: 0;
  244. bottom: 0;
  245. background: rgba(0, 0, 0, 0.75);
  246. z-index: 99996;
  247. transition: all 0.2s ease-in-out;
  248. opacity: 0;
  249. visibility: hidden;
  250. }
  251. .tui-visible {
  252. visibility: visible;
  253. opacity: 1;
  254. transform: scale(1);
  255. }
  256. </style>