原生小程序实现tooltips提示信息
大家好我是小文同学,失踪人口回归了。被自己的懒惰失踪的三周里,属实没有学习没有进度,真是太罪恶了。所以我来了。
1. 背景
故事是这样的,之前有个重构的需求里出现了这样的一个弹窗。唤醒姿势是点击某个按钮或者tips的icon时需要出现这样的提示。回过头来找找之前我们维护的组件库,嗯确实有人已经写过的这样的组件啦!正打算用的时候发现用不了。。。。为什么呢,因为我们的小程序项目是基于mpx框架构建而成的,然而已有的组件是用的mpx文件写的,然后我要重构的页面是原生小程序实现的。。。出于安全考虑,还是在原页面上进行修改吧。嗯所以自己就简单的写了一个单纯只在我这里实现的tips而已了。
2. 学习
在写完这个简单的实现之后,我就去看看当时这个组件是怎么实现的啦。
经过我的粗略学习,该组件的开发者写了一个简单的event.js,实现了一个消息中心,也就是我们所认识的发布订阅模式。通过该方法在组件attached的时候去监听某个事件,在点击某个地方的时候再emit激活该事件。
因为mpx的增加能力使得我们能够在项目中使用ref获取某个元素,这也为实现在该项目中实现该功能提供了很大的便利,例如直接通过ref获取这个元素的一些信息,并且可以做相应的处理。以下是我学习完总结出来用原生的写法的一个版本。
3.原生小程序实现
<view class="tooltip my-class" bindtap="clickTips">
<view class="tips {{ isNeedTips ? 'visible' : 'hidden' }} {{ placement }}" style="width: {{ tooltipWidth + 'rpx' }}">{{ tips }}</view>
<view>{{ content }}</view>
</view>
const screenWidth = wx.getSystemInfoSync().windowWidth // 获取设备信息(宽度)
externalClasses: ['my-class'],
properties: {
placement: {
type: String,
value: 'top' // right bottom left
},
content: String,
tips: String,
maxWidth: {
type: Number,
value: 354
},
duration: {
type: Number,
value: 2000
}
},
data() {
return {
tooltipWidth: 100
}
}
lifetimes: {
attached() {
this.getTooltipWidth()
this.judgePosition()
}
}
methods: {
getTooltipWidth() {
const contentRPXWidth = this.data.tips.length * 28 + 36 * 2 // 自定义的一个tips宽度
const conetntPXWidth = (contentRPXWidth / 750) * screenWidth // 根据屏幕适配的宽度
wx.createSelectorQuery().in(this).select('.tooltip').boundingClientRect(({ width }) => {
const {
maxWidth
} = this.data
let tooltipWidth = 0
// 获取自定义元素的宽度 与 屏幕适配宽度做比较
// 最终参考使用一个合适的宽度作为 tips 的宽度
if (conetntPXWidth < width) {
tooltipWidth = contentRPXWidth
} else {
tooltipWidth = contentRPXWidth < maxWidth ? contentRPXWidth : maxWidth
}
this.setData({
tooltipWidth
})
}).exec()
}
},
// 判断tips是否在某个位置上有足够的空间放置
judgePosition() {
// 同理通过 wx.createSelectorQuery().in(this).select('').boundingClientRect去获取自定义元素的位置元素信息以及tips的位置元素信息去做处理
// 在这里只列举了其中一种情况的例子进行判断来设置该tips的实际放置位置
// 以下情况可能出现的场景是:自定义元素放置的位置过于偏左 导致上下的tips没办法放置 因此设置tips到右边 别的情况同理
if (placement === 'top' || placement === 'bottom')
const targetLeftCenter = targetLeft + targetWidth / 2 // 点击元素的中间位置坐标
if (targetLeftCenter < tipWidth / 2) {
this.setData({
placement: 'right'
})
}
}
clickTips() {
const { duration } = this.data
this.setData({ isNeedTips: true }) // 显示tips
let timer = setTimeout(() => {
this.setData({
isNeedTips: false // 在duration毫秒后隐藏tips
})
wx.nextTick(() => {
clearTimeout(timer) && (timer = null) // 清理定时器
})
}, duration)
this.triggerEvent('click') // 抛出一个点击事件
}
- tooltip最外层样式类名my-class使用了externalClasses: ['my-class'],给用户提供了自定义元素样式的机会
- clickTips事件实现了点击自定义元素时,弹出tips
- tips的实现本来是想用伪元素来实现的,但是这样的话就没办法动态改变该tips的宽,在这里tips的宽度是根据自定义元素的宽度和tips的文字长度一个计算方式比较得出的使用宽度
- isNeedTips用于控制该tips的显示与否
- placement用于控制该tips显示的位置(上、下、左、右)
- tooltipWidth用于设置该tips的宽度
- tips用于设置该tips的内容
- content用于设置自定义元素的内容
- duration用于设置tips的显示时间
- maxWidth是该tips的默认最大宽度 参考下图
4.使用方法
<tooltip my-class="myClass" content="我是内容" tips="我是提示" placement="top" duration="1000" bind:click="handleClick"></tooltip>
5.参考文档
externalClasses
developers.weixin.qq.com/miniprogram…
wx.getSystemInfoSync() developers.weixin.qq.com/miniprogram…
wx.createSelectorQuery() developers.weixin.qq.com/miniprogram…
wx.nextTick() developers.weixin.qq.com/miniprogram…
写在最后
小文同学学艺不精,有写的不好的地方欢迎多多指教啦。一些css代码以及js代码就不贴啦~主要是想跟大家交流一下实现思路。希望广大优秀网友们帮我该组件再提供一些建议我好去补充啦!
最后感谢各位抽出宝贵时间看小文的文章!我们下期再见!
转载自:https://juejin.cn/post/7012301682977538079