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 相关文章推荐
Jquery 基础学习笔记
May 29 Javascript
apycom出品的jQuery精美菜单破解方法
Feb 18 Javascript
node.js中的fs.fsync方法使用说明
Dec 15 Javascript
原生javascript实现连连看游戏
Jan 03 Javascript
微信小程序实现工作时间段选择
Feb 15 Javascript
微信小程序简单的canvas裁剪图片功能详解
Jul 12 Javascript
mock.js模拟数据实现前后端分离
Jul 24 Javascript
JS如何生成随机验证码
Mar 02 Javascript
vue v-for出来的列表,点击某个li使得当前被点击的li字体变红操作
Jul 17 Javascript
Element Card 卡片的具体使用
Jul 26 Javascript
详解JavaScript类型判断的四种方法
Oct 21 Javascript
vue表单验证之禁止input输入框输入空格
Dec 03 Vue.js
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
在WordPress中使用wp-cron插件来设置定时任务
2015/12/10 PHP
在Laravel5.6中使用Swoole的协程数据库查询
2018/06/15 PHP
PHP基于cookie实现统计在线人数功能示例
2019/01/16 PHP
laravel框架路由分组,中间件,命名空间,子域名,路由前缀实例分析
2020/02/18 PHP
用JQuery 实现的自定义对话框
2007/03/24 Javascript
offsetParent 算法分析
2010/04/05 Javascript
JavaScript高级程序设计(第3版)学习笔记 概述
2012/10/11 Javascript
jQuery手机浏览器中拖拽动作的艰难性分析
2015/02/04 Javascript
javascript中的Function.prototye.bind
2015/06/25 Javascript
Backbone.js的一些使用技巧
2015/07/01 Javascript
响应式表格之固定表头的简单实现
2016/08/26 Javascript
基于jQuery实现选项卡效果
2017/01/04 Javascript
Bootstrap图片轮播效果详解
2017/10/17 Javascript
Angular4学习教程之DOM属性绑定详解
2018/01/04 Javascript
小程序rich-text组件如何改变内部img图片样式的方法
2019/05/22 Javascript
vue中根据时间戳判断对应的时间(今天 昨天 前天)
2019/12/20 Javascript
vue切换菜单取消未完成接口请求的案例
2020/11/13 Javascript
swiper实现导航滚动效果
2020/12/13 Javascript
[03:09]2014DOTA2国际邀请赛 赛场上的美丽风景线 中国Coser也爱DOTA2
2014/07/20 DOTA
python 用lambda函数替换for循环的方法
2018/06/09 Python
使用 Python 合并多个格式一致的 Excel 文件(推荐)
2019/12/09 Python
Python字典深浅拷贝与循环方式方法详解
2020/02/09 Python
英国领先的杂志订阅网站:Magazine.co.uk
2018/01/25 全球购物
爱尔兰灯和灯具网上商店:Lights.ie
2018/03/26 全球购物
数控机械专业个人的自我评价
2014/01/02 职场文书
50岁生日感言
2014/01/23 职场文书
新任教师自我鉴定
2014/02/24 职场文书
交通安全寄语大全
2014/04/08 职场文书
节约能源标语
2014/06/17 职场文书
班主任自我评价范文
2015/03/11 职场文书
2015年乡镇安全生产工作总结
2015/05/19 职场文书
八月迷情观后感
2015/06/11 职场文书
ThinkPHP5和ThinkPHP6的区别
2021/03/31 PHP
浅谈如何提高PHP代码质量之单元测试
2021/05/28 PHP
多线程Spring通过@Scheduled实现定时任务
2022/05/25 Java/Android
教你nginx跳转配置的四种方式
2022/07/07 Servers