magic-navbar.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import { ref, h, Teleport, computed } from 'vue'
  2. import MagicIcon from '../icon/magic-icon.vue'
  3. import './magic-navbar.css'
  4. export default {
  5. props: {
  6. direction: {
  7. type: String,
  8. default: ''
  9. },
  10. reverse: {
  11. type: Boolean,
  12. default: false
  13. },
  14. defaultSelect: {
  15. type: Number,
  16. default: 0
  17. },
  18. allowClose: {
  19. type: Boolean,
  20. default: true
  21. },
  22. tooltipDirection: {
  23. type: String,
  24. default: 'right'
  25. },
  26. spliter: Boolean,
  27. value: Array,
  28. to: HTMLElement
  29. },
  30. setup(props, context) {
  31. const selectIndex = ref(props.defaultSelect)
  32. return {
  33. slots: computed(() => context.slots.default()[0].children),
  34. navbars: computed(() => context.slots.default()[0].children.flatMap(it => it.props)),
  35. selectIndex
  36. }
  37. },
  38. methods: {
  39. select(index){
  40. this.selectIndex = index
  41. }
  42. },
  43. render() {
  44. const renderSvg = word => {
  45. const pathId = parseInt(Math.random() * 100000000)
  46. const height = word.length * 6
  47. return h('svg', {
  48. xmlns: 'http://www.w3.org/2000/svg',
  49. version: '1.1',
  50. width: 22,
  51. height
  52. }, [
  53. h('defs', h('path', { id: `path-text-${pathId}`, d: this.reverse ? `M6,0 L6,${height}` : `M14,${height} L14,0`})),
  54. h('text', { fill: 'var(--main-color)' }, h('textPath', { 'xlink:href': `#path-text-${pathId}`}, word))
  55. ])
  56. }
  57. const splitTitle = (title) => {
  58. if(this.spliter && this.direction === 'vertical' && title.match(/\w/g)) {
  59. const elements = [];
  60. let last = ''
  61. let flag = 1
  62. let lastFlag
  63. const words = title.split('')
  64. for(let i=0, len = words.length; i< len;i++){
  65. const word = words[i]
  66. flag = word.match(/\w/) ? 1 : 2
  67. if(flag == lastFlag){
  68. last += word
  69. } else {
  70. last && elements.push(lastFlag === 1 ? renderSvg(last) : last)
  71. last = word
  72. }
  73. lastFlag = flag
  74. }
  75. last && elements.push(lastFlag === 1 ? renderSvg(last) : last)
  76. return elements
  77. }
  78. return [title];
  79. }
  80. const childs = [h('ul',{ class: 'magic-navbar-header none-select' }, this.navbars.map((navbar, index) => {
  81. const elements = [h('div', { class: 'magic-navbar-title'}, [ ...splitTitle(navbar.title) ])]
  82. if(navbar.icon) {
  83. elements.push(h(MagicIcon, { icon: navbar.icon}))
  84. }
  85. const style = navbar.style || {}
  86. if(navbar.show === false){
  87. style['display'] = 'none'
  88. }
  89. return h('li', {
  90. class: this.selectIndex === index ? 'selected' : '',
  91. 'data-title': navbar.title,
  92. 'data-tooltip-direction': this.tooltipDirection,
  93. style,
  94. onClick: ()=> {
  95. if(this.selectIndex === index && this.allowClose){
  96. this.selectIndex = -1
  97. }else {
  98. this.selectIndex = index
  99. }
  100. }
  101. }, elements)
  102. }))]
  103. this.slots.forEach((slot, index) => {
  104. const style = index !== this.selectIndex || slot.props.show === false ? { display: 'none' } : {};
  105. if(this.to){
  106. childs.push(h(Teleport, {to: this.to}, h('div', { class:"magic-navbar-body", style}, slot)))
  107. }else {
  108. childs.push(h('div', { class: 'magic-navbar-body', style }, slot))
  109. }
  110. })
  111. return h('div', {
  112. class: `magic-navbar magic-navbar__${this.direction}` + (this.reverse ? ' reverse': '')
  113. }, childs)
  114. }
  115. }