JavaScript CSS修改学习第五章 给“上传”添加样式


Posted in Javascript onFebruary 19, 2010

问题
在一个网站中可能我的输入框式下面这样的:
JavaScript CSS修改学习第五章 给“上传”添加样式 
设计者可能想让上传部分也像这样然后再添加一个select按钮。但是当我想把普通的输入框改为上传框时就根本不能工作。浏览器之间有很大的不同,给默认按钮添加样式也几乎不可能。
JavaScript CSS修改学习第五章 给“上传”添加样式

这很难成为设计的很好的上传框,但是也是我们能做的最多的了。

注意到Safari的设计有些不同。Safari小组想关闭手动输入文件的功能,可能担心这样的溢出。这样设计有个缺点就是用户在选择了一个文件之后不能取消上传文件。

解决办法

读者Michael McGrady发明了一个不错的小技巧来解决给上传按钮添加样式的问题。这个页面上的所有解决办法都是他发明的,我只是添加了position:relative,一些注释和测试,然后转为JavaScript。

没有使用这个技巧的时候:

使用了之后我想成为这样:

JavaScript CSS修改学习第五章 给“上传”添加样式

现在看起来好多了不是么?

McGrady的方法很简单且优雅:

1、设置一个普通的<input type="file">,然后放置在包含postion:relative属性的元素中。

2、同样在父元素中,添加一个普通的<input>和一个图片,给他们设置样式。给他设置绝对位置让这个普通的input能够和<input type="file">重叠。

3、然后把<input type="file">的z-index设置为2,这样他就能在普通的input上面显示。

4、最后将<input type="file">的opacity设置为0。这样<input type="file">就看不见了,下面的input/image就能显现出来,但是你还能点击“浏览”按钮。如果这个按钮的位置在图片上面,那么看起来好像点击的就是图片一样。

注意你不能使用visibility:hidden,因为一个真正的不可见元素是不能点击的,我们需要一个能点击的不可见元素。

至此,这个效果可以通过纯CSS显示了,但是还差一点

5、当用户选择了一个文件之后,那个可见的假的输入框应该显示选择文件的路径,就像正常的<input type="file">一样。虽然只需要简单的把<input type="file">的内容复制过来,但是还是需要JavaScript的。

所以这个技术如果没有JavaScript可能不能完全实现。我一会会解释原因。我决定把整个这个想法写成JavaScript的。如果你想使用没有文件名显示的上传框的话也可以使用纯CSS方式,虽然这不是一个好办法。

HTML/CSS结构
我打算用下面的HTML/CSS结构:

div.fileinputs { 
    position: relative; 
} div.fakefile { 
    position: absolute; 
    top: 0px; 
    left: 0px; 
    z-index: 1; 
} 
input.file { 
    position: relative; 
    text-align: right; 
    -moz-opacity:0 ; 
    filter:alpha(opacity: 0); 
    opacity: 0; 
    z-index: 2; 
} 
<div class="fileinputs"> 
    <input type="file" class="file" /> 
    <div class="fakefile"> 
        <input /> 
        <img src="search.gif" /> 
    </div> 
</div>

<div class="fileinputs">的位置是relative,这样我们就能在里面放置一个绝对位置的层:假的输入框。

<div class="fakefile">包含一个假的输入框和一个按钮,他的位置是绝对的,z-index值是1,这样他就能在真正的上传框下面显示。

真正的上传框也有位置属性relavtive,这样就能设置他的z-index值了。总之需要上传框在假的输入框之上显示。然后我们设置他的透明度为0,让他不可见。

还需要注意text-align:right:因为Mozilla不能设置上传框的宽度,所以我们要保证浏览按钮在DIV的右边缘,假的按钮也要在右边,而且应该在真的下面。

你还需要一些css代码来设置宽度高度边框等等,在这个例子中我没有写。

为什么是JavaScript?
使用JavaScript的第一个原因就是要把文件路径复制到假的文本框里。

第二,JavaScript会忽略掉没有意义的HTML代码:<div class="fakefile">,让代码保持干净。

最后,对于一些旧的浏览器不能处理CSS,在Netscape和IE4里面文件输入就不可访问。对于那些没有CSS的浏览器,用户会看到两个输入框,而且不能理解第二个是干嘛的。

Netscape 4的问题

在Netscape 4里面用户只能看见按钮。可能是因为position:absolute的原因。

JavaScript CSS修改学习第五章 给“上传”添加样式

IE4的问题

在IE4里面会有一个诡异的原来的“浏览”按钮的影子,而且不能点击。没有解决办法

JavaScript CSS修改学习第五章 给“上传”添加样式

Netscape 3的问题

对于那些没有CSS功能的浏览器。虽然可以使用,但是两个输入框会让用户郁闷。

