//js代码 videob.onclick=function(){ let video=document.createE" />

小言_互联网的博客

探索在原生网页中使用自定义数据属性

463人阅读  评论(0)

先说说我为什么有这种“奇怪”的想法。
它基于这样一个场景:我最近闲来无事完善了一个小demo:音乐播放器。在里面有一个功能 —— 点击列表某一项弹出音乐播放弹框。我原先一直是“为每一项单独加一个click事件监听”。这很糟糕!

<div id="videob"></div>

//js代码
videob.onclick=function(){
	let video=document.createElement('video')
	video.setAttribute('src','xxx')
	video.setAttribute('controls','controls')
	video.style.cssText="width:90%;height:300px"
	document.querySelector('body').appendChild(video)
}

后来我优化时改用了 事件代理 ,不得不承认它非常优秀,但是我不得不改变结构,使得js中出现了一堆“MP4数据”(一个数组),在触发事件时判断当前是哪一个,然后从数组中拿到赋值给 audiosrc


事实上,在开发 Web 应用时,经常会用 JavaScript 获取文档之外的信息 ,某些情况下,我们需要用一些技巧来处理这些额外信息以保证 Web 应用能够正常运行。一般而言,技巧无外乎是将额外的信息塞入事件处理程序或滥用 rel 属性或 class 属性以方便注入行为。

幸运的是,HTML5引入了自定义数据属性:所有的自定义数据属性都以 data-前缀开头,HTML5 文档的验证器会在验证时忽略它。开发人员可以在任意元素中加入自定义数据属性,属性值可以是照片的元数据、经纬度坐标或者弹出窗口的尺寸。
最棒的是,几乎在所有浏览器中,你都能够使用自定义数据属性,因为我们可以轻易地使用 JavaScript 来获取它们。


为什么设置onclick不好
在开始操作之前,我们必须先“重复”一个概念:0级DOM事件 。通俗来说就是各种on前缀的事件名称(比如:onclick、onmouseon、onkeydown),他们可以存在于 <script> 或者HTML标签中,且没有事件捕获和冒泡机制!

有这样一个场景:Web 应用的开发人员尤其是初学者常常需要依赖于弹出窗口,以便向用户显示在线帮助信息、附加选项或者其他重要的用户界面功能。
我们经常能在一个页面中看到如下代码:

<a href="#" onclick="window.open('xxx',null,'width=300,height=300');">go to xxx</a>

就是这段没怎么起眼的代码存在着非常致命的问题:

  1. 链接的目标地址没有设置!如果 JavaScript 被禁用了,那么链接将无法引导用户进入相应页面。这很一个非常严重,以至于我们需要立即解决。我建议开发者永远不要省略 href属性、任何情况下都不要为 href 属性赋“#”。
  2. 注意保持行为与内容分离,正如用链接样式表保持样式信息分离一样。开始的时候,使用 onclick 会带来便利,但是想象一下页面上有 50 个链接的情况,那时你会看到 onclick 方法失控的场面。你将只能一遍又一遍地编写重复的 JavaScript 代码。如果是通过服务器端代码来生成浏览器端代码,那么你就是在增加 JavaScript 事件。

为了解决上面的问题,我们为每个a链接设置了href,而且增加了不同的class!以增加“相同类型元素”的可识别性。

<a href="xxx" class="pop">go to xxx</a>

//js代码
var link=document.querySelector('a.pop')
link.onclick=function(e){
	e.preventDefault();
	window.open(this.getAttribute('href'));
}

我们还没有为open设置长宽!

现在,我们又回到了和文章开头一样的问题!


使用自定义数据属性
当创建应用了 JavaScript 的 Web 应用时,刚刚提到的情况比较常见。如你所见,在代码中存储窗口的期望高度和宽度是可取的,但是 onclick 方法有诸多弊端。我们可以改换在元素上嵌入属性的方式加以实现。现在要做的是将链接改造成下面这种形式:

<a href="xxx" data-width="600" data-height="400" class="pop">go to xxx</a>
var link=document.querySelector('a.pop')
link.onclick=function(e){
	e.preventDefault();
	window.open(this.getAttribute('href'),null,"width="+this.getAttribute('data-width')+",height="+this.getAttribute('data-height'));
}

好吧,这个例子似乎没有什么说服力。
但是为了让你能够真正认识到“问题的严重性”,我将带你来优化文章开头的示例:

<div id="mxc">
	<div class="videob" data-uri="./img/1.mp4"></div>
	<div class="videob" data-uri="./img/2.mp4"></div>
</div>
mxc.addEventListener('click',function(e){
	let target=e.target || e.srcElement;
	let video=document.createElement('video')
	video.setAttribute('src',target.getAttribute('data-uri'))
	video.setAttribute('controls','controls')
	video.style.cssText="width:90%;height:300px;margin:0 auto"
	document.querySelector('body').appendChild(video)
},false)

这样才“真正”体现了“代理的价值”!


其他用到“自定义数据属性”最多的地方应该就是【图片懒加载】里面设置替换图了吧:

<body>
<div class="imgs">
    <div>
        <img src="占位图" data-src="真正图片" alt="图片说明">
    </div>
    ...
</div>
<script>
    window.onload=function () {
        var imgs=document.querySelectorAll('img');
        function offset(el){
			let top=el.offsetTop
			while(el.offsetParent){
				el=el.offsetParent
				top+=el.offsetTop   //scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离
			}
			return { top }
		}
        function lazyload(imgs) {
            var h=window.innerHeight;   //innerheight	返回窗口的文档显示区的高度
            var s=document.documentElement.scrollTop || document.body.scrollTop;   //document.body.scrollTop 网页被卷去的高
            for(var i=0;i<imgs.length;i++){
                if((h+s)>offset(imgs[i]).top){   //窗口文档显示去高度+向上滚动的高度,判断是否到达了图片的位置,如果到了,才去加载,并在加载中 用一个动图去“占位”
                    (function (i) {
                        setTimeout(function () {
                            var tmp=new Image();
                            tmp.src=imgs[i].getAttribute("data-src");   //   直接获取
                            tmp.onload=function () {
                                imgs[i].src=imgs[i].getAttribute("data-src");   //   如果直接获取不了(还没加载完),就等加载完前面的再去获取
                            }
                        },1300)
                    })(i)
                }
            }
        }
        lazyload(imgs);
        window.onscroll=function () {
            lazyload(imgs);
        }
    }
</script>
</body>

事实上,我们确实在很多地方可以用到它:比如自定义组件(vue / 微信小程序)中我们可以为它设置参数为它本身携带的值。


展望
开发者可以用自定义数据属性将各式各样的信息嵌入标记中。
我们可以使用自定义数据属性将日期和时间缓存在页面中,并以用户时区为基准来显示日期和时间。只需将时间以 UTC 的形式置于 HTML 页面中,在客户端将其转换成用户本地时间即可。(主要配合浏览器的缓存:在页面信息未改变时不会更新)


转载:https://blog.csdn.net/qq_43624878/article/details/107977721
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场