index.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <template>
  2. <div class="menuInRow">
  3. <template v-if="showData.length>0">
  4. <div class="showMenu" v-menuInRow="getMenuNum">
  5. <div v-for="(item,index) in showData" :key="'show'+index" @click.prevent="clickDom(item)" class="menuItem" :class="index >= (surplusNum>0?num-1:num)?'display_none':''">
  6. <slot name="menuItem" v-if="data.length>0" :row="item">
  7. <div v-html="item[prop.name]"></div>
  8. </slot>
  9. <div v-else v-html="item.name"></div>
  10. </div>
  11. </div>
  12. <div v-if="surplusNum>0" class="hideMenu">
  13. <el-dropdown>
  14. <span class="el-dropdown-link">
  15. 更多<i class="el-icon-arrow-down el-icon--right"></i>
  16. </span>
  17. <el-dropdown-menu slot="dropdown">
  18. <el-dropdown-item v-for="(item,index) in hideData" :key="'hide'+index" @click.native.prevent="clickDom(item)">
  19. <slot name="menuItem" v-if="data.length>0" :row="item">
  20. <div v-html="item[prop.name]"></div>
  21. </slot>
  22. <div v-else v-html="item.name"></div>
  23. </el-dropdown-item>
  24. </el-dropdown-menu>
  25. </el-dropdown>
  26. </div>
  27. </template>
  28. <template v-if="data.length == 0">
  29. <div v-getChildData style="display:none">
  30. <slot></slot>
  31. </div>
  32. </template>
  33. </div>
  34. </template>
  35. <script>
  36. async function menuInRowFun(el,binding,childNodes){
  37. el.style.whiteSpace = 'nowrap';
  38. el.style.width = 'calc(100% - 60px)'
  39. var el_width = el.clientWidth
  40. var width = 0
  41. var num = 0
  42. var surplusNum = 0
  43. async function getElementWidthWithMargin(element) {
  44. const rect = await element.getBoundingClientRect();
  45. return rect.width;
  46. }
  47. var widths = []
  48. for(var i = 0;i<childNodes.length;i++){
  49. let childWidth = await getElementWidthWithMargin(childNodes[i])
  50. widths.push(childWidth)
  51. width += childWidth
  52. if(width >el_width ){
  53. break;
  54. }
  55. num ++
  56. }
  57. surplusNum = childNodes.length - num
  58. binding.value(num,surplusNum)
  59. el.style.width = width - widths[num-1] + 20 + 'px'
  60. }
  61. function getMenuItem(el, binding,vnode){
  62. var that = vnode.context
  63. var childNodes = el.childNodes
  64. var data = []
  65. for(var i = 0;i<childNodes.length;i++){
  66. var child = childNodes[i]
  67. var name = child.getAttribute('name')
  68. if(name != 'menuInRowItem'){
  69. continue;
  70. }
  71. var value = child.getAttribute('value')
  72. var label = child.outerHTML
  73. data.push(
  74. {
  75. value:value,
  76. name:label
  77. }
  78. )
  79. }
  80. that.showData = data
  81. // binding.value(data)
  82. }
  83. export default {
  84. directives:{
  85. getChildData:{
  86. bind(el, binding,vnode){
  87. getMenuItem(el, binding,vnode)
  88. // console.log(that.showData)
  89. },
  90. // componentUpdated(el, binding,vnode) {
  91. // getMenuItem(el, binding,vnode)
  92. // },
  93. },
  94. menuInRow:{
  95. bind(el, binding,vnode) {
  96. var that = vnode.context
  97. var childNodes = el.childNodes
  98. that.$nextTick(()=>{
  99. menuInRowFun(el, binding,childNodes)
  100. window.addEventListener('resize',()=>{
  101. that.$commonJS.debounce( menuInRowFun(el, binding,childNodes),1000)
  102. })
  103. })
  104. },
  105. // 如果需要,可以在更新时再次执行逻辑
  106. // componentUpdated(el, binding,vnode) {
  107. // menuInRowFun(el, binding)
  108. // },
  109. unbind(el) {
  110. var eventListener = window.eventListeners_
  111. if(!eventListener){
  112. return false
  113. }
  114. const listeners = eventListener.resize
  115. if(listeners){
  116. window.removeEventListener("resize");
  117. }
  118. },
  119. }
  120. },
  121. components: {},
  122. props: {
  123. data:{
  124. type:Array,
  125. default:()=>{
  126. return []
  127. }
  128. },
  129. prop:{
  130. type:String,
  131. default:'name'
  132. }
  133. },
  134. data() {
  135. return {
  136. config:{
  137. num:0,
  138. surplusNum:0,
  139. },
  140. num:0,
  141. surplusNum:0,
  142. showData:this.data,
  143. hideData:[]
  144. };
  145. },
  146. watch: {},
  147. computed: {},
  148. created() {},
  149. mounted() {
  150. },
  151. methods: {
  152. getMenuNum(num,surplusNum){
  153. this.num=num||0,
  154. this.surplusNum=surplusNum||0
  155. // this.showData = this.getShowData()
  156. this.hideData = this.getHideData()
  157. },
  158. getShowData(){
  159. if(this.surplusNum==0){
  160. return this.data
  161. }else{
  162. return this.data.slice(0, this.num)
  163. }
  164. },
  165. getHideData(){
  166. if(this.surplusNum==0){
  167. return []
  168. }
  169. return this.showData.slice(-this.surplusNum)
  170. },
  171. clickDom(item){
  172. if(this.data.length>0){
  173. this.$emit('click',item)
  174. }else{
  175. this.$emit('click',item.value)
  176. }
  177. }
  178. },
  179. };
  180. </script>
  181. <style lang="scss" scoped>
  182. .menuInRow{
  183. display:flex;
  184. align-items: center;
  185. width:calc(100% - 40px);
  186. padding:5px 20px;
  187. border-top:1px solid #e6e6e6;
  188. overflow:hidden;
  189. .showMenu{
  190. display:flex;
  191. align-items: center;
  192. width:calc(100% - 60px);
  193. }
  194. .menuItem{
  195. cursor: pointer;
  196. margin:0 10px;
  197. padding:5px 10px;
  198. min-width:fit-content
  199. }
  200. .hideMenu{
  201. margin-left:10px;
  202. width:50px;
  203. min-width:50px;
  204. background:white;
  205. cursor: pointer;
  206. }
  207. }
  208. .display_none{
  209. opacity: 0;
  210. pointer-events: none;
  211. }
  212. </style>