JavaScript CSS修改学习第五章 给“上传”添加样式

解决办法-JavaScript

这些问题的解决办法就是JavaScript:通过JavaScript生成输入框和按钮。现在最坏的情况就是JavaScript不能执行,即使如此,用户也能上传文件。虽然不那么好看,但是还是能工作的。

所以原来复杂的HTML变成了:

<div class="fileinputs"> 
    <input type="file" class="file"> 
</div>

我们通过JavaScript来添加其他元素。
代码
var W3CDOM = (document.createElement && document.getElementsByTagName); 
function initFileUploads() { 
    if (!W3CDOM) return; 
    var fakeFileUpload = document.createElement('div'); 
    fakeFileUpload.className = 'fakefile'; 
    fakeFileUpload.appendChild(document.createElement('input')); 
    var image = document.createElement('img'); 
    image.src='pix/button_select.gif'; 
    fakeFileUpload.appendChild(image); 
    var x = document.getElementsByTagName('input'); 
    for (var i=0;i<x.length;i++) { 
        if (x[i].type != 'file') continue; 
        if (x[i].parentNode.className != 'fileinputs') continue; 
        x[i].className = 'file hidden'; 
        var clone = fakeFileUpload.cloneNode(true); 
        x[i].parentNode.appendChild(clone); 
        x[i].relatedElement = clone.getElementsByTagName('input')[0]; 
        x[i].onchange = x[i].onmouseout = function () { 
            this.relatedElement.value = this.value; 
        } 
    } 
}

