要让一个DOM元素出现悬浮文字提示,一般情况下,我们都会选择使用H5的title属性。例如:
123
这样设置之后,当鼠标在div上悬浮过了一段时间之后,网页上鼠标位置附近就会出现悬浮文字提示,例如这样:
但是,不同的浏览器,悬浮等待的时间和悬浮文字的样式都可能会不一样,例如chrome上显示是白底灰字,firefox上就可能是黄底黑字,时长可能是3s或者1s,如果为了确保不同浏览器的用户体验的效果趋于一致的话,那么我们就需要禁用默认的title属性,改用js手动实现悬浮文字的提示。
为了提高组件的简洁性,所以这里我采用原生js进行编码,不兼容IE 6 7 8,并且没有做过渡动画,只是简单是隐藏显示,有兴趣的同学可以改用jquery重构来提高代码兼容性,用fadeIn fadeOut等动画效果代替直接的显示隐藏。
经分析,H5的title属性的作用逻辑如下:
js和html测试代码如下:
123
asdjkasl
fjksdkfj
上面这个代码还是比较简单,涉及的知识点主要有:
1.原生js获取节点的方法,document.querySelector()和document.querySelectorAll().这两个函数,接受的参数都是一个css选择器字符串,例如’.box’, ".father .son:nth-of-type(1)"之类的,总之只要能够写在css中的选择器,这里都可以使用。其中,document.querySelector()返回的是第一个匹配的原生DOM节点,和document.getElementById()有点类似,但是更加强大,而document.querySelectorAll()返回的是一个原生节点数组,存储所有匹配到的节点,和document.getElementsByClassName()有点像,但是更好用。
2.通配符选择器*用于选中网页上的所有节点,属性选择器[]用于选中含有某个属性或属性值为某个特定值的节点。搭配在一起后*[title]用于选中所有含有title属性的节点。
3. JavaScript中函数和对象this的指向问题,函数的this通常指向函数的上一层对象,上面的代码中频繁地使用到了this,如果大家对js的this的概念含糊不清的话可能会看不懂,建议大家百度一下或参考:JS this指向总结
这个组件比较简单,测试什么的我就不贴图啦,大家自己把代码拷到本地运行就知道效果了,先写到这里吧,本文作者郑伟斌,写于2019/4/26,转载请注明出处
v2.0采用jQuery改写,使用了MutationObserver来自动监听新元素的插入,使用者只需在页面初始化时调用titleTools.init()即可
;(function(window,document,$){
var titleTools = tt = {
$box: null,
_init : function(time,selector){
var $box = selector ? $(selector) : $('body');
this.$box = $box;
var temp = time;
time = parseInt(time);
if(!isNaN(time)&&time>=0){
tt.timeout = time;
}else{
console.warn("param "+time+" is not a number or out of range! using default timeout setting");
}
//选中所有含有title属性的节点
$box.find('*[title],*[data-optionaltitle]').each(function(index,ele){
if(ele.title){
$(ele).attr('data-optionaltitle',ele.title).removeAttr('title');
}
tt.bind(ele);
});
//监听body的后代节点插入和对title、data-optionaltitle属性的修改
var MutationObserver = window.MutationObserver || window.WebkitMutationObserver || window.MozMutationObserver;
if(!tt.observer){
var observer = this.observer = new MutationObserver(function(mutations,observer){
mutations.forEach(function(mutation){
var type = mutation.type;
var target = mutation.target;
if(type == 'attributes'){
//通过定时器达到异步执行的目的
setTimeout(function(){
//title属性只识别增加,不识别清空操作
if(mutation.attributeName == 'title'){
//确保事件绑定
tt.bind(target);
if(target.title) $(target).attr('data-optionaltitle',target.title).removeAttr('title');
}
//如果需要清空title则将data-optionaltitle赋值为空
else if(mutation.attributeName == 'data-optionaltitle'){
//确保事件绑定
tt.bind(target);
}
},0);//异步函数会等待所有同步代码执行完毕后才开始执行
}else if(type == 'childList'){
var adds = mutation.addedNodes;
var removes = mutation.removedNodes;
//nodeList数组
//通过定时器达到异步执行的目的
setTimeout(function(){
$(adds).each(function(index,ele){
if(ele.nodeType == 1){
tt._init(tt.timeout,ele);
}
});
$(removes).each(function(index,ele){
//解绑事件
tt.unbind(ele);
});
},0);
}
});
});
var options = {
attributes: true,
attributeFilter: ['title','data-optionaltitle'],
attributeOldValue: true,
childList: true,
subtree: true
};
$box.each(function(index,ele){
observer.observe(ele,options);
});
}
},
dispose: function(){
if(tt.observer){
tt.observer.disconnect;
delete tt.observer;
}
var $box = tt.$box;
$.each($box,function(index,ele){
var $self = $(ele);
$self.attr('title',$self.attr('data-optionaltitle')).removeAttr('data-optionaltitle');
tt.unbind($self);
});
},
bind: function(ele){
tt.unbind(ele);
$(ele).on("mouseover.titletools",titleTools.title).on("mouseout.titletools",titleTools.clears)
},
unbind: function(ele){
$(ele).off('mousemove.titletools mouseover.titletools mouseout.titletools')
},
//延时显示文字
timeout : 500,
className : 'custom-title-box',
styles : {
"display" : "inline-block",
"padding": "4px 5px",
"line-height" : "1.34",
"color" : "#fff",
"background" : "rgba(0,0,0,0.7)",
"max-width" : "25em",
"border-radius" : "2px",
"font-size": "12px",
"position" : "fixed",
"z-index" : "999",
"text-align" : "justify"
},
remove : function(){
$('.'+this.className).remove();
},
//显示提示文字的函数绑定在mouseover中
title : function(e){
e = e || window.event;
e.stopPropagation ? e.stopPropagation() : window.event.cancelBubble = true;
var self = this;
self.nowX = e.clientX;
self.nowY = e.clientY;
$(self).on("mousemove.titletools",tt.moveRecord);
},
//
moveRecord : function(e){
e.stopPropagation ? e.stopPropagation() : window.event.cancelBubble = true;
e = e || window.event;
var type = e.type;
var thisf = arguments.callee;
var self = this;
self.nowX = e.clientX;
self.nowY = e.clientY;
clearTimeout(this.timer);
this.timer = setTimeout(function(){
tt.remove();
if(!$(self).attr("data-optionaltitle")) return;
var div = document.createElement('div');
div.className = tt.className;
div.innerHTML = $(self).attr("data-optionaltitle");
$(div).css(tt.styles);
$(div).css({
"left" : (self.nowX+15)+'px',
"top" : (8+self.nowY)+'px'
});
document.body.appendChild(div);
self.titleElement = div;
$(self).off('mousemove.titletools');
},tt.timeout);
},
//清除文字提示框的函数,绑定在mousemove和mouseout上
clears : function(e){
e.stopPropagation ? e.stopPropagation() : window.event.cancelBubble = true;
clearTimeout(this.timer);
tt.remove();
}
};
window.titleTools = titleTools;
})(window,document,jQuery)
更新时间: 2019/8/26