tm-menu.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <template>
  2. <view class="tm-menu relative d-inline-block">
  3. <view @click.stop="toogle">
  4. <slot></slot>
  5. </view>
  6. <view v-if="showMenu" class="tm-menu-block absolute animation" :class="[direction,mentDirection]">
  7. <view v-if="direction==='bottom'" class=" px-16" :class="[tipFangx]">
  8. <text class="iconfont icon-sort-up " style="font-size: 46upx;line-height: 0.5;margin-bottom: -4upx;"
  9. :class="{
  10. 'text-white':!black_tmeme,
  11. 'text-grey-darken-3':black_tmeme
  12. }"></text>
  13. </view>
  14. <view class="round-3 overflow-x" :style="{maxHeight:maxHeight+'rpx'}">
  15. <tm-listitem
  16. @click="showMenu=false;$emit('change',{index:index,value:item})"
  17. :black="black_tmeme"
  18. v-for="(item,index) in list" :key="index"
  19. dense
  20. :left-icon="item['icon']"
  21. :left-icon-color="(item['iconColor']||iconColor)"
  22. :left-icon-size="36"
  23. :show-left-icon="item['icon']?true:false"
  24. :round="0"
  25. >
  26. <text class="text-size-n">
  27. {{ listType?item:item[rangKey] }}
  28. </text>
  29. </tm-listitem>
  30. </view>
  31. <view v-if="direction==='top'" class=" px-16" :class="[tipFangx]">
  32. <text class="iconfont icon-sort-down " style="font-size: 46upx;line-height: 0.5;margin-top: -4upx;"
  33. :class="{
  34. 'text-white':!black_tmeme,
  35. 'text-grey-darken-3':black_tmeme
  36. }"></text>
  37. </view>
  38. </view>
  39. <tm-maskFlow :blur='false' v-model="showMenu" bgColor='none'></tm-maskFlow>
  40. </view>
  41. </template>
  42. <script>
  43. /**
  44. * 弹出菜单
  45. * @property {Boolean} black = [true|false] 默认:false,暗黑模式。
  46. * @property {Boolean} show = [true|false] 默认:false,始终显示菜单。
  47. * @property {Boolean} disabled = [true|false] 默认:false,禁用
  48. * @property {Number} maxHeight = [] 默认:500,单位rpx
  49. * @property {String} icon-color = [] 默认:primary,如果有图标将会使用这个图标颜色,如果在数据格式中不提供
  50. * @property {String} tip-direction = [left | center | right] 默认:center,指示三角形的方向
  51. * @property {String} direction = [top | bottom] 默认:bottom,弹出方向,top | bottom
  52. * @property {String} ment-direction = [left | center | right] 默认:center,弹出在父组件上的对齐方式,默认居中。可选left,right,center
  53. * @property {Array} list = [] 默认:[],菜单列表可以是字符串对象或者数组对象。
  54. * @property {String} rang-key = [] 默认:title,菜单列表数组对象时,需要提供key
  55. * @property {Function} change 点击列表项目时触发,返回:{index:index,value:item}
  56. * @example <tm-menu :list="['菜单1','菜单2']"><tm-button>弹出菜单</tm-button></tm-menu>
  57. *
  58. */
  59. import tmGrouplist from "@/tm-vuetify/components/tm-grouplist/tm-grouplist.vue"
  60. import tmListitem from "@/tm-vuetify/components/tm-listitem/tm-listitem.vue"
  61. import tmMaskFlow from "@/tm-vuetify/components/tm-maskFlow/tm-maskFlow.vue"
  62. export default {
  63. components:{tmGrouplist,tmListitem,tmMaskFlow},
  64. name: "tm-menu",
  65. props: {
  66. black: {
  67. type:Boolean | String,
  68. default:null
  69. },
  70. maxHeight:{
  71. type:Number|String,
  72. default:500
  73. },
  74. // 三角形的方向。left | center | right
  75. tipDirection: {
  76. type: String,
  77. default: 'center'
  78. },
  79. // 始终显示菜单
  80. show: {
  81. type: Boolean,
  82. default: false
  83. },
  84. disabled: {
  85. type: Boolean,
  86. default: false
  87. },
  88. // 如果列表有图标,显示的图标颜色主题名称
  89. iconColor: {
  90. type: String,
  91. default: 'primary'
  92. },
  93. // 弹出方向,top | bottom
  94. direction: {
  95. type: String,
  96. default: 'bottom'
  97. },
  98. // 弹出在父组件上的对齐方式,默认居中。可选left,right,center
  99. mentDirection: {
  100. type: String,
  101. default: 'center'
  102. },
  103. list: {
  104. type: Array,
  105. default: () => {
  106. return [];
  107. }
  108. },
  109. // 如果list提供的是对象数组,需要提供对象的key。如果是string对象,无需提供。默认title
  110. rangKey: {
  111. type: String,
  112. default: 'title'
  113. }
  114. },
  115. computed: {
  116. listType: function() {
  117. return typeof this.list[0] === 'string';
  118. },
  119. tipFangx: function() {
  120. if (this.tipDirection === 'left') return 'flex-start';
  121. if (this.tipDirection === 'center') return 'flex-center';
  122. if (this.tipDirection === 'right') return 'flex-end';
  123. },
  124. black_tmeme: function() {
  125. if (this.black !== null) return this.black;
  126. return this.$tm.vx.state().tmVuetify.black;
  127. }
  128. },
  129. data() {
  130. return {
  131. showMenu: false,
  132. };
  133. },
  134. mounted() {
  135. if(this.disabled) return;
  136. this.showMenu = this.show;
  137. },
  138. methods: {
  139. toogle() {
  140. if (!this.list || this.list.length == 0) return;
  141. if(this.disabled) return;
  142. this.showMenu = !this.showMenu;
  143. this.$emit("update:show",this.showMenu)
  144. },
  145. open() {
  146. if (!this.list || this.list.length == 0) return;
  147. if(this.disabled) return;
  148. this.showMenu = true;
  149. this.$emit("update:show",true)
  150. },
  151. off() {
  152. if (!this.list || this.list.length == 0) return;
  153. if(this.disabled) return;
  154. this.showMenu = false;
  155. this.$emit("update:show",false)
  156. }
  157. },
  158. }
  159. </script>
  160. <style lang="scss" scoped>
  161. .tm-menu {
  162. position: relative;
  163. text-align: center;
  164. .tm-menu-block {
  165. z-index: 501;
  166. width: 320upx;
  167. &.bottom {
  168. top: 100%;
  169. bottom: inherit;
  170. animation: roteScale 0.3s ease-in-out;
  171. }
  172. &.top {
  173. top: inherit;
  174. bottom: 100%;
  175. animation: roteScaleTop 0.3s ease-in-out;
  176. }
  177. &.center {
  178. left: calc(50% - 160upx);
  179. }
  180. &.left {
  181. left: 0upx;
  182. }
  183. &.right {
  184. right: 0upx;
  185. }
  186. }
  187. }
  188. @keyframes roteScale{
  189. 0%{
  190. transform: scale(0.9) translateY(-20rpx);
  191. opacity: 0;
  192. }
  193. 100%{
  194. transform: scale(1) translateY(0rpx);
  195. opacity: 1;
  196. }
  197. }
  198. @keyframes roteScaleTop{
  199. 0%{
  200. transform: scale(0.9) translateY(20rpx);
  201. opacity: 0;
  202. }
  203. 100%{
  204. transform: scale(1) translateY(0rpx);
  205. opacity: 1;
  206. }
  207. }
  208. </style>