解释
如果浏览器不支持W3C DOM,那么什么也不做。
var W3CDOM = (document.createElement && document.getElementsByTagName); 
function initFileUploads() { 
    if (!W3CDOM) return;

创建<div class="fakefile">和他的内容。需要的时候我们会复制它。
var fakeFileUpload = document.createElement('div'); 
fakeFileUpload.className = 'fakefile'; 
fakeFileUpload.appendChild(document.createElement('input')); 
var image = document.createElement('img'); 
image.src='pix/button_select.gif'; 
fakeFileUpload.appendChild(image);

然后遍历页面上的所有input,如果不是<input type="file">则忽略。
var x = document.getElementsByTagName('input'); 
for (var i=0;i<x.length;i++) { 
    if (x[i].type != 'file') continue;

再做一次检测:如果<input type="file">的父元素没有fileinputs的class,则忽略。
if (x[i].parentNode.className != 'fileinputs') continue;

现在我们就找到了需要添加样式的上传框。首先我们添加一个hidden的类名。
x[i].className = 'file hidden';

复制假的输入框然后添加在<input type="file">的父元素上。
var clone = fakeFileUpload.cloneNode(true); 
x[i].parentNode.appendChild(clone);

现在我们就成功的添加了样式。但是还没有结束,我们希望用户在输入框内看到文件路径。
首先我们给<input type="file">创建一个属性,指向假的输入框:
x[i].relatedElement = clone.getElementsByTagName('input')[0];

这样当用户改变了上传文件的时候我们就能很轻松及时的访问到假的输入框,然后复制路径。
在这有个问题,我们使用什么event呢?通常使用change事件,当上传文件改变的时候,假的输入框的值也随之改变。
但是Mozilla 1.6在上传框上不支持这个事件(Firefox支持)。所以我在这里添加一个onmouseout的事件。(IE下同样可以运行,Safari不行)
x[i].onchange = x[i].onmouseout = function () { 
this.relatedElement.value = this.value; 3 }

问题和扩展
还有一个问题,用户在选择了一个文件之后就不能取消了。
假设用户选择了一个文件之后,突然不想上传了。通常只需要删除文件路径就可以了。但是在我们的例子里却很难,试一试,可以删除但是通常与感觉相反。
所以我们希望用户通过修改假的输入框也能修改真正的上传路径。
允许选择是可能的。当用户选择了上传文件的任何部分,我们就选择整个假输入框的全部内容。
[code] x[i].onselect = function () { 2 this.relatedElement.select(); 3 }
但是JavaScript的安全性不允许程序修改上传路径,所以我们不能通过让用户修改输入框的内容来修改真正的上传路径。所以我决定放弃onselect事件。
一种可行的办法是:给假的输入框添加一个清楚按钮,当用户点击之后就删除掉原来的上传框然后重新创建一个。这虽然笨重,但是能确实删除用户不想上传的文件路径。我不觉得这个一定可以工作,我也没有写这部分代码。
点击事件的路径
有读者建议,去掉那些繁杂的CSS,彻底隐藏上传框,然后把假的输入框的click事件绑定在真正的上传框上。非常棒的想法,而且比上面的简单的多。
[code] fakeField.onclick = function () { 2 realField.click() 3 }
这个click()方法允许你仿真一个表单项。复选框的点击,单选框被选中等等。然而Mozilla和Opera不支持。我想知道为什么,因为添加这个方法最大的不安全性就在于弹出一个选择文件的对话框而已。
所以我们也不能用这个简单的办法。
翻译地址:http://www.quirksmode.org/dom/inputfile.html
转载请保留以下信息
作者:北玉(tw:@rehawk)
Javascript 相关文章推荐
js程序中美元符号$是什么
Jun 05 Javascript
jQuery学习笔记之jQuery选择器的使用
Dec 22 Javascript
JavaScript对象反射用法实例
Apr 17 Javascript
Javascript中的方法和匿名方法实例详解
Jun 13 Javascript
js控制多图左右滚动切换效果代码分享
Aug 26 Javascript
ionic组件ion-tabs选项卡切换效果实例
Aug 27 Javascript
微信小程序  生命周期详解
Oct 27 Javascript
微信小程序 蓝牙的实现实例代码
Jun 27 Javascript
JavaScript阻止表单提交方法(附代码)
Aug 15 Javascript
初学者AngularJS的环境搭建过程
Oct 27 Javascript
js实现简单模态框实例
Nov 16 Javascript
element-ui 中使用upload多文件上传只请求一次接口
Jul 19 Javascript
JavaScript CSS 修改学习第四章 透明度设置
Feb 19 #Javascript
JavaScript CSS修改学习第三章 修改样式表
Feb 19 #Javascript
JavaScript CSS修改学习第二章 样式
Feb 19 #Javascript
JavaScript CSS修改学习第一章 查找位置
Feb 19 #Javascript
JavaScript DOM 学习第九章 选取范围的介绍
Feb 19 #Javascript
JavaScript DOM学习第八章 表单错误提示
Feb 19 #Javascript
JavaScript DOM 学习第七章 表单的扩展
Feb 19 #Javascript
You might like
ASP和PHP都是可以删除自身的
2007/04/09 PHP
PHP程序开发范例学习之表单 获取文本框的值
2011/08/08 PHP
PHP实现基于PDO扩展连接PostgreSQL对象关系数据库示例
2018/03/31 PHP
jQuery.ajax 用户登录验证代码
2010/10/29 Javascript
js两行代码按指定格式输出日期时间
2011/10/21 Javascript
原生js拖拽(第一课 未兼容)拖拽思路
2013/03/29 Javascript
JavaScript中的Repaint和Reflow用法详解
2015/07/27 Javascript
JavaScript中数组的22种方法必学(推荐)
2016/07/20 Javascript
Bootstrap中的Dropdown下拉菜单更改为悬停(hover)触发
2016/08/31 Javascript
将json转换成struts参数的方法
2016/11/08 Javascript
js+html5实现半透明遮罩层弹框效果
2020/08/24 Javascript
js如何编写简单的ajax方法库
2017/08/02 Javascript
快速解决element的autofocus失效问题
2020/09/08 Javascript
[03:14]辉夜杯主赛事 12月25日每日之星
2015/12/26 DOTA
编写Python的web框架中的Model的教程
2015/04/29 Python
浅析python递归函数和河内塔问题
2017/04/18 Python
目前最全的python的就业方向
2018/06/05 Python
python中的turtle库函数简单使用教程
2018/07/23 Python
python 对给定可迭代集合统计出现频率,并排序的方法
2018/10/18 Python
Python进程间通信Queue消息队列用法分析
2019/05/22 Python
详解Python 调用C# dll库最简方法
2019/06/20 Python
Python enumerate函数遍历数据对象组合过程解析
2019/12/11 Python
Python使用py2neo操作图数据库neo4j的方法详解
2020/01/13 Python
html5 postMessage解决跨域、跨窗口消息传递方案
2016/12/20 HTML / CSS
英国豪华装饰照明品牌的在线零售商:Inspyer Lighting
2019/12/10 全球购物
毕业生自荐信
2013/12/14 职场文书
超市仓管员岗位职责范本
2014/09/18 职场文书
区长工作作风个人整改措施
2014/10/01 职场文书
微观世界观后感
2015/06/10 职场文书
领导激励员工的演讲稿,各种会上用得到,建议收藏
2019/08/13 职场文书
请学会珍惜眼前,因为人生没有下辈子!
2019/11/12 职场文书
导游词之张家口
2019/12/13 职场文书
浅谈Python响应式类库RxPy
2021/06/14 Python
详解Python中的进程和线程
2021/06/23 Python
Flutter Navigator 实现路由传递参数
2022/04/22 Java/Android
Nginx跨域问题解析与解决
2022/08/05 Servers