zb-tooltip.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. <template>
  2. <view class="zb-tooltip" :style="{
  3. '--theme-bg-color':color
  4. }">
  5. <view class="zb_tooltip_content" @click.stop="handleClick">
  6. <slot></slot>
  7. <view class="zb_tooltip__popper"
  8. @click.stop="()=>{}"
  9. :style="[style,{
  10. visibility:isShow?'visible':'hidden',
  11. color:color==='white'?'':'#fff',
  12. boxShadow: color==='white'?'0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d':''
  13. }]" >
  14. <slot name="content">{{content}}</slot>
  15. <view class="zb_popper__icon" :style="[arrowStyle]" :class="[{
  16. 'zb_popper__up':placement.indexOf('bottom')===0,
  17. 'zb_popper__arrow':placement.indexOf('top')===0,
  18. 'zb_popper__right':placement.indexOf('right')===0,
  19. 'zb_popper__left':placement.indexOf('left')===0,
  20. }]">
  21. </view>
  22. </view>
  23. </view>
  24. </view>
  25. </template>
  26. <script>
  27. export default {
  28. props:{
  29. visible:Boolean,
  30. color:{
  31. type:String,
  32. default:'#303133',
  33. },
  34. placement:{
  35. type:String,
  36. default:'top',
  37. },
  38. content:{
  39. type:String,
  40. default:''
  41. },
  42. show:{
  43. type:Boolean,
  44. default:false,
  45. }
  46. },
  47. data() {
  48. return {
  49. isShow :this.visible,
  50. title: 'Hello',
  51. arrowLeft:0,
  52. query:null,
  53. style:{
  54. },
  55. arrowStyle:{}
  56. }
  57. },
  58. onLoad() {
  59. },
  60. watch:{
  61. isShow:{
  62. handler(val){
  63. this.$emit('update:visible', val)
  64. },
  65. immediate:true,
  66. },
  67. visible:{
  68. handler(val){
  69. if(val){
  70. this.$nextTick(()=>{
  71. this.getPosition()
  72. })
  73. }
  74. this.isShow = val
  75. },
  76. immediate:true,
  77. }
  78. },
  79. mounted(){
  80. // #ifdef H5
  81. window.addEventListener('click',()=>{
  82. this.isShow = false
  83. })
  84. // #endif
  85. this.getPosition()
  86. },
  87. methods: {
  88. close(){
  89. this.isShow = false
  90. },
  91. fixedWrap(){
  92. this.isShow = false
  93. },
  94. async handleClick(){
  95. if(this.isShow){
  96. return this.isShow = false
  97. }
  98. await this.getPosition()
  99. this.isShow = true
  100. },
  101. getPosition(){
  102. return new Promise((resolve) => {
  103. uni.createSelectorQuery().in(this).selectAll('.zb_tooltip_content,.zb_tooltip__popper').boundingClientRect(async (data)=>{
  104. let {left,bottom,right,top,width,height} = data[0]
  105. let obj1 = data[1]
  106. let objStyle = {}
  107. let objStyle1 = {}
  108. switch(this.placement){
  109. case 'top':
  110. if(obj1.width > width){
  111. objStyle.left = `-${(obj1.width - width)/2}px`
  112. }else{
  113. objStyle.left = `${Math.abs(obj1.width - width)/2}px`
  114. }
  115. objStyle.bottom =`${height+8}px`
  116. objStyle1.left = (obj1.width/2-6)+'px'
  117. break;
  118. case 'top-start':
  119. objStyle.left = `0px`
  120. objStyle.bottom =`${height+8}px`
  121. break;
  122. case 'top-end':
  123. objStyle.right = `0px`
  124. objStyle.bottom =`${height+8}px`
  125. objStyle1.right=`8px`
  126. break;
  127. case 'bottom':
  128. if(obj1.width>width){
  129. objStyle.left = `-${(obj1.width - width)/2}px`
  130. }else{
  131. objStyle.left = `${Math.abs(obj1.width - width)/2}px`
  132. }
  133. objStyle.top =`${height+8}px`
  134. objStyle1.left = (obj1.width/2-6)+'px'
  135. break;
  136. case 'bottom-start':
  137. objStyle.left = `0px`
  138. objStyle.top =`${height+8}px`
  139. objStyle1.left = `8px`
  140. break;
  141. case 'bottom-end':
  142. objStyle.right = `0px`
  143. objStyle.top =`${height+8}px`
  144. objStyle1.right = `8px`
  145. break;
  146. case 'right':
  147. objStyle.left = `${width+8}px`
  148. if(obj1.height>height){
  149. objStyle.top =`-${(obj1.height - height)/2}px`
  150. }else{
  151. objStyle.top =`${Math.abs((obj1.height - height)/2)}px`
  152. }
  153. objStyle1.top = `${obj1.height/2-6}px`
  154. break;
  155. case 'right-start':
  156. objStyle.left = `${width+8}px`
  157. objStyle.top =`0px`
  158. objStyle1.top = `8px`
  159. break;
  160. case 'right-end':
  161. objStyle.left = `${width+8}px`
  162. objStyle.bottom =`0px`
  163. objStyle1.bottom = `8px`
  164. break;
  165. case 'left':
  166. objStyle.right = `${width+8}px`
  167. if(obj1.height>height){
  168. objStyle.top =`-${(obj1.height - height)/2}px`
  169. }else{
  170. objStyle.top =`${Math.abs((obj1.height - height)/2)}px`
  171. }
  172. objStyle1.top = `${obj1.height/2-6}px`
  173. break;
  174. case 'left-start':
  175. objStyle.right = `${width+8}px`
  176. objStyle.top =`0px`
  177. objStyle1.top = `8px`
  178. break;
  179. case 'left-end':
  180. objStyle.right = `${width+8}px`
  181. objStyle.bottom =`0px`
  182. objStyle1.bottom = `8px`
  183. break;
  184. }
  185. this.style = objStyle
  186. // 三角形箭头
  187. this.arrowStyle = objStyle1
  188. resolve()
  189. }).exec()
  190. })
  191. }
  192. }
  193. }
  194. </script>
  195. <style lang="scss" scoped>
  196. $theme-bg-color: var(--theme-bg-color);
  197. .zb-tooltip{
  198. position: relative;
  199. }
  200. .zb_tooltip_content{
  201. height: 100%;
  202. /* float: left; */
  203. position: relative;
  204. display: inline-block;
  205. // display: flex;
  206. // flex-direction: row;
  207. // align-items: center;
  208. /* overflow: hidden; */
  209. }
  210. .zb_tooltip__popper{
  211. /* transform-origin: center top; */
  212. background: $theme-bg-color;
  213. visibility: hidden;
  214. // color:'#fff';
  215. position: absolute;
  216. border-radius: 4px;
  217. font-size: 12px;
  218. padding: 10px;
  219. min-width: 10px;
  220. word-wrap: break-word;
  221. display: inline-block;
  222. white-space: nowrap;
  223. z-index:9;
  224. }
  225. .zb_popper__icon{
  226. width: 0;
  227. height: 0;
  228. z-index:9;
  229. position: absolute;
  230. }
  231. .zb_popper__arrow{
  232. bottom: -5px;
  233. left:2px;
  234. /* transform-origin: center top; */
  235. border-left: 6px solid transparent;
  236. border-right: 6px solid transparent;
  237. border-top: 6px solid $theme-bg-color;
  238. }
  239. .zb_popper__right{
  240. border-top: 6px solid transparent;
  241. border-bottom: 6px solid transparent;
  242. border-right: 6px solid $theme-bg-color;
  243. left:-5px;
  244. }
  245. .zb_popper__left{
  246. border-top: 6px solid transparent;
  247. border-bottom: 6px solid transparent;
  248. border-left: 6px solid $theme-bg-color;
  249. right:-5px;
  250. }
  251. .zb_popper__up{
  252. border-left: 6px solid transparent;
  253. border-right: 6px solid transparent;
  254. border-bottom: 6px solid $theme-bg-color;
  255. top:-5px;
  256. }
  257. .fixed{
  258. position: absolute;width: 100vw;
  259. height: 100vh;
  260. position: fixed;
  261. left: 0;
  262. top: 0;
  263. pointer-events: auto;
  264. background: red;
  265. z-index:-1;
  266. }
  267. </style>