y-Fab.vue 7.3 KB

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