【前端特辑】探索a链接实践奥秘

此文转载自:https://blog.csdn.net/qq_43624878/article/details/109722712#commentBox

见过a标签各种“千奇百怪”的写法,也探索过它的各种用法;于是迫不及待地想要分享出来 —— 这个在我看来html中最“好玩”的一个标签。


先来康康“朴实无华”a标签:
from 菜鸟教程
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轮询的使用!

比如这样:

a-target

(:如果跳转后不能刷新页面,则可把target链接中“?”及后面删掉(也就是没有search参数)即可 —— target指向(任意)一个一样的字符串,这没什么。


a链接实现下载文件

关于这方面,笔者最早是在“canvas图片压缩”中使用,并且在遇到最近这个需求之前甚至以为这么用就足够了:
在html5时代,a标签中多了一个属性 —— download,用于下载href中的链接(在线)文件。
拿canvas来说,经过 ctx.drawImage(...)ctx.fillText(...) 之后得到的是一个“类图片”格式,这时候怎么拿到href中?

js提供了一些转化为URL的方法:
canvas.toDataURL("image/png") ——对canvas
URL.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);
};

a-download

当然,有些时候你并不想下载单个文件 —— 比如压缩包下载(文件夹是不可能的,这辈子都不可能✧(≖ ◡ ≖✿ )!
「在闲逛GitHub时,发现了一个比较流批的开源项目:
jszip ,可用于ZIP打包下载。(好多星星,我慕了。。。)」


a链接在某些情况下的缺陷及其替代

这个应该是比较常见的了:简单来说就是 —— 点击某个链接,跳转到对应页面。

但一般不只是这么做,否则我也不会写这篇文章了!
常见的比如一个学校的介绍div,里面有图片、名称、简介,一般这种都是出现在机构的问卷之类的活动页中,所以还能看到点赞(支持度)。就有要求了:点击整体要跳转到学校的官网,但是如果点击的是“简介”部分,就跳转到“百度百科”中。

再复杂一点的还有:点击“点赞”,跳转到投票页面、点击图片跳转到学校风光页面等等。。。

你是否知道:<a>不支持自身嵌套

<a href="#destiny">
	nyist
	<a href="#communite">
		uc
	</a>
</a>

显示出来却是这样的:
a-嵌套
同级?!

这时候,如果我们有链接嵌套的需求,就可以试试使用<area>元素(“热点区域”)!如上面所说的场景:

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在线编译器

更新↓
但是当一切“尘埃落定”,我无意中用火狐浏览器打开了这个页面:
a-area

标题和整体部分怎么跳转到一个页面去了?
上网搜查这个问题时发现 张鑫旭的这篇文章 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文章中提出的方法一样


  1. 张大的这篇文章中也提到了关于area的其它实践,有兴趣可以品尝一下,感觉怎么说呢:妙不可言! ↩︎

原文地址:https://www.cnblogs.com/phyger/p/14043742.html