【前端特辑】探索a链接实践奥秘
见过a标签各种“千奇百怪”的写法,也探索过它的各种用法;于是迫不及待地想要分享出来 —— 这个在我看来html中最“好玩”的一个标签。
先来康康“朴实无华”a标签:
a是行内元素!
a标签实现刷新页面和跳转刷新
你可能会想:这是个什么奇怪的需求?但是它确实发生了:笔者在一个项目中曾接到这样的需求 —— 需要在页面上有一个特定形状的按钮并给用户以提示刷新当前页面。
我首先想到的肯定是<button>
啊:因为提示了“按钮”。但很快我就不这么认为了 —— 考虑到浏览器兼容性以及button原生样式问题,在每一次写button之前都至少要加这么一段代码:
margin: 0;
padding: 0;
/*自定义边框*/
border: 0;
/*消除默认点击蓝色边框效果*/
outline: none;
-webkit-appearence: none;
然后再去覆盖。
input —— 不管是 type="button"
还是 type="checkbox"
也都要进行重置。
这时候就显示出a链接的厉害了 —— 它只有一条多余的下划线,去除即可。
比如在circle.html中:
<a href="circle.html">刷新</a>
光凭上面这点可吸引不到我 —— 你可能不知道的是:a标签的target属性中是可以放具体的URL地址的 !
它的特点是:如果浏览器已经有标签页的地址是circle.html,则点击链接并不会打开新窗口,是直接刷新已经打开的circle.html(而不是打开一个新窗口!);如果浏览器中没有地址是circle.html的标签页,则此时target属性的行为表现类似 '_blank'
。
这个特点有什么应用呢?
假如有这么个链接:
<a href="circle.html?s=list" target="_search">成绩排名</a>
<!-- 或者 -->
<a href="circle.html?s=list" target="circle.html?s=list">成绩排名</a>
它指向一个新页面,而这个页面是你的网站某个页面答题环节的排名。根据上面的特点,你是否能想到:在每次答完题后点击提交时去触发这个链接就能跳转到排名页面 —— 不管它是否已经存在,并且刷新得到当前排名?
而不再需要Server-Sent Events或者web socket甚至是ajax轮询的使用!
比如这样:
(:如果跳转后不能刷新页面,则可把target链接中“?”及后面删掉(也就是没有search参数)即可 —— target指向(任意)一个一样的字符串,这没什么。
a链接实现下载文件
关于这方面,笔者最早是在“canvas图片压缩”中使用,并且在遇到最近这个需求之前甚至以为这么用就足够了:
在html5时代,a标签中多了一个属性 —— download,用于下载href中的链接(在线)文件。
拿canvas来说,经过 ctx.drawImage(...)
或 ctx.fillText(...)
之后得到的是一个“类图片”格式,这时候怎么拿到href中?
js提供了一些转化为URL的方法:
canvas.toDataURL("image/png")
——对canvasURL.createObjectURL()
——对大部分js对象fileReader.readAsDataURL()
——对文件对象
…
var Imgload = function (domImg, filename="photo.png") {
// 创建隐藏的可下载链接
var eleLink = document.createElement('a');
eleLink.download = filename; // 设置图片名称;
eleLink.style.display = 'none';
// 图片转base64地址
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var width = domImg.naturalWidth;
var height = domImg.naturalHeight;
ctx.drawImage(domImg, 0, 0);
// 如果是或要转为PNG,则可用canvas.toDataURL('image/png')
eleLink.href = canvas.toDataURL('image/jpeg');
// 触发点击
document.body.appendChild(eleLink);
eleLink.click();
// 然后移除
document.body.removeChild(eleLink);
};
类似地,对于其它格式的文件,可以将文本或者JS字符串信息借助Blob转换成二进制,然后,作为<a>
元素的href属性,配合download属性,实现下载。
巧的是,js也提供了一些转化为blob的api:
xhr.responseType="blob"
——用于ajax请求中new Blob([...])
——用于一般js实例(甚至是arraybuffer实例)
一般来说,blob对象被用来转化为URL!
比如:将html代码下载为html文件
/**
content:文本内容
filename:下载到系统中的文件名称
*/
var Fileload = function (content, filename) {
// 创建隐藏的可下载链接
var eleLink = document.createElement('a');
eleLink.download = filename;
eleLink.style.display = 'none';
// 字符内容转变成blob地址
var blob = new Blob([content]);
eleLink.href = URL.createObjectURL(blob);
// 触发点击
document.body.appendChild(eleLink);
eleLink.click();
// 然后移除
document.body.removeChild(eleLink);
};
当然,有些时候你并不想下载单个文件 —— 比如压缩包下载(文件夹是不可能的,这辈子都不可能✧(≖ ◡ ≖✿ )!
「在闲逛GitHub时,发现了一个比较流批的开源项目:jszip ,可用于ZIP打包下载。(好多星星,我慕了。。。)」
a链接在某些情况下的缺陷及其替代
这个应该是比较常见的了:简单来说就是 —— 点击某个链接,跳转到对应页面。
但一般不只是这么做,否则我也不会写这篇文章了!
常见的比如一个学校的介绍div,里面有图片、名称、简介,一般这种都是出现在机构的问卷之类的活动页中,所以还能看到点赞(支持度)。就有要求了:点击整体要跳转到学校的官网,但是如果点击的是“简介”部分,就跳转到“百度百科”中。
再复杂一点的还有:点击“点赞”,跳转到投票页面、点击图片跳转到学校风光页面等等。。。
你是否知道:<a>
不支持自身嵌套 ?
<a href="#destiny">
nyist
<a href="#communite">
uc
</a>
</a>
显示出来却是这样的:
同级?!
这时候,如果我们有链接嵌套的需求,就可以试试使用<area>
元素(“热点区域”)!如上面所说的场景:
以前比较好的方法是通过CSS重新布局定位/浮动改变DOM结构和顺序,使链接内容变成相邻关系,虽然麻烦了点,但在语义和无障碍方面还是很好的;或者使用普通元素,用js为每个“独立元素”分配事件;或者是使用JS,点击目标区域时用 preventDefault
阻止默认事件,然后再 location.href
跳转。
实际上,还有一种更好的做法,就是<a>
元素中嵌套<area>
元素,可以保证DOM结构符合视觉呈现,又无需JS辅助。
比如图片热点的使用,就是借助<map>
和<area>
元素在图片上创造点击热点,把整个图片区域都作为点击热点,既能充分发挥<area>
标签本身的特性,又没有什么兼容性问题,键盘访问等都非常良好,还可满足我们链接嵌套功能:
<img src="./img/nan.png" class="book-cover" alt="南阳理工学院" usemap="#bookCover">
<map id="bookCover" name="bookCover">
<area hidefocus="true" shape="rect" coords="0,0,80,107" href="https://image.baidu.com/search/index?tn=baiduimage&ct=201326592&lm=-1&cl=2&ie=gb18030&word=%C4%CF%D1%F4%C0%ED%B9%A4&fr=ala&ala=1&alatpl=adress&pos=0&hs=2&xthttps=000000" alt="南阳理工学院" target="_blank">
</map>
而标题文字的链接内嵌处理则要麻烦一些。笔者的做法是:在文字前面直接放置了一个裸的<area>
元素,通过CSS设置覆盖文字实现的:
<h4 class="book-title">
<area class="area" href="https://baike.baidu.com/item/%E5%8D%97%E9%98%B3%E7%90%86%E5%B7%A5%E5%AD%A6%E9%99%A2/249491?fromtitle=%E5%8D%97%E9%98%B3%E7%90%86%E5%B7%A5&fromid=1973960&fr=aladdin" target="_blank">
南阳理工学院
</h4>
.book-title{
margin: 0;
float: left;
position: relative;
}
.area{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
注意:
area的使用必须和map标签一起,且map作为父元素 -><map>
标签用于客户端图像映射(图像映射指带有可点击区域的一幅图像),<area>
标签定义图像映射内部的区域,且<area>
元素始终嵌套在<map>
标签内部;<img>
标签通过 usemap 属性与<map>
元素中的 name 相关联;<area>
元素是空标签,不支持子元素,只能采用css覆盖或者伪元素(::before
等)的形式
案例代码及效果查看:JSBin在线编译器
更新↓
但是当一切“尘埃落定”,我无意中用火狐浏览器打开了这个页面:
标题和整体部分怎么跳转到一个页面去了?
上网搜查这个问题时发现 张鑫旭的这篇文章 1 已有研究,并提出:Firefox浏览器不支持area标签覆盖文字(Firefox的<area>
元素默认display:none
,且无法重置)。
张大也提出了一种解决方法:使用透明图片覆盖的方式实现文字的链接嵌套,也就是把原本裸露的<area>
换成<img>
,然后再使用<area>
元素创建图片热点。
<h4 class="book-title">
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="area" usemap="mapTitle">
南阳理工学院
</h4>
<map id="mapTitle" name="mapTitle">
<area shape="rect" coords="0,0,200,21" href="https://baike.baidu.com/item/%E5%8D%97%E9%98%B3%E7%90%86%E5%B7%A5%E5%AD%A6%E9%99%A2/249491?fromtitle=%E5%8D%97%E9%98%B3%E7%90%86%E5%B7%A5&fromid=1973960&fr=aladdin" target="_blank">
</map>
就能达到和想要的一样的效果了!
(:嘿嘿,和笔者在之前一篇css文章中提出的方法一样
-
张大的这篇文章中也提到了关于area的其它实践,有兴趣可以品尝一下,感觉怎么说呢:妙不可言! ↩︎
本文地址:https://blog.csdn.net/qq_43624878/article/details/109722712